"""Independent musical and selection contracts for complete phrase generation.""" import dataclasses import fractions import unittest from unittest.mock import patch from generator import model, vocabulary from generator.scales import selection, timeline from generator.solo import analysis, construction, harmonic, profiles, types, placement from generator.solo import selection as evaluation from tests import solo_fixtures as fixtures, rhythm_fixtures, scale_fixtures def builder(symbols=('C7','FM7','Dm7','G7'),seed='independent',count=8): source=fixtures.song(count=count,chords=symbols);a=analysis.analyze(source);ms=source['staves'][0]['measures'] end=sum(model.fraction(m['duration']) for m in ms) cs=selection.select(timeline.read(source['staves'][0]),timeline.Solo(0,end,'test'),scale_fixtures.library()) return construction.Builder(a,ms,harmonic.Harmony(cs,profiles.Instrument(reference=60)),fixtures.library(),rhythm_fixtures.library(),end,seed) class PhraseConstruction(unittest.TestCase): def test_completed_candidates_are_valid_and_cover_the_requested_span(self): b=builder(count=4) values=b.candidates(fractions.Fraction(),b.end,construction.State()) self.assertGreater(len(values),1) for p,home in values: self.assertEqual((p.start,p.end),(0,b.end)) self.assertTrue(b.harmony.evaluate(p.notes,expressions=p.expressions,complete=True).valid) self.assertEqual(p.evaluation.total,sum(p.evaluation.contributions.values())) self.assertTrue(all(p.start<=n.start