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 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 policy_creator(modality_type, modality_tone, tertian_chord_txt, low_pitch_txt, hi_pitch_txt): diatonic_tonality = Tonality.create(modality_type, modality_tone) chord = TertianChordTemplate.parse(tertian_chord_txt).create_chord(diatonic_tonality) hc = HarmonicContext(diatonic_tonality, chord, Duration(1, 2)) pitch_range = PitchRange(DiatonicPitch.parse(low_pitch_txt).chromatic_distance, DiatonicPitch.parse(hi_pitch_txt).chromatic_distance) return PolicyContext(hc, pitch_range)
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 _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 _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