import copy import dataclasses import fractions import unittest import generator.model import generator.parts import generator.source import generator.solo.profiles import generator.solo.placement import tests.solo_fixtures def events(measure): return tuple((generator.model.fraction(n['onset']), generator.model.fraction(n['duration']), tuple((p['letter'], p['alter']['numerator'], p['octave'], p['tablature']['string'], p['tablature']['fret']) for p in n['pitches'])) for v in measure['voices'] for n in v['notes']) class SoloInstrumentAndIdentity(unittest.TestCase): def test_role_ranges_and_no_open_strings(self): acoustic = generator.solo.profiles.for_part('acoustic') electric = generator.solo.profiles.for_part('electric') self.assertEqual(acoustic.register, (41, 76)) self.assertEqual(electric.register, (41, 76)) self.assertTrue(acoustic.permits(41)) self.assertTrue(electric.permits(50)) self.assertTrue(acoustic.permits(72)) for profile in (acoustic, electric): for midi in range(40, 78): for p in generator.solo.placement.positions(midi, profile): self.assertIn(p.string_number, profile.strings) self.assertTrue(1 <= p.fret <= 12) self.assertTrue(any(p.string_number == 1 for p in generator.solo.placement.positions(65, electric))) self.assertTrue(any(p.string_number == 1 for p in generator.solo.placement.positions(65, acoustic))) def test_soft_overlapping_registers_do_not_inherit_a_mandatory_octave(self): source = generator.source.analyze(generator.parts.prepare_document(tests.solo_fixtures.song(count=4, chords=('CM7',)))) acoustic = generator.solo.profiles.for_part('acoustic', source) electric = generator.solo.profiles.for_part('electric', source) self.assertIsNone(electric.reference) self.assertIsNone(acoustic.reference) self.assertEqual(acoustic.melody_range, electric.melody_range)