def test_is_not_equal(self): logging.debug('Start test_is_not_equal') note1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) lower_policy_context = TestNotEqualPitchConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_context_note_a = ContextualNote( lower_policy_context, Note(DiatonicPitch.parse('F#:6'), Duration(1, 8))) p_map = PMap() p_map[note1] = lower_context_note_a other_source = [] for tone in ['B:5', 'D:5', 'E:5']: n = Note(DiatonicPitch.parse(tone), Duration(1, 8)) lower_context_note = ContextualNote(lower_policy_context) p_map[n] = lower_context_note other_source.append(n) params = list([note1]) params.extend(other_source) policy = NotEqualPitchConstraint(params) for c_note in p_map.unassigned_actors(policy): print(c_note) v_result = policy.values(p_map, c_note) assert v_result is not None assert DiatonicPitch.parse('F#:6') not in { n.diatonic_pitch for n in v_result } p_map[other_source[1]].note = Note(DiatonicPitch.parse('E:6'), Duration(1, 8)) for c_note in p_map.unassigned_actors(policy): print(c_note) v_result = policy.values(p_map, c_note) assert v_result is not None ret_pitches = {n.diatonic_pitch for n in v_result} assert len( ret_pitches.intersection( {DiatonicPitch.parse('F#:6'), DiatonicPitch.parse('E:6')})) == 0 assert policy.verify(p_map) is False p_map[other_source[2]].note = Note(DiatonicPitch.parse('F#:6'), Duration(1, 8)) assert policy.verify(p_map) is False p_map[other_source[0]].note = Note(DiatonicPitch.parse('D:6'), Duration(1, 8)) assert policy.verify(p_map) is False p_map[other_source[2]].note = Note(DiatonicPitch.parse('A:6'), Duration(1, 8)) assert policy.verify(p_map) is True logging.debug('End test_is_not_equal') return
def test_compute_with_minor_key(self): print('-- test_compute_with_minor_key ---') line = Line() f = GenericUnivariatePitchFunction( TestFitPitchToFunctionConstraint.sinasoidal, Position(0), Position(2)) v_notes = [ Note(DiatonicPitch.parse('A:4'), Duration(1, 16)) for _ in range(0, 33) ] for i in range(0, 33): line.pin(v_notes[i], Offset(i, 16)) constraint, lower_policy_context = \ TestFitPitchToFunctionConstraint.build_simple_constraint(v_notes[0], f, ModalityType.NaturalMinor, 'C', 'tV') constraints = list() constraints.append(constraint) for i in range(1, 33): c, _ = \ TestFitPitchToFunctionConstraint.build_simple_constraint(v_notes[i], f, ModalityType.NaturalMinor, 'C', 'tV') constraints.append(c) p_map = PMap() p_map[v_notes[0]] = ContextualNote(lower_policy_context) results = constraint.values(p_map, v_notes[0]) assert results is not None assert len(results) == 1 print(next(iter(results)).diatonic_pitch) assert 'C:4' == str(next(iter(results)).diatonic_pitch) result_pitches = [] for i in range(0, 33): p_map = PMap() p_map[v_notes[i]] = ContextualNote(lower_policy_context) results = constraints[i].values(p_map, v_notes[i]) result_pitches.append(next(iter(results)).diatonic_pitch) assert len(result_pitches) == 33 for i in range(0, 33): print('[{0}] {1}'.format(i, str(result_pitches[i]))) checks = [ 'C:4', 'G:4', 'D:5', 'F:5', 'G:5', 'F:5', 'D:5', 'G:4', 'C:4' ] for i in range(0, len(checks)): assert checks[i] == str(result_pitches[i])
def test_non_scale_note(self): logging.debug('Start test_non_scale_note') note = Note(DiatonicPitch.parse("Bb:4"), Duration(1, 4)) policy = FixedPitchConstraint(note, DiatonicPitch.parse("Ab:5")) policy_context = TestFixedPitchConstraint.policy_creator( ModalityType.Major, DiatonicTone('C'), 'tIV', 'C:2', 'C:8') contextual_note = ContextualNote(policy_context) p_map = PMap() p_map[note] = contextual_note v_result = policy.values(p_map, note) result = next(iter(v_result)) print('test_non_scale_note note= {0}'.format(result)) assert result.diatonic_pitch == DiatonicPitch.parse("Ab:5") assert result.base_duration == Duration(1, 4) contextual_note.note = result result = policy.verify(p_map) assert result is True logging.debug('end test_non_scale_note')
def test_is_equal(self): logging.debug('Start test_is_equal') note1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) note2 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) lower_policy_context = TestEqualPitchConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_context_note_a = ContextualNote( lower_policy_context, Note(DiatonicPitch.parse('F#:6'), Duration(1, 8))) lower_context_note_b = ContextualNote(lower_policy_context) parameter_map = dict([(note1, lower_context_note_a), (note2, lower_context_note_b)]) parameter_map = PMap(parameter_map) policy = EqualPitchConstraint([note1, note2]) result = policy.values(parameter_map, note2) actual_note = next(iter(result)) print('test_is_equal; note = {0}'.format(actual_note)) assert actual_note.diatonic_pitch == DiatonicPitch.parse("F#:6") assert actual_note.base_duration == Duration(1, 8) parameter_map[note2].note = actual_note assert policy.verify(parameter_map) is True logging.debug('End test_is_equal')
def test_simple_fixed_pitch(self): logging.debug('Start test_simple_fixed_pitch') note = Note(DiatonicPitch.parse("C:5"), Duration(1, 4)) select_notes = {'A:5', 'C:4', 'Eb:2', 'F#:6'} constraint = FixedPitchSelectSetConstraint( note, {DiatonicPitch.parse(p) for p in select_notes}) policy_context = TestFixedPitchSelectSetConstraint.policy_creator( ModalityType.Major, DiatonicTone('C'), 'tIV', 'C:2', 'C:8') lower_contextual = ContextualNote(policy_context) p_map = PMap() p_map[note] = lower_contextual v_results = constraint.values(p_map, note) assert v_results is not None assert len(v_results) == len(select_notes) for result in v_results: print(str(result)) assert select_notes == {str(n.diatonic_pitch) for n in v_results} assert not constraint.verify(p_map) lower_contextual.note = Note(DiatonicPitch.parse('Eb:2'), Duration(1, 4)) assert constraint.verify(p_map)
def test_for_book_example_2(self): print('----- test for book example 2 -----') source_instance_expression = '{<A-Major:i> [sA:4 A A A] qA:4 [iA:4 A] <:iv> qA:4 [sA:4 A A A] qA:4}' target_instance_expression = '{<G-Major:i> wA:4 <:iv> wA:4}' lge = LineGrammarExecutor() source_instance_line, source_instance_hct = lge.parse( source_instance_expression) actors = source_instance_line.get_all_notes() for a in actors: print("{0}".format(a)) target_instance_line, target_instance_hct = lge.parse( target_instance_expression) target_hcs = target_instance_hct.hc_list() for hc in target_hcs: print("{0}".format(hc)) pitch_range = PitchRange( DiatonicPitch.parse('C:4').chromatic_distance, DiatonicPitch.parse('C:6').chromatic_distance) p_map = PMap.create(source_instance_expression, pitch_range, [('G-Major:I', Duration(3, 4)), ('G-Major:IV', Duration(3, 4))]) actors = p_map.actors policies = OrderedSet() policies.add( StepSequenceConstraint( [actors[0], actors[1], actors[2], actors[3]], [1, 1, 1])) policies.add(ChordalPitchConstraint(actors[0])) policies.add(ChordalPitchConstraint(actors[4])) policies.add(ChordalPitchConstraint(actors[8])) policies.add( StepSequenceConstraint( [actors[8], actors[9], actors[10], actors[11]], [1, -1, -1])) policies.add(EqualPitchConstraint([actors[0], actors[12]])) policies.add(EqualPitchConstraint([actors[4], actors[7]])) policies.add( RelativeDiatonicConstraint(actors[4], actors[5], Interval(3, IntervalType.Major), Interval(1, IntervalType.Perfect))) policies.add(StepSequenceConstraint([actors[5], actors[6]], [-1])) # policies.add(ChordalPitchConstraint(actors[7])) solver = PitchConstraintSolver(policies) full_results, partial_results = solver.solve(p_map) print('Results has {0} results.'.format(len(full_results))) for pm in full_results: if str(pm[actors[7]].note.diatonic_pitch) == 'D:4' and str( pm[actors[0]].note.diatonic_pitch) == 'G:4': print("{0}".format(pm))
def _optimize_note_domain(self, note, constraints, score): """ For note, get all values it can take satisfying all its constraints. Then if there is only one, build a fixed pitch constraint for it. If there are more than two, use the curve fits values to make a fixed pitch to set. :param note: :param constraints: :param score: :return: """ domain = set() first = True for constraint in constraints: # build a pmap for all actor in the constraint pmap = PMap() for n in constraint.actors: hc = score.hct.get_hc_by_position(n.get_absolute_position()) pmap[n] = ContextualNote( PolicyContext( hc, score.instrument.sounding_pitch_range() if score.instrument is not None else PitchRange.create( 'A:0', 'C:8'))) # Get all possible pitch values for note in this constraint. # domain will hold all the values that match across all constraints values = {n.diatonic_pitch for n in constraint.values(pmap, note)} if first: domain = values first = False else: domain = domain.intersection(values) if len(domain) == 0: return set() pitch_list = list(domain) if len(domain) > 2: # Find 2 pitches in domain that are closest to the curve fit valuation = self.pitch_function.eval_as_nearest_pitch( note.get_absolute_position().position) candidates = [ (p, abs(p.chromatic_distance - valuation.chromatic_distance)) for p in domain ] candidates = sorted(candidates, key=lambda candidate: candidate[1] ) # sort on chromatic distance. pitch_list = [candidates[0][0], candidates[1][0]] # Take the top to if len(pitch_list) == 1: return {FixedPitchConstraint(note, pitch_list[0])} # set first as best, second as next best. (first, second) = (pitch_list[0], pitch_list[1]) if pitch_list[0].chromatic_distance <= \ pitch_list[1].chromatic_distance else \ (pitch_list[1], pitch_list[0]) return {FixedPitchSelectSetConstraint(note, [first, second])}
def test_create(self): music_line = '{<Ab-Major:I> qC:4 D E F <Db-Major:IV> iDb:4 Eb F Gb <C-Major:IV> qE:4 F G A }' pr = PitchRange.create('Ab:3', 'C:5') pm = PMap.create(music_line, pr) assert pm is not None assert len(pm.keys()) == 12 assert pm.actors[11].diatonic_pitch is not None assert str(pm.actors[11].diatonic_pitch) == 'A:4' assert pm[pm.actors[11]] is not None assert pm[pm.actors[11]].policy_context is not None assert pm[pm.actors[11]].policy_context.harmonic_context is not None assert pm[ pm.actors[11]].policy_context.harmonic_context.tonality is not None assert str(pm[pm.actors[11]].policy_context.harmonic_context.tonality ) == 'C-Major' target_harmonic_list = [('A-Melodic:iv', 1), ('A-Natural:i', Duration(1, 4)), ('A-Melodic:V', 1)] pm = PMap.create(music_line, pr, target_harmonic_list) assert pm is not None assert len(pm.keys()) == 12
def test_compute_simple_function_tone(self): print('--- test_compute_simple_function_tone ---') line = Line() f = GenericUnivariatePitchFunction( TestFitPitchToFunctionConstraint.sinasoidal, Position(0), Position(2)) v_note = Note(DiatonicPitch.parse('A:4'), Duration(1, 32)) line.pin(v_note, Offset(0)) constraint, lower_policy_context = TestFitPitchToFunctionConstraint.build_simple_constraint( v_note, f, ModalityType.Major, 'G', 'tV') p_map = PMap() p_map[v_note] = ContextualNote(lower_policy_context) results = constraint.values(p_map, v_note) assert results is not None assert len(results) == 1 print(next(iter(results)).diatonic_pitch) assert 'C:4' == str(next(iter(results)).diatonic_pitch) v_note = Note(DiatonicPitch.parse('A:4'), Duration(1, 32)) line.pin(v_note, Offset(1, 32)) constraint, lower_policy_context = TestFitPitchToFunctionConstraint.build_simple_constraint( v_note, f, ModalityType.Major, 'G', 'tV') p_map = PMap() p_map[v_note] = ContextualNote(lower_policy_context) results = constraint.values(p_map, v_note) assert results is not None assert len(results) == 1 print(next(iter(results)).diatonic_pitch) assert 'E:4' == str(next(iter(results)).diatonic_pitch) p_map[v_note].note = next(iter(results)) assert constraint.verify(p_map)
def test_more_than_two(self): logging.debug('Start test_more_than_two') lower_policy_context = TestEqualPitchConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') upper_notes = list() for i in range(0, 5): upper_notes.append(Note(DiatonicPitch.parse('C:5'), Duration(1, 8))) lower_notes = list() for i in range(0, 5): n = ContextualNote(lower_policy_context, Note(DiatonicPitch.parse('F#:6'), Duration(1, 8))) if i == 0 else \ ContextualNote(lower_policy_context) lower_notes.append(n) policy = EqualPitchConstraint(upper_notes) p_map = PMap() for i in range(0, 5): p_map[upper_notes[i]] = lower_notes[i] for i in range(1, len(upper_notes)): v_results = policy.values(p_map, upper_notes[i]) assert len(v_results) == 1 note = next(iter(v_results)) print(note) assert str(note.diatonic_pitch) == 'F#:6' # Again but assign the received note each time - then call verify. for i in range(1, len(upper_notes)): v_results = policy.values(p_map, upper_notes[i]) note = next(iter(v_results)) p_map[upper_notes[i]].note = note assert str(note.diatonic_pitch) == 'F#:6' assert policy.verify(p_map) logging.debug("End test_more_than_two")
def solve(self, p_map_param, instance_limit=-1, accept_partials=False): """ Solve the constraints constraint system using p_map_param as the start. :param p_map_param: Initial PMap to fill out. :param instance_limit: Number of full results to limit search; -1 no limit :param accept_partials: Boolean, True means return some partial results :return: """ p_map = p_map_param if isinstance(p_map_param, PMap) else PMap(p_map_param) self._check_p_map(p_map) self.__instance_limit = instance_limit self.__num_instances = 0 # reset self.__full_results = list() partial_results = [p_map] # list of tuples (v_note, {solution to v_note's policies}) sorted by low number of solutions. unsolved_nodes = [t[0] for t in self._build_potential_values(p_map, p_map.keys())] if len(unsolved_nodes) == 0: raise Exception('Policies insufficient for solution or parameter map is full.') while len(unsolved_nodes) != 0: v_node = unsolved_nodes[0] results_prime = list() for p_map in partial_results: if p_map[v_node] is None or p_map[v_node].note is None: visit_results = self._visit(p_map, v_node) if len(visit_results) == 0: if accept_partials: # if accept partials, keep in partial results. results_prime.append(p_map) else: results_prime.extend(visit_results) # note: contains possible extensions of pmap else: # v_note already filled, keep it in partial_results. results_prime.append(p_map) partial_results = results_prime if self.instance_limit != -1 and len(partial_results) >= self.instance_limit: break unsolved_nodes.remove(v_node) return self.full_results, partial_results if accept_partials else list()
def test_in_range(self): logging.debug('Start test_in_range') lower_policy_context = TestPitchRangeConstraint.policy_creator(ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') v_notes = [] p_map = PMap() for s in ['C:5', 'B:4', 'D:5', 'G:4']: v_note = Note(DiatonicPitch.parse(s), Duration(1, 8)) v_notes.append(v_note) p_map[v_note] = ContextualNote(lower_policy_context) policy = PitchRangeConstraint(v_notes, PitchRange.create('G:3', 'A:4')) values = policy.values(p_map, v_notes[0]) assert values is not None assert len(values) is not 0 pitches = set() for v in values: print(v.diatonic_pitch) pitches.add(v.diatonic_pitch) answers_str = {'G:3', 'A:3', 'B:3', 'C:4', 'D:4', 'E:4', 'F#:4', 'G:4', 'A:4'} answers = {DiatonicPitch.parse(s) for s in answers_str} assert pitches == answers index = 0 it = iter(values) for v_note in v_notes: p_map[v_note].note = next(it) index = index + 1 assert policy.verify(p_map) is True # Change one and get false p_map[v_notes[0]].note = Note(DiatonicPitch.parse('B:4'), Duration(1, 8)) assert policy.verify(p_map) is False logging.debug('End test_in_range')
def test_compute_simple_scale_tones(self): print('Start test_compute_simple_scale_tones') # upper_policy_context = TestStepSequenceConstraint.policy_creator(ModalityType.Major, DiatonicTone('Ab'), # 'tIV', # 'C:2', 'C:8') lower_policy_context = TestStepSequenceConstraint.policy_creator(ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') upper_pitch_txts = ['C:5', 'D:5', 'E:5', 'G:5', 'B:5', 'C:6', 'B:5', 'G:5', 'E:5', 'D:5', 'C:5', 'C:5'] actors = list() differentials = [1, 1, 2, 2, 1, -1, -2, -2, -1, -1, 0] p_map = PMap() for pitch_txt in upper_pitch_txts: upper_note = Note(DiatonicPitch.parse(pitch_txt), Duration(1, 8)) lower_note = ContextualNote(lower_policy_context) p_map[upper_note] = lower_note actors.append(upper_note) policy = StepSequenceConstraint(actors, differentials) notes = policy.values(p_map, actors[2]) print('uninitialized: {0} notes'.format(len(notes))) for note in notes: print(note.diatonic_pitch) print('-----') assert len(notes) == 7 * 6 + 1 assert str(next(iter(notes)).diatonic_pitch) == 'C:2' note = None for n in notes: note = n assert note is not None assert str(note.diatonic_pitch) == 'C:8' p_map[actors[0]].note = Note(DiatonicPitch.parse('F#:4'), Duration(1, 8)) answers = ['F#:4', 'G:4', 'A:4', 'C:5', 'E:5', 'F#:5', 'E:5', 'C:5', 'A:4', 'G:4', 'F#:4', 'F#:4'] for i in range(1, len(actors)): notes = policy.values(p_map, actors[i]) for note in notes: print(note.diatonic_pitch) assert str(next(iter(notes)).diatonic_pitch) == answers[i] print('-----') p_map[actors[-1]].note = Note(DiatonicPitch.parse('F#:4'), Duration(1, 8)) p_map[actors[0]].note = None answers = ['F#:4', 'G:4', 'A:4', 'C:5', 'E:5', 'F#:5', 'E:5', 'C:5', 'A:4', 'G:4', 'F#:4', 'F#:4'] for i in range(1, len(actors)): notes = policy.values(p_map, actors[i]) for note in notes: print(note.diatonic_pitch) assert str(next(iter(notes)).diatonic_pitch) == answers[i] print('-----') p_map[actors[6]].note = Note(DiatonicPitch.parse('E:5'), Duration(1, 8)) p_map[actors[-1]].note = None answers = ['E:5', 'G:4', 'A:4', 'C:5', 'E:5', 'F#:5', 'E:5', 'C:5', 'A:4', 'G:4', 'F#:4', 'F#:4'] for i in range(1, len(actors)): notes = policy.values(p_map, actors[i]) for note in notes: print(note.diatonic_pitch) assert str(next(iter(notes)).diatonic_pitch) == answers[i] print('-----') logging.debug('End test_compute_simple_scale_tones')
def _build_pitch_solutions_old(self, beat_score_results, pitch_constraints): """ Build the final results using the beat results, then the pitch results, then the reshape constraints. :param beat_score_results: Set of (PositionDeltaInfo, LiteScore)'s :param pitch_constraints: Set of Constraints :return: """ final_results = list() pitch_results = list() # Solve the pitch constraints using the beat constraint results. if beat_score_results is not None: for beat_result_pdi, beat_result_score in beat_score_results: revised_constraints = TReshape._regenerate_constraints( pitch_constraints, self.score.line, beat_result_score.line) pitch_solver = PitchConstraintSolver(revised_constraints) p_map_dict = PMap( self._build_p_map_dict(beat_result_pdi.hct, revised_constraints)) pitch_solver_results = pitch_solver.solve(p_map_dict) for pitch_pmap in pitch_solver_results: line = pitch_pmap.apply(beat_result_score.line) pitch_results.append( (pitch_pmap, beat_result_score, LiteScore(line, beat_result_pdi.hct, self.score.instrument, beat_result_pdi.tempo_event_sequence, beat_result_pdi.ts_event_sequence))) else: pitch_solver = PitchConstraintSolver(pitch_constraints) p_map_dict = PMap( self._build_p_map_dict(self.score.hct, pitch_constraints)) pitch_solver_results = pitch_solver.solve(p_map_dict) for pitch_pmap in pitch_solver_results: line = pitch_pmap.apply(self.score.line) pitch_results.append( (pitch_pmap, self.score, LiteScore(line, self.score.hct, self.score.instrument, self.score.tempo_sequence, self.score.time_signature_sequence))) # Solve the reshape constraints using the pitch constraint solutions. for pitch_result_pmap, beat_result_score, pitch_result_score in pitch_results: # Issue 1. we generate constraints for ALL NOTES on pitch_result_score's line, note that this means # we cannot reliably use pitch_result_pmap further on since pitch_result_score is buily with # an apply - meaning the notes are in the pmap's range, not domain. # tersely: pitch_result_pmap: self.score.line --> pitch_result_score.line q = { key: value for key, value in zip(beat_result_score.line.get_all_notes(), pitch_result_score.line.get_all_notes()) } ignore_notes = { q[n] for n in pitch_result_pmap.keys() if pitch_result_pmap[n].note is not None } reshape_constraints = self._generate_reshape_constraints( pitch_result_score.line, pitch_result_score.tempo_sequence, pitch_result_score.time_signature_sequence, ignore_notes) p_map = PMap() for c in reshape_constraints: note = c.actor_note hc = pitch_result_score.hct[ note.get_absolute_position().position] if hc is None: raise Exception( 'Cannot locate harmonic context for note \'{0}\''. format(note)) contextual = ContextualNote( PolicyContext( hc, pitch_result_score.instrument.sounding_pitch_range() if pitch_result_score.instrument is not None else PitchRange.create('A:0', 'C:8'))) # Note: p_map maps from pitch_result_score's line notes to something else (does not matter) p_map[note] = contextual pitch_solver = PitchConstraintSolver(reshape_constraints) reshape_results = pitch_solver.solve(p_map) # reshape_pmap_result maps pitch_result_score's line notes to something else with a pitch designation. # Issue 2): we are getting failures on some notes due to being too close to chord on beat. In these cases, # the solve is not failing, but giving back a partial result. for reshape_pmap_result in reshape_results: master_pmap = PMap() # Not sure pitch_result_pmap maps from beat_score_result.line notes to a note with pitch desig. # reshape_pmap_result pitch_result_score's line notes to something else with a pitch designation. # mm: beat_result_score --> self.score or beat_result_score mm = { key: value for key, value in zip( beat_result_score.line.get_all_notes() if beat_result_score else self.score.line.get_all_notes(), pitch_result_score.line.get_all_notes()) } for note in pitch_result_pmap.keys(): # map notes in pitch_result_score to what beat_score_result would master_pmap[mm[note]] = pitch_result_pmap[note] for note in reshape_pmap_result.keys(): if note not in master_pmap.keys(): master_pmap[note] = reshape_pmap_result[note] line_answer = master_pmap.apply(pitch_result_score.line) final_results.append( LiteScore(line_answer, pitch_result_score.hct, pitch_result_score.instrument, pitch_result_score.tempo_sequence, pitch_result_score.time_signature_sequence)) return final_results
def _build_pitch_solutions(self, beat_score_results, pitch_constraints): """ Build the final results using the beat results, then the pitch results, then the reshape constraints. :param beat_score_results: Set of (PositionDeltaInfo, LiteScore)'s :param pitch_constraints: Set of Constraints :return: """ final_results = list() pitch_results = list() # Solve the pitch constraints using the beat constraint results. if beat_score_results is not None: for beat_result_pdi, beat_result_score in beat_score_results: revised_constraints = TReshape._regenerate_constraints( pitch_constraints, self.score.line, beat_result_score.line) pitch_solver = PitchConstraintSolver(revised_constraints) p_map_dict = PMap( self._build_p_map_dict(beat_result_pdi.hct, revised_constraints)) pitch_solver_results, _ = pitch_solver.solve(p_map_dict) for pitch_pmap in pitch_solver_results: line = pitch_pmap.apply(beat_result_score.line) pitch_results.append( (pitch_pmap, beat_result_score, LiteScore(line, beat_result_pdi.hct, self.score.instrument, beat_result_pdi.tempo_event_sequence, beat_result_pdi.ts_event_sequence))) else: pitch_solver = PitchConstraintSolver(pitch_constraints) p_map_dict = PMap( self._build_p_map_dict(self.score.hct, pitch_constraints)) pitch_solver_results, _ = pitch_solver.solve(p_map_dict) for pitch_pmap in pitch_solver_results: line = pitch_pmap.apply(self.score.line) pitch_results.append( (pitch_pmap, self.score, LiteScore(line, self.score.hct, self.score.instrument, self.score.tempo_sequence, self.score.time_signature_sequence))) # Solve the reshape constraints using the pitch constraint solutions. for pitch_result_pmap, beat_result_score, pitch_result_score in pitch_results: # pitch_result_pmap: self.score.line --> pitch_result_score.line q = { key: value for key, value in zip(beat_result_score.line.get_all_notes(), pitch_result_score.line.get_all_notes()) } # ignore_notes are notes that were satisfied by constraints. ignore_notes = { q[n] for n in pitch_result_pmap.keys() if pitch_result_pmap[n].note is not None } # note_to_pitch_map maps each ignore-note in line to a curve fit pitch. note_to_pitch_map = self._generate_reshape_map( pitch_result_score.line, ignore_notes) # Map pitch result score notes to their resolved pitches master_map = dict() # mm: beat_result_score.line --> pitch_reslt_score.line (self.score or beat_result_score) # For pitch constraint notes, map them to their pitch constraint results. mm = { key: value for key, value in zip( beat_result_score.line.get_all_notes() if beat_result_score else self.score.line.get_all_notes(), pitch_result_score.line.get_all_notes()) } # Put the constraint based notes into master for note in pitch_result_pmap.keys(): # map notes in pitch_result_score to what beat_score_result would if pitch_result_pmap[note].note is None: raise Exception( 'Note {0} not solved for value in constraint.'.format( note)) master_map[ mm[note]] = pitch_result_pmap[note].note.diatonic_pitch # Map reshaped notes in pitch_result_score to their resolved notes into master for note in note_to_pitch_map.keys(): if note not in master_map.keys(): master_map[note] = note_to_pitch_map[note] # Clone pitch_result_score, and build a map from pitch_result_score.line to the clone's notes (mmm) line_answer = pitch_result_score.line.clone() mmm = { key: value for key, value in zip(pitch_result_score.line.get_all_notes(), line_answer.get_all_notes()) } # A shallow form of apply (use mmm and master_map to reset the diatonic pitches on line_answer. for note in master_map.keys(): if master_map[note] is not None: mmm[note].diatonic_pitch = master_map[note] final_results.append( LiteScore(line_answer, pitch_result_score.hct, pitch_result_score.instrument, pitch_result_score.tempo_sequence, pitch_result_score.time_signature_sequence)) return final_results
def test_for_book_example_1(self): print('----- test for book example 1 -----') source_instance_expression = '{<C-Major:IV> [sC:5 B:4 A G] qF:4 [sA:4 B C:5 D] qD:5}' target_instance_expression = '{<G-Major:V> wA:4}' lge = LineGrammarExecutor() target_instance_line, target_instance_hct = lge.parse( target_instance_expression) target_hcs = target_instance_hct.hc_list() for hc in target_hcs: print("{0}".format(hc)) pitch_range = PitchRange.create('C:2', 'C:8') p_map = PMap.create(source_instance_expression, pitch_range, [('G-Major:V', 1)]) actors = p_map.actors for a in actors: print("{0}".format(a)) policies = set() policies.add( PitchStepConstraint(actors[0], actors[1], 1, PitchStepConstraint.Down)) policies.add( PitchStepConstraint(actors[1], actors[2], 1, PitchStepConstraint.Down)) policies.add( PitchStepConstraint(actors[2], actors[3], 1, PitchStepConstraint.Down)) policies.add( PitchStepConstraint(actors[5], actors[6], 1, PitchStepConstraint.UP)) policies.add( PitchStepConstraint(actors[6], actors[7], 1, PitchStepConstraint.UP)) policies.add( PitchStepConstraint(actors[7], actors[8], 1, PitchStepConstraint.UP)) policies.add(EqualPitchConstraint([actors[3], actors[4]])) policies.add(EqualPitchConstraint([actors[8], actors[9]])) policies.add( RelativeDiatonicConstraint(actors[4], actors[5], Interval(3, IntervalType.Major), Interval(1, IntervalType.Perfect))) policies.add( RelativeDiatonicConstraint(actors[3], actors[8], Interval(5, IntervalType.Perfect), Interval(1, IntervalType.Perfect))) policies.add(ChordalPitchConstraint(actors[4])) policies.add(ChordalPitchConstraint(actors[9])) solver = PitchConstraintSolver(policies) full_results, _ = solver.solve(p_map) print('Results has {0} results.'.format(len(full_results))) for pm in full_results: print("{0}".format(pm))