def test_enharmonic_fixed_tone(self): logging.debug('Start test_enharmonic_fixed_tone') note = Note(DiatonicPitch.parse("C:5"), Duration(1, 4)) policy = FixedToneConstraint(note, DiatonicToneCache.get_tone("Bbb")) lower_policy_context = TestFixedToneConstraint.policy_creator(ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_contextual_note = ContextualNote(lower_policy_context) m = dict([(note, lower_contextual_note)]) v_result = policy.values(m, note) assert len(v_result) == 6 for note in v_result: print('test_simple_fixed_tone pitch = {0}'.format(note.diatonic_pitch)) assert note.diatonic_pitch.diatonic_tone == DiatonicToneCache.get_tone('A') assert note.base_duration == Duration(1, 4) lower_contextual_note.note = note result = policy.verify(m) assert result is True lower_contextual_note.note = None logging.debug('End test_enharmonic_fixed_tone')
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_basic_policy(self): logging.debug('Start test_basic_policy') lower_policy_context = TestRelativeScalarStepConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') note1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) note2 = Note(DiatonicPitch.parse('D:5'), Duration(1, 8)) lower_note_1 = ContextualNote( lower_policy_context, Note(DiatonicPitch.parse('F#:5'), Duration(1, 8))) lower_note_2 = ContextualNote(lower_policy_context) p_map = dict([(note1, lower_note_1), (note2, lower_note_2)]) # F#:5 --> G Major two below and 3 above policy = RelativeScalarStepConstraint(note1, note2, -2, 3) v_result = policy.values(p_map, note2) pitches = [n.diatonic_pitch for n in v_result] assert len(pitches) == 6 for s in ['D:5', 'E:5', 'F#:5', 'G:5', 'A:5', 'B:5']: assert DiatonicPitch.parse(s) in pitches for note in v_result: logging.debug(note) # Check verify for each answer for n in v_result: lower_note_2.note = n assert policy.verify(p_map) logging.debug('End test_basic_policy')
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_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_across_tonalities(self): logging.debug('Start test_across_tonalities.') lower_policy_context_1 = TestRelativeDiatonicConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_policy_context_2 = TestRelativeDiatonicConstraint.policy_creator( ModalityType.Major, DiatonicTone('Ab'), 'tI', 'C:2', 'C:8') upper_note_1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) upper_note_2 = Note(DiatonicPitch.parse('D:5'), Duration(1, 8)) lower_note_1 = ContextualNote( lower_policy_context_1, Note(DiatonicPitch.parse('F#:5'), Duration(1, 8))) lower_note_2 = ContextualNote(lower_policy_context_2) p_map = dict([(upper_note_1, lower_note_1), (upper_note_2, lower_note_2)]) policy = RelativeDiatonicConstraint(upper_note_1, upper_note_2, Interval(3, IntervalType.Minor), Interval(3, IntervalType.Major)) v_result = policy.values(p_map, upper_note_2) for note in v_result: logging.debug(note) pitches = [note.diatonic_pitch for note in v_result] assert {str(p) for p in pitches} == {'Eb:5', 'F:5', 'G:5', 'Ab:5'} logging.debug('End test_across_tonalities.')
def test_reversal_on_policy(self): logging.debug('Start test_reversal_on_policy') lower_policy_context = TestRelativeScalarStepConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') note1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) note2 = Note(DiatonicPitch.parse('D:5'), Duration(1, 8)) lower_note_1 = ContextualNote(lower_policy_context) lower_note_2 = ContextualNote( lower_policy_context, Note(DiatonicPitch.parse('C:5'), Duration(1, 8))) p_map = dict([(note1, lower_note_1), (note2, lower_note_2)]) # F#:5 --> G Major two below and 3 above policy = RelativeScalarStepConstraint(note1, note2, -2, 3) result = policy.values(p_map, note1) pitches = [n.diatonic_pitch for n in result] for pitch in pitches: logging.debug(pitch) # Check that each returned verifies for n in result: lower_note_1.note = n assert policy.verify(p_map) logging.debug('End test_reversal_on_policy')
def test_simple_cross_tonality(self): logging.debug('Start test_simple_cross_tonality') # upper_policy_context = TestStepSequenceConstraint.policy_creator(ModalityType.Major, DiatonicTone('C'), 'tIV', # 'C:2', 'C:8') lower_policy_context_1 = TestStepSequenceConstraint.policy_creator(ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_policy_context_2 = TestStepSequenceConstraint.policy_creator(ModalityType.Major, DiatonicTone('B'), 'tV', 'C:2', 'C:8') upper_pitch_txts = ['C:5', 'D:5', 'E:5', 'F:5'] tonalities = [lower_policy_context_1, lower_policy_context_1, lower_policy_context_2, lower_policy_context_2] differentials = [1, 1, 1] actors = list() p_map = dict() for i in range(0, len(upper_pitch_txts)): upper_note = Note(DiatonicPitch.parse(upper_pitch_txts[i]), Duration(1, 8)) lower_note = ContextualNote(tonalities[i]) actors.append(upper_note) p_map[upper_note] = lower_note policy = StepSequenceConstraint(actors, differentials) p_map[actors[0]].note = Note(DiatonicPitch.parse('B:5'), Duration(1, 8)) answers = ['B:6', 'C:6', 'C#:6', 'D#:6'] 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("------") upper_pitch_txts = ['F#:5', 'E:5', 'D:5', 'C:5'] tonalities = [lower_policy_context_1, lower_policy_context_1, lower_policy_context_2, lower_policy_context_2] differentials = [-1, -1, -1] actors = list() p_map = dict() for i in range(0, len(upper_pitch_txts)): upper_note = Note(DiatonicPitch.parse(upper_pitch_txts[i]), Duration(1, 8)) lower_note = ContextualNote(tonalities[i]) actors.append(upper_note) p_map[upper_note] = lower_note policy = StepSequenceConstraint(actors, differentials) p_map[actors[0]].note = Note(DiatonicPitch.parse('F#:6'), Duration(1, 8)) answers = ['F#:6', 'E:6', 'D#:6', 'C#:6'] 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_simple_cross_tonality')
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_is_chordal(self): logging.debug('Start test_is_chordal') upper_context_note = Note(DiatonicPitch.parse('F:5'), Duration(1, 4)) lower_policy_context = TestChordalToneConstraint.policy_creator(ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_context_note = ContextualNote(lower_policy_context) parameter_map = dict([(upper_context_note, lower_context_note)]) policy = ChordalPitchConstraint(upper_context_note) v_result = policy.values(parameter_map, upper_context_note) results = {DiatonicTone('D'), DiatonicTone('F#'), DiatonicTone('A')} for note in v_result: print('test_is_chordal; note = {0}'.format(note)) tone = note.diatonic_pitch.diatonic_tone octave = note.diatonic_pitch.octave assert tone in results assert octave in range(2, 9) assert len(v_result) == 6 * 3 for note in v_result: parameter_map[upper_context_note].note = note assert policy.verify(parameter_map) is True logging.debug('End test_is_chordal')
def create(line_str, pitch_range, target_hct_list=None): """ Create a PMap from :param line_str: a melodic string :param pitch_range: PitchRange :param target_hct_list: list of pairs ('tonality:chord', duration) :return: pmap Note if target_hct_list is not specified, we use the hct from the line_str. """ lge = LineGrammarExecutor() line, hct = lge.parse(line_str) if target_hct_list is not None: hct = PMap.build_hct(target_hct_list) actors = line.get_all_notes() d = OrderedDict() for note in actors: hc = hct[note.get_absolute_position().position] if hc is None: raise Exception( 'Cannot locate harmonic context for note \'{0}\''.format( note)) contextual_note = ContextualNote(PolicyContext(hc, pitch_range)) d[note] = contextual_note return PMap(d)
def test_is_scalar_with_roles(self): logging.debug('Start test_is_scalar_with_roles') v_note = Note(DiatonicPitch.parse('F:5'), Duration(1, 4)) lower_policy_context = TestScalarPitchConstraint.policy_creator( ModalityType.Major, DiatonicToneCache.get_tone('G'), 'tV', 'G:5', 'G:7') lower_context_note = ContextualNote(lower_policy_context) parameter_map = dict([(v_note, lower_context_note)]) policy = ScalarPitchConstraint(v_note, [3, 5]) v_result = policy.values(parameter_map, v_note) tones = list(lower_policy_context.harmonic_context.tonality.annotation) tones = tones[:-1] for note in v_result: print('test_is_scalar; note = {0}'.format(note)) tone = note.diatonic_pitch.diatonic_tone octave = note.diatonic_pitch.octave assert tone in tones assert tones.index(tone) in [3, 5] assert octave in range(5, 8) assert len(v_result) == 2 * 2 for note in v_result: parameter_map[v_note].note = note assert policy.verify(parameter_map) is True logging.debug('End test_is_scalar_with_roles')
def _build_p_map_dict(self, partial_pitch_results=None): actors = OrderedSet() for p in self.pitch_constraints: actors = actors.union(p.actors) d = OrderedDict() for note in actors: hc = self.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, self.pitch_range)) d[note] = contextual if partial_pitch_results is not None: for k, v in partial_pitch_results.items(): if not isinstance(k, Note): raise Exception( 'key of partial_pitch_results must be a Note.') if not isinstance(v, DiatonicPitch): raise Exception( 'value of partial_pitch_results must be a DiatonicPitch.' ) if k not in d: raise Exception( 'Note \'{0}\' of partial result is not a constraint actor.' .format(k)) d[k].note = Note(v, k.base_duration, k.num_dots) return d
def test_simple_major_scale_descent_two_steps(self): logging.debug('Start test_simple_major_scale_descent_two_steps') upper_context_notes = list() for s in ['C:6', 'A:5', 'F:5', 'D:5', 'B:4']: upper_context_notes.append(Note(DiatonicPitch.parse(s), Duration(1, 8))) lower_policy_context = TestPitchStepConstraint.policy_creator(ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_context_notes = list() for s in range(0, len(upper_context_notes)): lower_context_notes.append(ContextualNote(lower_policy_context)) lower_context_notes[0].note = Note(DiatonicPitch.parse("E:5"), Duration(1, 8)) parameter_map = dict() policies = [] for s, sp in zip(upper_context_notes, lower_context_notes): parameter_map[s] = sp for i in range(0, len(upper_context_notes) - 1): policies.append(PitchStepConstraint(upper_context_notes[i], upper_context_notes[i + 1], 2, PitchStepConstraint.Down)) answers = ['C:5', 'A:4', 'F#:4', 'D:4'] for policy, answer in zip(policies, answers): result = policy.values(parameter_map, policy.note_two) note = next(iter(result)) print(note) assert str(note.diatonic_pitch) == answer parameter_map[policy.note_two].note = note assert policy.verify(parameter_map) logging.debug('End test_simple_major_scale_descent_two_steps')
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_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 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 create_contextual_notes(pitch_list, duration_list, policy_context): assert len(pitch_list) == len(duration_list) assert len(pitch_list) > 0 result = [] for pitch_str, duration_str in zip(pitch_list, duration_list): pitch = DiatonicPitch.parse(pitch_str) duration = TestPitchConstraintSolver.parse_duration(duration_str) note = Note(pitch, duration) cn = ContextualNote(policy_context, note) result.append(cn) return result
def test_is_not_equal(self): logging.debug('Start test_is_not_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, Note(DiatonicPitch.parse('G:6'), Duration(1, 8))) parameter_map = dict([(note1, lower_context_note_a), (note2, lower_context_note_b)]) policy = EqualPitchConstraint([note1, note2]) assert policy.verify(parameter_map) is False logging.debug('End test_is_not_equal')
def test_reverse_arguments(self): logging.debug('Start test_reverse_arguments') lower_policy_context = TestPitchStepConstraint.policy_creator(ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') upper_context_notes = list() for s in ['C:6', 'B5']: upper_context_notes.append(Note(DiatonicPitch.parse(s), Duration(1, 8))) policy = PitchStepConstraint(upper_context_notes[0], upper_context_notes[1], 1, PitchStepConstraint.Down) lower_contextual_note_0 = ContextualNote(lower_policy_context) lower_contextual_note_1 = ContextualNote(lower_policy_context, Note(DiatonicPitch.parse("E:5"), Duration(1, 4))) parameter_map = dict([(upper_context_notes[0], lower_contextual_note_0), (upper_context_notes[1], lower_contextual_note_1)]) result = policy.values(parameter_map, policy.note_one) note = next(iter(result)) print(note) assert str(note.diatonic_pitch) == 'F#:5' logging.debug('End test_reverse_arguments')
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 _build_p_map_dict(self, hct, pitch_constraints): actors = set() for p in pitch_constraints: actors = actors.union(p.actors) d = OrderedDict() for note in actors: hc = hct[note.get_absolute_position().position] if hc is None: raise Exception( 'Cannot locate harmonic context for note \'{0}\''.format( note)) pitch_range = self.score.instrument.sounding_pitch_range() if self.score.instrument is not None \ else PitchRange.create('A:0', 'C:8') contextual = ContextualNote(PolicyContext(hc, pitch_range)) d[note] = contextual return d
def test_simple_diatonic_test(self): logging.debug('Start test_simple_diatonic_test') lower_policy_context = TestRelativeDiatonicConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') upper_note_1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) upper_note_2 = Note(DiatonicPitch.parse('D:5'), Duration(1, 8)) lower_note_1 = ContextualNote( lower_policy_context, Note(DiatonicPitch.parse('F#:5'), Duration(1, 8))) lower_note_2 = ContextualNote(lower_policy_context) p_map = dict([(upper_note_1, lower_note_1), (upper_note_2, lower_note_2)]) policy = RelativeDiatonicConstraint(upper_note_1, upper_note_2, Interval(3, IntervalType.Minor), Interval(3, IntervalType.Major)) v_result = policy.values(p_map, upper_note_2) for note in v_result: logging.debug(note) pitches = [note.diatonic_pitch for note in v_result] assert {str(p) for p in pitches} == {'D:5', 'E:5', 'F#:5', 'G:5', 'A:5'} # test for determining note 1 logging.debug('Determining note 1') lower_note_2.note = lower_note_1.note lower_note_1.note = None v_result = policy.values(p_map, upper_note_1) for note in v_result: logging.debug(note) pitches = [note.diatonic_pitch for note in v_result] assert {str(p) for p in pitches} == {'A:5', 'G:5', 'F#:5', 'E:5'} logging.debug('End test_simple_diatonic_test')
def create_pmap(upper_notes, lower_policy_context): p_map = OrderedDict() for s in upper_notes: lower_cn = ContextualNote(lower_policy_context) p_map[s] = lower_cn return p_map
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 test_compute_simple_scale_tones(self): logging.debug('Start test_compute_simple_scale_tones') lower_policy_context = TestPMap.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 = OrderedDict() 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) p_map[actors[2]].note = Note(DiatonicPitch.parse('G:5'), Duration(1, 8)) solver = PitchConstraintSolver([policy]) results = None try: results, _ = solver.solve(p_map) if results is None: print("Results is None") else: print("Results is not None") if len(results) == 0: print("Results is empty") else: print('Results has {0} results.'.format(len(results))) # verify for pm in results: if not policy.verify(pm.p_map): print('Policy failure: {0}'.format( type(policy).__name__)) print(pm) continue for pm in results: print(pm) except Exception as e: print(e) # print >> sys.stderr, traceback.format_exc() traceback.print_exc() assert results is not None assert len(results) == 1 pm = next(iter(results)) answers = [ 'E:5', 'F#:5', 'G:5', 'B:5', 'D:6', 'E:6', 'D:6', 'B:5', 'G:5', 'F#:5', 'E:5', 'E:5' ] for i in range(0, len(actors)): assert str(pm[actors[i]].note.diatonic_pitch) == answers[i] print('-----') # Build a line and test apply on pm line = Line() begin_note = Note(DiatonicPitch.parse('A:2'), Duration(1, 2)) end_note = Note(DiatonicPitch.parse('B:2'), Duration(1, 2)) offset = Offset(0) line.pin(begin_note, offset) offset = offset + begin_note.duration.duration for note in actors: line.pin(note, offset) offset += note.duration.duration line.pin(end_note, offset) new_line = pm.apply(line) assert new_line is not None assert new_line != line all_notes = new_line.get_all_notes() assert len(all_notes) == 2 + len(actors) assert str(all_notes[0].diatonic_pitch) == 'A:2' assert str(all_notes[-1].diatonic_pitch) == 'B:2' for i in range(1, len(all_notes) - 1): assert str(all_notes[i].diatonic_pitch) == answers[i - 1]
def test_basic_policy(self): logging.debug('Start test_basic_policy') lower_policy_context = TestComparativePitchConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:4', 'C:6') upper_note_1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) upper_note_2 = Note(DiatonicPitch.parse('D:5'), Duration(1, 8)) lower_note_1 = ContextualNote( lower_policy_context, Note(DiatonicPitch.parse('F#:5'), Duration(1, 8))) lower_note_2 = ContextualNote(lower_policy_context) p_map = dict([(upper_note_1, lower_note_1), (upper_note_2, lower_note_2)]) policy = ComparativePitchConstraint( upper_note_1, upper_note_2, ComparativePitchConstraint.LESS_THAN) result = policy.values(p_map, upper_note_2) pitches = sorted([note.diatonic_pitch for note in result]) for pitch in pitches: logging.debug(pitch) # validate assert DiatonicPitch.parse('F#:5') not in pitches assert len(pitches) == 4 for pitch in pitches: assert pitch.chromatic_distance > DiatonicPitch.parse('F#:5').chromatic_distance, \ "{0} <= {1}".format(pitch, DiatonicPitch.parse('F#:5')) for note in result: lower_note_2.note = note assert policy.verify(p_map) is True lower_note_2.note = None # Do less than logging.debug('------') policy = ComparativePitchConstraint( upper_note_1, upper_note_2, ComparativePitchConstraint.GREATER_THAN) result = policy.values(p_map, upper_note_2) pitches = sorted([note.diatonic_pitch for note in result]) for pitch in pitches: logging.debug(pitch) assert DiatonicPitch.parse('F#:5') not in pitches assert len(pitches) == 10 for pitch in pitches: assert pitch.chromatic_distance < DiatonicPitch.parse('F#:5').chromatic_distance, \ "{0} >= {1}".format(pitch, DiatonicPitch.parse('F#:5')) for note in result: lower_note_2.note = note assert policy.verify(p_map) is True lower_note_2.note = None # Do greater than or equal logging.debug('------') policy = ComparativePitchConstraint( upper_note_1, upper_note_2, ComparativePitchConstraint.LESS_EQUAL) result = policy.values(p_map, upper_note_2) pitches = sorted([note.diatonic_pitch for note in result]) for pitch in pitches: logging.debug(pitch) assert DiatonicPitch.parse('F#:5') in pitches assert len(pitches) == 5 for pitch in pitches: assert pitch.chromatic_distance >= DiatonicPitch.parse('F#:5').chromatic_distance, \ "{0} < {1}".format(pitch, DiatonicPitch.parse('F#:5')) for note in result: lower_note_2.note = note assert policy.verify(p_map) is True lower_note_2.note = None # Do less than or equal logging.debug('------') policy = ComparativePitchConstraint( upper_note_1, upper_note_2, ComparativePitchConstraint.GREATER_EQUAL) result = policy.values(p_map, upper_note_2) pitches = sorted([note.diatonic_pitch for note in result]) for pitch in pitches: logging.debug(pitch) assert DiatonicPitch.parse('F#:5') in pitches assert len(pitches) == 11 for pitch in pitches: assert pitch.chromatic_distance <= DiatonicPitch.parse('F#:5').chromatic_distance, \ "{0} > {1}".format(pitch, DiatonicPitch.parse('F#:5')) for note in result: lower_note_2.note = note assert policy.verify(p_map) is True lower_note_2.note = None # Do equal logging.debug('------') policy = ComparativePitchConstraint(upper_note_1, upper_note_2, ComparativePitchConstraint.EQUAL) result = policy.values(p_map, upper_note_2) pitches = sorted([note.diatonic_pitch for note in result]) for pitch in pitches: logging.debug(pitch) assert DiatonicPitch.parse('F#:5') in pitches assert len(pitches) == 1 for pitch in pitches: assert pitch.chromatic_distance == DiatonicPitch.parse('F#:5').chromatic_distance, \ "{0} != {1}".format(pitch, DiatonicPitch.parse('F#:5')) for note in result: lower_note_2.note = note assert policy.verify(p_map) is True lower_note_2.note = None logging.debug('End test_basic_policy')
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