+28
-11
@@ -11,6 +11,8 @@ import unittest.mock
|
||||
import generator.production
|
||||
import generator.parts
|
||||
import generator.musicxml
|
||||
import generator.model
|
||||
import generator.score
|
||||
import generator.train
|
||||
import generator.training_io
|
||||
import generator.vocabulary
|
||||
@@ -20,7 +22,7 @@ import generator.solo.composer
|
||||
import generator.solo.decoder
|
||||
import generator.solo.harmonic
|
||||
import generator.solo.analysis
|
||||
import generator.solo.export
|
||||
import tests.score_events
|
||||
import tests.solo_fixtures
|
||||
import tests.test_musicxml
|
||||
import generator.harmonic_time
|
||||
@@ -45,23 +47,38 @@ class TrainingAndRepertoire(unittest.TestCase):
|
||||
self.assertNotIn('electric', json.dumps(baseline))
|
||||
frozen = json.loads((ROOT / 'data/models/solo.json').read_text())
|
||||
self.assertEqual(frozen, generator.solo.learned.fit(self.examples, self.provenance))
|
||||
def test_repertoire_exports_exact_sounding_music_for_every_registered_pair(self):
|
||||
def test_repertoire_preserves_exact_sounding_music_for_every_registered_pair(self):
|
||||
manifest = json.loads((ROOT / 'data/training/manifest.json').read_text())
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
for entry in manifest['examples']:
|
||||
for entry in manifest['examples']:
|
||||
with self.subTest(pair=entry['id']):
|
||||
part = 'acoustic' if entry['slot'] == 1 else 'electric'
|
||||
doc = generator.parts.prepare_document(generator.musicxml.load_musicxml(ROOT / 'data/training' / entry['source']))
|
||||
source = generator.production.SourceAnalysis.read(doc)
|
||||
with unittest.mock.patch('generator.solo.composer.compose', side_effect=AssertionError('authored pair must not be predicted')):
|
||||
result = generator.production.generate_role(source, part + '_solo', ROOT / 'data')
|
||||
path = pathlib.Path(directory) / (part + '.xml')
|
||||
generator.solo.export.write_role(result, path)
|
||||
actual = generator.training_io.read(path, part)
|
||||
measures = result['document']['staves'][0]['measures']
|
||||
first = next(i for i, m in enumerate(measures) if m.get('section_label') == part.capitalize() + ' Solo')
|
||||
last = next((i for i in range(first + 1, len(measures)) if measures[i].get('section_label')), len(measures))
|
||||
first -= result['details']['allocation']['lead_in_measures']
|
||||
offset = sum((generator.model.fraction(m['duration']) for m in measures[:first]), fractions.Fraction())
|
||||
timeline = tests.score_events.timeline(result['document'])
|
||||
actual = tuple((generator.model.fraction(n['onset']) - offset,
|
||||
generator.model.fraction(n['onset']) + generator.model.fraction(n['duration']) - offset,
|
||||
generator.model.fraction(n['pitch'])) for n in timeline['events'])
|
||||
expected = generator.training_io.read(ROOT / 'data/training' / entry['solo'], part, pitch_convention=entry['pitch_convention'])
|
||||
self.assertEqual(music(actual['sounding_events']), music(expected['sounding_events']), entry['id'])
|
||||
self.assertEqual([(m['start'], m['duration']) for m in actual['measures']], [(m['start'], m['duration']) for m in expected['measures']])
|
||||
self.assertEqual(actual['discrepancies'], [])
|
||||
self.assertTrue(all(n['legal_positions_at_sounding_pitch'] for n in actual['notes'] if n['pitch']))
|
||||
self.assertEqual(actual, music(expected['sounding_events']))
|
||||
cursor, spans = fractions.Fraction(), []
|
||||
for measure in measures[first:last]:
|
||||
duration = generator.model.fraction(measure['duration'])
|
||||
spans.append((str(cursor), str(duration)))
|
||||
cursor += duration
|
||||
for note in generator.score.measure_notes(measure):
|
||||
for pitch in note['pitches']:
|
||||
position = pitch['tablature']
|
||||
self.assertIn(position['string'], range(1, 7))
|
||||
self.assertIn(position['fret'], range(1, 13))
|
||||
self.assertEqual(spans, [(m['start'], m['duration']) for m in expected['measures']])
|
||||
self.assertEqual(expected['discrepancies'], [])
|
||||
def test_lookup_uses_source_music_and_slot_not_title_or_path(self):
|
||||
entry = json.loads((ROOT / 'data/training/manifest.json').read_text())['examples'][0]
|
||||
doc = generator.parts.prepare_document(generator.musicxml.load_musicxml(ROOT / 'data/training' / entry['source']))
|
||||
|
||||
Reference in New Issue
Block a user