@@ -1,4 +1,9 @@
|
||||
"""Dependency and music contracts use synthetic sources, never audition scores."""
|
||||
import generator.composition_types
|
||||
import generator.arrange.assembly
|
||||
import generator.composition
|
||||
import generator.source
|
||||
import generator.validation
|
||||
import concurrent.futures
|
||||
import copy
|
||||
import contextlib
|
||||
@@ -13,15 +18,10 @@ import unittest.mock
|
||||
|
||||
import generator.production
|
||||
import generator.model
|
||||
import generator.vocabulary
|
||||
import generator.solo.expressions
|
||||
import generator.solo.types
|
||||
import generator.solo.harmonic
|
||||
import generator.solo.placement
|
||||
import generator.solo.notation
|
||||
import generator.solo.composer
|
||||
import tests.solo_fixtures
|
||||
import tests.solo_fixtures
|
||||
import tests.solo_fixtures
|
||||
|
||||
def music(result):
|
||||
@@ -30,23 +30,23 @@ def music(result):
|
||||
class IndependentRoles(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.source = generator.production.SourceAnalysis.read(tests.solo_fixtures.song(count=1, chords=('CM7',)))
|
||||
cls.source = generator.source.SourceAnalysis.read(tests.solo_fixtures.song(count=1, chords=('CM7',)))
|
||||
cls.root = pathlib.Path('data').resolve()
|
||||
def test_alone_order_parallel_and_assembly(self):
|
||||
serial = {role: generator.production.generate_role(self.source, role, self.root) for role in generator.production.ROLES}
|
||||
serial = {role: generator.composition.generate_role(self.source, role, self.root) for role in generator.composition_types.ROLES}
|
||||
with concurrent.futures.ProcessPoolExecutor(max_workers=2, mp_context=multiprocessing.get_context('spawn')) as pool:
|
||||
jobs = {role: pool.submit(generator.production._job, (self.source, role, self.root, {}, None)) for role in reversed(generator.production.ROLES)}
|
||||
jobs = {role: pool.submit(generator.production._job, generator.composition_types.RoleRequest(self.source, role, self.root)) for role in reversed(generator.composition_types.ROLES)}
|
||||
parallel = {role: future.result() for role, future in jobs.items()}
|
||||
for role in generator.production.ROLES:
|
||||
for role in generator.composition_types.ROLES:
|
||||
self.assertEqual(music(serial[role]), music(parallel[role]), role)
|
||||
for doc in generator.production.assemble(self.source, serial).values():
|
||||
generator.model.validate_document(doc)
|
||||
for doc in generator.arrange.assembly.assemble(self.source, serial).values():
|
||||
generator.validation.validate_document(doc)
|
||||
def test_role_setting_and_cache_are_independent(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
a = generator.production.generate_role(self.source, 'acoustic_solo', self.root, cache_dir=directory)
|
||||
b = generator.production.generate_role(self.source, 'electric_solo', self.root, {'seed': 'changed'}, directory)
|
||||
again = generator.production.generate_role(self.source, 'acoustic_solo', self.root, cache_dir=directory)
|
||||
clean = generator.production.generate_role(self.source, 'acoustic_solo', self.root)
|
||||
a = generator.composition.generate_role(self.source, 'acoustic_solo', self.root, cache_dir=directory)
|
||||
b = generator.composition.generate_role(self.source, 'electric_solo', self.root, {'seed': 'changed'}, directory)
|
||||
again = generator.composition.generate_role(self.source, 'acoustic_solo', self.root, cache_dir=directory)
|
||||
clean = generator.composition.generate_role(self.source, 'acoustic_solo', self.root)
|
||||
self.assertTrue(again['cache_hit'])
|
||||
self.assertEqual(music(a), music(again))
|
||||
self.assertEqual(music(a), music(clean))
|
||||
@@ -60,7 +60,7 @@ class IndependentRoles(unittest.TestCase):
|
||||
self.assertNotIn('generated_assets', str(path))
|
||||
return original(path, *args, **kwargs)
|
||||
with unittest.mock.patch.object(pathlib.Path, 'open', guarded):
|
||||
result = generator.production.generate_role(self.source, 'acoustic_solo', self.root)
|
||||
result = generator.composition.generate_role(self.source, 'acoustic_solo', self.root)
|
||||
self.assertNotIn('reference', json.dumps(result['trace']))
|
||||
def test_titles_and_export_ids_do_not_supply_musical_identity(self):
|
||||
document = tests.solo_fixtures.song(count=1, chords=('CM7',))
|
||||
@@ -69,7 +69,7 @@ class IndependentRoles(unittest.TestCase):
|
||||
for m in other['staves'][0]['measures']:
|
||||
m['id'] = 'exporter_123'
|
||||
m['number'] = '99'
|
||||
self.assertEqual(generator.production.SourceAnalysis.read(document), generator.production.SourceAnalysis.read(other))
|
||||
self.assertEqual(generator.source.SourceAnalysis.read(document), generator.source.SourceAnalysis.read(other))
|
||||
def test_reference_presence_and_changes_do_not_change_clean_music(self):
|
||||
# No repository reference is a fixture or prerequisite. These deliberately
|
||||
# invalid optional files test the absence of a discovery/fallback branch.
|
||||
@@ -78,16 +78,16 @@ class IndependentRoles(unittest.TestCase):
|
||||
reference_dir.mkdir()
|
||||
references = [reference_dir / (source_name + '-solo-' + str(index) + suffix + '.xml')
|
||||
for source_name in ('all-of-me', 'autumn-leaves') for index in (1, 2) for suffix in ('', '(4)')]
|
||||
before = generator.production.generate_role(self.source, 'electric_solo', self.root)
|
||||
before = generator.composition.generate_role(self.source, 'electric_solo', self.root)
|
||||
for reference in references:
|
||||
reference.write_text('<not-a-production-source/>')
|
||||
present = generator.production.generate_role(self.source, 'electric_solo', self.root)
|
||||
present = generator.composition.generate_role(self.source, 'electric_solo', self.root)
|
||||
for reference in references:
|
||||
reference.write_text('changed optional target, still not MusicXML')
|
||||
changed = generator.production.generate_role(self.source, 'electric_solo', self.root)
|
||||
changed = generator.composition.generate_role(self.source, 'electric_solo', self.root)
|
||||
for reference in references:
|
||||
reference.unlink()
|
||||
absent = generator.production.generate_role(self.source, 'electric_solo', self.root)
|
||||
absent = generator.composition.generate_role(self.source, 'electric_solo', self.root)
|
||||
self.assertTrue(all(music(before) == music(v) for v in (present, changed, absent)))
|
||||
def test_original_melody_changes_the_theme_with_unchanged_harmony(self):
|
||||
source = tests.solo_fixtures.song(count=4, chords=('CM7',))
|
||||
@@ -97,11 +97,11 @@ class IndependentRoles(unittest.TestCase):
|
||||
for n in v['notes']:
|
||||
for p in n['pitches']:
|
||||
p['letter'] = {'c': 'e', 'd': 'f', 'e': 'g', 'f': 'a'}[p['letter']]
|
||||
a = generator.production.generate_role(generator.production.SourceAnalysis.read(source), 'acoustic_solo', self.root)
|
||||
b = generator.production.generate_role(generator.production.SourceAnalysis.read(changed), 'acoustic_solo', self.root)
|
||||
a = generator.composition.generate_role(generator.source.SourceAnalysis.read(source), 'acoustic_solo', self.root)
|
||||
b = generator.composition.generate_role(generator.source.SourceAnalysis.read(changed), 'acoustic_solo', self.root)
|
||||
self.assertNotEqual(a['details']['phrases'][0]['notes'], b['details']['phrases'][0]['notes'])
|
||||
def test_source_tuplet_lanes_survive_assembly(self):
|
||||
serial = {r: generator.production.generate_role(self.source, r, self.root) for r in generator.production.ROLES}
|
||||
serial = {r: generator.composition.generate_role(self.source, r, self.root) for r in generator.composition_types.ROLES}
|
||||
# Exercise a different original lane name, as in the imported Autumn head.
|
||||
doc = serial['electric_melody']['document']
|
||||
staff = doc['staves'][0]
|
||||
@@ -117,10 +117,10 @@ class IndependentRoles(unittest.TestCase):
|
||||
n['voice'] = 'voice_source'
|
||||
for t in staff['tuplets']:
|
||||
t['voice'] = 'voice_source'
|
||||
generator.model.validate_document(doc)
|
||||
generator.model.validate_document(generator.production.assemble(self.source, serial)['electric'])
|
||||
generator.validation.validate_document(doc)
|
||||
generator.validation.validate_document(generator.arrange.assembly.assemble(self.source, serial)['electric'])
|
||||
def test_sparse_parts_reuse_the_canonical_form(self):
|
||||
result = generator.production.generate_role(generator.production.SourceAnalysis.read(tests.solo_fixtures.song(count=4, chords=('Dm7', 'G7', 'CM7'))), 'acoustic_accompaniment', self.root)
|
||||
result = generator.composition.generate_role(generator.source.SourceAnalysis.read(tests.solo_fixtures.song(count=4, chords=('Dm7', 'G7', 'CM7'))), 'acoustic_accompaniment', self.root)
|
||||
measures = result['document']['staves'][0]['measures']
|
||||
def signature(m):
|
||||
return [(n['onset'], n['duration'], [(generator.model.pitch_number(p), p['tablature']) for p in n['pitches']]) for v in m['voices'] for n in v['notes']]
|
||||
|
||||
Reference in New Issue
Block a user