Spaces:
Build error
Build error
File size: 4,706 Bytes
d8fad2b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
from typing import Optional
from note_seq.protobuf.music_pb2 import NoteSequence
from note_seq.constants import STANDARD_PPQ
def token_sequence_to_note_sequence(
token_sequence: str,
qpm: float = 120.0,
use_program: bool = True,
use_drums: bool = True,
instrument_mapper: Optional[dict] = None,
only_piano: bool = False,
) -> NoteSequence:
"""
Converts a sequence of tokens into a sequence of notes.
Args:
token_sequence (str): The sequence of tokens to convert.
qpm (float, optional): The quarter notes per minute. Defaults to 120.0.
use_program (bool, optional): Whether to use program. Defaults to True.
use_drums (bool, optional): Whether to use drums. Defaults to True.
instrument_mapper (Optional[dict], optional): The instrument mapper. Defaults to None.
only_piano (bool, optional): Whether to only use piano. Defaults to False.
Returns:
NoteSequence: The resulting sequence of notes.
"""
if isinstance(token_sequence, str):
token_sequence = token_sequence.split()
note_sequence = empty_note_sequence(qpm)
# Compute note and bar lengths based on the provided QPM
note_length_16th = 0.25 * 60 / qpm
bar_length = 4.0 * 60 / qpm
# Render all notes.
current_program = 1
current_is_drum = False
current_instrument = 0
track_count = 0
for _, token in enumerate(token_sequence):
if token == "PIECE_START":
pass
elif token == "PIECE_END":
break
elif token == "TRACK_START":
current_bar_index = 0
track_count += 1
pass
elif token == "TRACK_END":
pass
elif token == "KEYS_START":
pass
elif token == "KEYS_END":
pass
elif token.startswith("KEY="):
pass
elif token.startswith("INST"):
instrument = token.split("=")[-1]
if instrument != "DRUMS" and use_program:
if instrument_mapper is not None:
if instrument in instrument_mapper:
instrument = instrument_mapper[instrument]
current_program = int(instrument)
current_instrument = track_count
current_is_drum = False
if instrument == "DRUMS" and use_drums:
current_instrument = 0
current_program = 0
current_is_drum = True
elif token == "BAR_START":
current_time = current_bar_index * bar_length
current_notes = {}
elif token == "BAR_END":
current_bar_index += 1
pass
elif token.startswith("NOTE_ON"):
pitch = int(token.split("=")[-1])
note = note_sequence.notes.add()
note.start_time = current_time
note.end_time = current_time + 4 * note_length_16th
note.pitch = pitch
note.instrument = current_instrument
note.program = current_program
note.velocity = 80
note.is_drum = current_is_drum
current_notes[pitch] = note
elif token.startswith("NOTE_OFF"):
pitch = int(token.split("=")[-1])
if pitch in current_notes:
note = current_notes[pitch]
note.end_time = current_time
elif token.startswith("TIME_DELTA"):
delta = float(token.split("=")[-1]) * note_length_16th
current_time += delta
elif token.startswith("DENSITY="):
pass
elif token == "[PAD]":
pass
else:
pass
# Make the instruments right.
instruments_drums = []
for note in note_sequence.notes:
pair = [note.program, note.is_drum]
if pair not in instruments_drums:
instruments_drums += [pair]
note.instrument = instruments_drums.index(pair)
if only_piano:
for note in note_sequence.notes:
if not note.is_drum:
note.instrument = 0
note.program = 0
return note_sequence
def empty_note_sequence(qpm: float = 120.0, total_time: float = 0.0) -> NoteSequence:
"""
Creates an empty note sequence.
Args:
qpm (float, optional): The quarter notes per minute. Defaults to 120.0.
total_time (float, optional): The total time. Defaults to 0.0.
Returns:
NoteSequence: The empty note sequence.
"""
note_sequence = NoteSequence()
note_sequence.tempos.add().qpm = qpm
note_sequence.ticks_per_quarter = STANDARD_PPQ
note_sequence.total_time = total_time
return note_sequence
|