예제 #1
0
    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]
예제 #2
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]
예제 #3
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
예제 #4
0
    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)