def compute(self, beat): if sequences.soprano().is_rest(beat.start()): soprano_pitch = -1 else: soprano_pitch = sequences.soprano().pitch(beat.start()).midi() candidates = get_candidate_matrix(beat, soprano_pitch) scored = {tuple(candidate): self.score(beat, candidate) for candidate in candidates} return util.key_for_highest_value(scored)
def get_all_transforms(start_position, end_position, max_subdivisions): satb = sequences.soprano(), sequences.alto(), sequences.tenor(), sequences.bass() pitches = [(sequence.pitch(start_position), sequence.pitch(end_position)) for sequence in satb] chord = chords.get(start_position) rhythm_set_groups = get_rhythm_sets(config.minimum_time_unit(), max_subdivisions, end_position - start_position) direction_set_groups = [direction_permutations(i) for i in range(1, max_subdivisions)] all_transforms = [] for i, (sequence, (start_pitch, end_pitch)) in enumerate(zip(satb[1:], pitches[1:])): # We can't (read: don't want to) transform to or from a rest; skip if the start or end pitch is a rest. if start_pitch == -1 or end_pitch == -1: all_transforms.append([[]]) continue high_thresh = min([p for p in pitches[i] if p != -1] + [sequence.part().max_high]) low_thresh = sequence.part().max_low if i == len(satb) - 1 else min(sequence.part().max_low, pitches[i - 1]) bounded_pitches = [pitch for pitch in chord.scale() if low_thresh <= pitch <= high_thresh] sequence_transforms = [] for i, direction_set_group in enumerate(direction_set_groups): pitch_sets = [group for direction_set in direction_set_group for group in pitch_sets_for_directions(bounded_pitches, start_pitch, end_pitch, direction_set)] trans = [StrongBeatPhrase(r, p) for p in pitch_sets for r in rhythm_set_groups[i]] sequence_transforms.extend(trans) all_transforms.append(sequence_transforms) product = list(itertools.product(*all_transforms)) return product
def score(self, beat, candidate): bass_score = get_bass_score(candidate[BASS_POSITION], beat) tenor_score = get_tenor_score(candidate[TENOR_POSITION], beat) alto_score = get_alto_score(candidate[ALTO_POSITION], beat) harmony_score = get_harmony_score(candidate, beat) duplicate_penalty = get_duplicate_penalty(candidate) rest_penalty = get_rest_penalty(candidate) motion_score = parallel_motion_score(candidate, beat, sequences.soprano(), sequences.alto(), sequences.tenor(), sequences.bass()) return sum([bass_score, tenor_score, alto_score, harmony_score, motion_score, rest_penalty, duplicate_penalty])
def test__Sequence_note_duration_count(self): fileloader.load(constants.TEST_MIDI + 'linear_motion.mid', False) sequence = sequences.soprano() number_of_sixteenths = 2 number_of_eighths = 5 duration_count = sequence.note_duration_count() self.assertEqual(duration_count.get(constants.SIXTEENTH_NOTE, 0), number_of_sixteenths) self.assertEqual(duration_count.get(constants.EIGHTH_NOTE, 0), number_of_eighths)
def test__Sequence_add_entities_splits(self): fileloader.load(constants.TEST_MIDI + 'entities.mid', False) sequence = sequences.soprano() new_entity_start = 480 new_entity_end = 576 note = sequences.Rest(sequence, new_entity_start, new_entity_end) sequence.add_entities(note) self.assertEqual(new_entity_start, sequence.entities().values()[3].end()) self.assertEqual(new_entity_end, sequence.entities().values()[5].start())
def test__Sequence_add_entities_consumes(self): fileloader.load(constants.TEST_MIDI + 'entities.mid', False) sequence = sequences.soprano() new_entity_start = 144 new_entity_end = 528 note = sequences.Note(sequence, new_entity_start, new_entity_end, pitches.Pitch(61)) sequence.add_entities(note) self.assertEqual(new_entity_start, sequence.entities().values()[1].end()) self.assertEqual(new_entity_end, sequence.entities().values()[3].start())
def test__flicker_avoidance_score(self): fileloader.load(constants.TEST_MIDI + 'flicker.mid', False) sequence = sequences.soprano() c = pitches.MIDI_VALUES['C5'] e = pitches.MIDI_VALUES['E5'] beat2 = time.beat_at_index(2) beat3 = time.beat_at_index(3) self.assertEqual( 1 * vars.FLICKER_COEF, note_picker.flicker_avoidance_score(c, beat2, sequence)) self.assertEqual( 2 * vars.FLICKER_COEF, note_picker.flicker_avoidance_score(e, beat3, sequence))
def test__get_motion_score(self): fileloader.load(constants.TEST_MIDI + 'parallel1.mid', False) soprano = sequences.soprano() tenor = sequences.RootSequence( read_pattern(constants.TEST_MIDI + 'parallel2.mid')[0]) irrelevant_pitch = 11 # [0] = alto, [1] = tenor, [2] = bass candidate = pitches.MIDI_VALUES['D5'], pitches.MIDI_VALUES[ 'A5'], irrelevant_pitch, self.assertEqual( 0.0, note_picker.parallel_motion_score(candidate, time.beat_at_index(0), soprano, sequences.alto(), tenor, sequences.bass())) self.assertEqual( vars.PARALLEL_MOVEMENT, note_picker.parallel_motion_score(candidate, time.beat_at_index(1), soprano, sequences.alto(), tenor, sequences.bass()))
def rhythm_based_strong_beat_score(measure, pattern): """ Returns the likelihood that a measure's strong beat pattern is the given pattern :param measure: time.Measure that we're testing :param pattern: tuple with the pattern, e.g. (0, 2, 4) or (3, 2, 2) in 7 :return: likelihood score """ likelihood_score = 0.0 position = 0 sequence = sequences.soprano() for i in range(len(pattern)): target_duration = ((pattern + (len(measure.beats()), ))[i + 1] - pattern[i]) * measure.beat_length() entity = sequence.entity(measure.start() + sum([j * measure.beat_length() for j in pattern[:i + 1]])) if entity.length() == target_duration and entity.start() == position: likelihood_score += vars.RHYTHM_PHRASING_COEF * ((pattern + (len(measure.beats()), ))[i + 1] - pattern[i]) position += target_duration return likelihood_score
def test__linear_motion_score(self): fileloader.load(constants.TEST_MIDI + 'quarter_arpeg.mid', False) sequence = sequences.soprano() beat_0_pitch = 59 motion_pitch = 61 # start of midi clip, no motion, return 0 self.assertEqual( 0.0, note_picker.linear_motion_score(beat_0_pitch, time.beat_at_index(0), sequence)) # same note as last beat self.assertEqual( 0.0, note_picker.linear_motion_score(beat_0_pitch, time.beat_at_index(1), sequence)) # linear motion exists self.assertEqual( vars.LINEAR_MOTION, note_picker.linear_motion_score(motion_pitch, time.beat_at_index(1), sequence))
for last_beat, this_beat in zip(strong_beats, strong_beats[1:]): t = transforms.get_all_transforms(last_beat.start(), this_beat.start(), 3) print 'yo' # motionizer = motion.Motionizer() # for measure in sequences.bass().measures(): # for beat in measure.beats(): # position = measure.sample_position() + beat.beat_index * config.resolution # # transforms = motionizer.compute_next(sequences.soprano, sequences.alto(), sequences.tenor(), sequences.bass()) # # sequences.alto().apply_transform(transforms['alto']) # sequences.tenor().apply_transform(transforms['tenor']) # sequences.bass().apply_transform(transforms['bass']) # ~~~~~~~~ Write to file ~~~~~~~~ # print(pat_util.sample_length(sequences.soprano().to_pattern())) folder = constants.OUT_DIR + config.name + '/' if not os.path.exists(folder): os.makedirs(folder) midi.write_midifile(folder + 'soprano.mid', sequences.soprano().to_pattern()) midi.write_midifile(folder + 'alto.mid', sequences.alto().to_pattern()) midi.write_midifile(folder + 'tenor.mid', sequences.tenor().to_pattern()) midi.write_midifile(folder + 'bass.mid', sequences.bass().to_pattern()) print 'Your arrangement has been written to ', folder, ' :)'