def _transpose(self, note_seq, to_key, min_pitch=constants.MIN_MIDI_PITCH, max_pitch=constants.MAX_MIDI_PITCH) -> NoteSequence: """Transposes a note sequence by the specified amount.""" def update_stats(key): if key in self.stats: self.stats[key] += 1 else: self.stats[key] = 1 note_seq_key = 0 # C major if len(note_seq.key_signatures) == 0: update_stats(NO_KEY_SIGNATURE) elif len(note_seq.key_signatures) > 1: note_seq_key = note_seq.key_signatures[0].key update_stats(MORE_THAN_ONE_KEY_SIGNATURE) amount = to_key - note_seq_key return sequences_lib.transpose_note_sequence( note_seq, amount, min_allowed_pitch=min_pitch, max_allowed_pitch=max_pitch)[0]
def augment(self, ns): stretch_factor = gauss(1.0, 0.5) velocity_factor = gauss(1.0, 0.2) transpose = randrange(-5, 7) ns = stretch_note_sequence(ns, stretch_factor) for note in ns.notes: note.velocity = max(1, min(127, int(note.velocity * velocity_factor))) return transpose_note_sequence(ns, transpose, in_place=True)[0]
def augment_note_sequence(ns, stretch_factor, transpose_amount): """Augment a NoteSequence by time stretch and pitch transposition.""" augmented_ns = sequences_lib.stretch_note_sequence( ns, stretch_factor, in_place=False) try: _, num_deleted_notes = sequences_lib.transpose_note_sequence( augmented_ns, transpose_amount, min_allowed_pitch=MIN_PITCH, max_allowed_pitch=MAX_PITCH, in_place=True) except chord_symbols_lib.ChordSymbolError: raise datagen_beam.DataAugmentationError( 'Transposition of chord symbol(s) failed.') if num_deleted_notes: raise datagen_beam.DataAugmentationError( 'Transposition caused out-of-range pitch(es).') return augmented_ns
def process(self, kv): # Seed random number generator based on key so that hop times are # deterministic. key, ns_str = kv m = hashlib.md5(key) random.seed(int(m.hexdigest(), 16)) # Deserialize NoteSequence proto. ns = note_seq.NoteSequence.FromString(ns_str) # Apply sustain pedal. ns = sequences_lib.apply_sustain_control_changes(ns) # Remove control changes as there are potentially a lot of them and they are # no longer needed. del ns.control_changes[:] for _ in range(self._num_replications): for augment_fn in self._augment_fns: # Augment and encode the performance. try: augmented_performance_sequence = augment_fn(ns) except DataAugmentationError: Metrics.counter('extract_examples', 'augment_performance_failed').inc() continue seq = self._encode_performance_fn( augmented_performance_sequence) # feed in performance as both input/output to music transformer # chopping sequence into length 2048 (throw out shorter sequences) if len(seq) >= 2048: max_offset = len(seq) - 2048 offset = random.randrange(max_offset + 1) cropped_seq = seq[offset:offset + 2048] example_dict = { 'inputs': cropped_seq, 'targets': cropped_seq } if self._melody: # decode truncated performance sequence for melody inference decoded_midi = self._decode_performance_fn(cropped_seq) decoded_ns = note_seq.midi_io.midi_file_to_note_sequence( decoded_midi) # extract melody from cropped performance sequence melody_instrument = melody_inference.infer_melody_for_sequence( decoded_ns, melody_interval_scale=2.0, rest_prob=0.1, instantaneous_non_max_pitch_prob=1e-15, instantaneous_non_empty_rest_prob=0.0, instantaneous_missing_pitch_prob=1e-15) # remove non-melody notes from score score_sequence = copy.deepcopy(decoded_ns) score_notes = [] for note in score_sequence.notes: if note.instrument == melody_instrument: score_notes.append(note) del score_sequence.notes[:] score_sequence.notes.extend(score_notes) # encode melody encode_score_fn = self._encode_score_fns['melody'] example_dict['melody'] = encode_score_fn( score_sequence) # make sure performance input also matches targets; needed for # compatibility of both perf and (mel & perf) autoencoders if self._noisy: # randomly sample a pitch shift to construct noisy performance all_pitches = [x.pitch for x in decoded_ns.notes] min_val = min(all_pitches) max_val = max(all_pitches) transpose_range = range(-(min_val - 21), 108 - max_val + 1) try: transpose_range.remove( 0) # make sure you transpose except ValueError: pass transpose_amount = random.choice(transpose_range) augmented_ns, _ = sequences_lib.transpose_note_sequence( decoded_ns, transpose_amount, min_allowed_pitch=21, max_allowed_pitch=108, in_place=False) aug_seq = self._encode_performance_fn(augmented_ns) example_dict['performance'] = aug_seq else: example_dict['performance'] = example_dict[ 'targets'] del example_dict['inputs'] Metrics.counter('extract_examples', 'encoded_example').inc() Metrics.distribution( 'extract_examples', 'performance_length_in_seconds').update( int(augmented_performance_sequence.total_time)) yield generator_utils.to_example(example_dict)