import copy, fractions import generator.model, generator.parts, generator.harmony import generator.solo.analysis, generator.solo.composer, generator.solo.types import tests.test_musicxml import generator.harmonic_time def song(meter=4, count=6, chords=('Dm7', 'G7', 'CM7')): document = tests.test_musicxml.parse(tests.test_musicxml.xml_score(''.join(tests.test_musicxml.xml_note(step, 1, 'quarter') for step in ('C', 'D', 'E', 'G')))) first = document['staves'][0]['measures'][0] measures = [] for index in range(count): measure = copy.deepcopy(first) measure.update(id=f'measure_{index + 1}', number=str(index + 1), duration=generator.model.rational(meter), meter={'groups': [{'beats': [meter], 'unit': 4}]}, time_signature=f'{meter}/4') measure['voices'][0]['notes'] = [generator.model.make_event(f'source_{index}_{beat}', fractions.Fraction(beat), fractions.Fraction(1), 'note', [{'letter': 'cdefg'[beat % 5], 'octave': 4, 'alter': 0}]) for beat in range(meter)] measure['harmonies'] = [{**generator.harmony.parse_symbol(chords[index % len(chords)]), 'id': f'h_{index}', 'onset': generator.model.rational(0)}] if chords else [] for harmony in measure['harmonies']: harmony['symbol'] = generator.harmony.symbol(harmony) measures.append(measure) document['staves'][0]['measures'] = measures return generator.parts.prepare_document(document) def compose(document, part='acoustic', cutoff=None): analysis = generator.solo.analysis.analyze(document) measures = document['staves'][0]['measures'] end = sum(generator.model.fraction(m['duration']) for m in measures) if cutoff is None else cutoff return generator.solo.composer.compose(analysis, measures, part, end) def note(start, end, letter='g', alter=0, octave=4, **kwargs): return generator.solo.types.Note(fractions.Fraction(start), fractions.Fraction(end), generator.solo.types.Pitch(letter, fractions.Fraction(alter), octave), **kwargs) def choices(symbols, duration=4): return tuple(generator.harmonic_time.ChordSpan(fractions.Fraction(i * duration), fractions.Fraction((i + 1) * duration), i + 1, str(i + 1), fractions.Fraction(1), generator.model.key_from_fifths(-1), generator.harmony.parse_symbol(symbol)) for i, symbol in enumerate(symbols))