Spaces:
Running on Zero
Running on Zero
Vansh Chugh commited on
Commit ·
3f552af
1
Parent(s): d6d11f2
initial deploy
Browse files- .gitignore +6 -0
- README.md +12 -4
- SOURCES.md +5 -0
- app.py +209 -0
- checkpoint/checkpoints/best_model.pt +3 -0
- checkpoint/train-args.json +1 -0
- mmt/__init__.py +1 -0
- mmt/encoding.json +1 -0
- mmt/music_x_transformers.py +579 -0
- mmt/representation.py +756 -0
- mmt/utils.py +88 -0
- model.json +11 -0
- packages.txt +1 -0
- requirements.txt +9 -0
.gitignore
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
| 2 |
+
*.pyc
|
| 3 |
+
.DS_Store
|
| 4 |
+
.venv/
|
| 5 |
+
MMT-repo/
|
| 6 |
+
_outputs/
|
README.md
CHANGED
|
@@ -1,13 +1,21 @@
|
|
| 1 |
---
|
| 2 |
title: MMT
|
| 3 |
-
emoji:
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: indigo
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
-
python_version: '3.
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
title: MMT
|
| 3 |
+
emoji: 🛤️
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: indigo
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 5.28.0
|
| 8 |
+
python_version: '3.11'
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
| 11 |
+
license: mit
|
| 12 |
---
|
| 13 |
|
| 14 |
+
# Multitrack Music Transformer (HARP)
|
| 15 |
+
|
| 16 |
+
HARP wrapper around the official implementation of "Multitrack Music Transformer" (ICASSP 2023).
|
| 17 |
+
Generates symbolic multi-instrument music — optionally continuing from an uploaded MIDI seed, or
|
| 18 |
+
unconditioned if none is given.
|
| 19 |
+
|
| 20 |
+
- Paper: https://arxiv.org/abs/2207.06983
|
| 21 |
+
- Code: https://github.com/salu133445/mmt
|
SOURCES.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Sources — MMT
|
| 2 |
+
|
| 3 |
+
- Source repo: https://github.com/salu133445/mmt.git
|
| 4 |
+
- Paper: https://arxiv.org/abs/2207.06983
|
| 5 |
+
- Hardware: undetermined, started on cpu-basic — run `probe_space.py --resize` once app.py is deployed to decide gpu vs cpu
|
app.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
|
| 3 |
+
sys.stdout.reconfigure(line_buffering=True)
|
| 4 |
+
|
| 5 |
+
try:
|
| 6 |
+
import spaces
|
| 7 |
+
except ImportError:
|
| 8 |
+
# keep @spaces.GPU usable as a no-op; ZeroGPU requires this exact name.
|
| 9 |
+
class spaces:
|
| 10 |
+
class GPU:
|
| 11 |
+
def __init__(self, func=None, duration=60):
|
| 12 |
+
self.func = func
|
| 13 |
+
|
| 14 |
+
def __call__(self, *args, **kwargs):
|
| 15 |
+
if self.func is not None:
|
| 16 |
+
return self.func(*args, **kwargs)
|
| 17 |
+
func = args[0]
|
| 18 |
+
return func
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
from pathlib import Path
|
| 22 |
+
|
| 23 |
+
# mmt/ keeps the original repo's bare intra-package imports (`import utils`,
|
| 24 |
+
# `import representation`), so it needs to be on sys.path directly rather
|
| 25 |
+
# than imported as a "mmt.*" package.
|
| 26 |
+
sys.path.insert(0, str(Path(__file__).parent / "mmt"))
|
| 27 |
+
|
| 28 |
+
import gradio as gr
|
| 29 |
+
import muspy
|
| 30 |
+
import numpy as np
|
| 31 |
+
import torch
|
| 32 |
+
from pyharp import ModelCard, build_endpoint, get_default_path
|
| 33 |
+
|
| 34 |
+
import music_x_transformers
|
| 35 |
+
import representation
|
| 36 |
+
import utils as mmt_utils
|
| 37 |
+
|
| 38 |
+
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
|
| 39 |
+
CKPT_DIR = Path(__file__).parent / "checkpoint"
|
| 40 |
+
|
| 41 |
+
train_args = mmt_utils.load_json(CKPT_DIR / "train-args.json")
|
| 42 |
+
encoding = representation.get_encoding()
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def load_model():
|
| 46 |
+
"""Build the model on CPU and load the sod/ape checkpoint weights. Stays on
|
| 47 |
+
CPU here even if GPU hardware is available -- ZeroGPU only allows touching
|
| 48 |
+
CUDA from inside an @spaces.GPU call, not at module load time."""
|
| 49 |
+
m = music_x_transformers.MusicXTransformer(
|
| 50 |
+
dim=train_args["dim"],
|
| 51 |
+
encoding=encoding,
|
| 52 |
+
depth=train_args["layers"],
|
| 53 |
+
heads=train_args["heads"],
|
| 54 |
+
max_seq_len=train_args["max_seq_len"],
|
| 55 |
+
max_beat=train_args["max_beat"],
|
| 56 |
+
rotary_pos_emb=train_args["rel_pos_emb"],
|
| 57 |
+
use_abs_pos_emb=train_args["abs_pos_emb"],
|
| 58 |
+
emb_dropout=train_args["dropout"],
|
| 59 |
+
attn_dropout=train_args["dropout"],
|
| 60 |
+
ff_dropout=train_args["dropout"],
|
| 61 |
+
)
|
| 62 |
+
state_dict = torch.load(
|
| 63 |
+
CKPT_DIR / "checkpoints" / "best_model.pt", map_location="cpu"
|
| 64 |
+
)
|
| 65 |
+
m.load_state_dict(state_dict)
|
| 66 |
+
m.eval()
|
| 67 |
+
return m
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
# Checkpoint is small (~80MB) and lives in the Space repo, so load it
|
| 71 |
+
# synchronously at startup rather than in a background thread.
|
| 72 |
+
model = load_model()
|
| 73 |
+
model_ready = False # has the model been moved onto DEVICE yet?
|
| 74 |
+
|
| 75 |
+
# Fetch upfront so failures show in logs, not after a request.
|
| 76 |
+
muspy.download_musescore_soundfont()
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def encode_seed(midi_path, encoding, max_beat):
|
| 80 |
+
"""Turn an uploaded MIDI file into the token prefix the model continues
|
| 81 |
+
from. Mirrors mmt/convert_sod.py's resolution-adjustment step and
|
| 82 |
+
mmt/dataset.py's max_beat trim, since generate.py normally gets both for
|
| 83 |
+
free from the preprocessed dataset it reads conditioning prefixes from."""
|
| 84 |
+
music = muspy.read(midi_path)
|
| 85 |
+
music.adjust_resolution(encoding["resolution"])
|
| 86 |
+
for track in music:
|
| 87 |
+
for note in track:
|
| 88 |
+
if note.duration == 0:
|
| 89 |
+
note.duration = 1
|
| 90 |
+
music.remove_duplicate()
|
| 91 |
+
|
| 92 |
+
notes = representation.extract_notes(music, encoding["resolution"])
|
| 93 |
+
if len(notes) == 0:
|
| 94 |
+
raise gr.Error("No usable notes found in the uploaded MIDI (check instruments are General MIDI, non-drum).")
|
| 95 |
+
n_beats = notes[-1, 0] + 1
|
| 96 |
+
if n_beats > max_beat:
|
| 97 |
+
notes = notes[notes[:, 0] < max_beat]
|
| 98 |
+
|
| 99 |
+
codes = representation.encode_notes(notes, encoding)
|
| 100 |
+
return codes[:-1] # drop the trailing EOS row so generation continues instead of stopping immediately
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
@spaces.GPU
|
| 104 |
+
@torch.inference_mode()
|
| 105 |
+
def process_fn(input_midi_path, generation_length, temperature, focus):
|
| 106 |
+
"""Generate a multi-instrument continuation of an uploaded MIDI seed, or an
|
| 107 |
+
unconditioned sample if no seed is given, and return it as MIDI + a rendered
|
| 108 |
+
audio preview."""
|
| 109 |
+
global model, model_ready
|
| 110 |
+
if not model_ready:
|
| 111 |
+
model = model.to(DEVICE)
|
| 112 |
+
model_ready = True
|
| 113 |
+
|
| 114 |
+
sos = encoding["type_code_map"]["start-of-song"]
|
| 115 |
+
eos = encoding["type_code_map"]["end-of-song"]
|
| 116 |
+
|
| 117 |
+
if input_midi_path:
|
| 118 |
+
prefix_codes = encode_seed(input_midi_path, encoding, train_args["max_beat"])
|
| 119 |
+
tgt_start = torch.tensor(prefix_codes, dtype=torch.long, device=DEVICE).unsqueeze(0)
|
| 120 |
+
else:
|
| 121 |
+
tgt_start = torch.zeros((1, 1, 6), dtype=torch.long, device=DEVICE)
|
| 122 |
+
tgt_start[:, 0, 0] = sos
|
| 123 |
+
|
| 124 |
+
generated = model.generate(
|
| 125 |
+
tgt_start,
|
| 126 |
+
int(generation_length),
|
| 127 |
+
eos_token=eos,
|
| 128 |
+
temperature=temperature,
|
| 129 |
+
filter_logits_fn="top_k",
|
| 130 |
+
filter_thres=focus,
|
| 131 |
+
monotonicity_dim=("type", "beat"),
|
| 132 |
+
)
|
| 133 |
+
full_codes = torch.cat((tgt_start, generated), 1)[0].cpu().numpy()
|
| 134 |
+
|
| 135 |
+
music = representation.decode(full_codes, encoding)
|
| 136 |
+
|
| 137 |
+
midi_path = get_default_path(ext=".mid")
|
| 138 |
+
music.write(midi_path)
|
| 139 |
+
|
| 140 |
+
audio_path = get_default_path(ext=".wav")
|
| 141 |
+
music.write(audio_path) # uses the MuseScore General soundfont muspy fetches on first use
|
| 142 |
+
|
| 143 |
+
return midi_path, audio_path
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
model_card = ModelCard(
|
| 147 |
+
name="Multitrack Music Transformer",
|
| 148 |
+
description=(
|
| 149 |
+
"Generates symbolic multi-instrument music. Upload a MIDI seed to continue it, "
|
| 150 |
+
"or leave it empty for an unconditioned generation. Trained on the Symbolic "
|
| 151 |
+
"Orchestral Database (SOD)."
|
| 152 |
+
),
|
| 153 |
+
author="Hao-Wen Dong, Ke Chen, Shlomo Dubnov, Julian McAuley, Taylor Berg-Kirkpatrick",
|
| 154 |
+
tags=["symbolic-music", "midi", "multitrack", "transformer"],
|
| 155 |
+
)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
with gr.Blocks() as demo:
|
| 159 |
+
input_components = [
|
| 160 |
+
gr.File(
|
| 161 |
+
type="filepath",
|
| 162 |
+
label="Seed MIDI (optional)",
|
| 163 |
+
file_types=[".mid", ".midi"],
|
| 164 |
+
).harp_required(False),
|
| 165 |
+
gr.Slider(
|
| 166 |
+
minimum=64,
|
| 167 |
+
maximum=1024,
|
| 168 |
+
step=64,
|
| 169 |
+
value=1024,
|
| 170 |
+
label="Generation Length",
|
| 171 |
+
info="Number of musical events to generate (default: 1024, per repo config)",
|
| 172 |
+
),
|
| 173 |
+
gr.Slider(
|
| 174 |
+
minimum=0.1,
|
| 175 |
+
maximum=2.0,
|
| 176 |
+
step=0.1,
|
| 177 |
+
value=1.0,
|
| 178 |
+
label="Randomness",
|
| 179 |
+
info="Sampling temperature -- higher wanders more (default: 1.0, per repo config)",
|
| 180 |
+
),
|
| 181 |
+
gr.Slider(
|
| 182 |
+
minimum=0.5,
|
| 183 |
+
maximum=0.99,
|
| 184 |
+
step=0.01,
|
| 185 |
+
value=0.9,
|
| 186 |
+
label="Focus",
|
| 187 |
+
info="Higher keeps only the most likely notes; lower allows more variety (default: 0.9, per repo config)",
|
| 188 |
+
),
|
| 189 |
+
]
|
| 190 |
+
output_components = [
|
| 191 |
+
gr.File(
|
| 192 |
+
label="Generated MIDI",
|
| 193 |
+
file_types=[".mid", ".midi"],
|
| 194 |
+
).set_info("The generated multi-instrument MIDI."),
|
| 195 |
+
gr.Audio(
|
| 196 |
+
type="filepath",
|
| 197 |
+
label="Audio Preview",
|
| 198 |
+
).set_info("A synthesized audio preview of the generated MIDI."),
|
| 199 |
+
]
|
| 200 |
+
|
| 201 |
+
build_endpoint(
|
| 202 |
+
model_card=model_card,
|
| 203 |
+
input_components=input_components,
|
| 204 |
+
output_components=output_components,
|
| 205 |
+
process_fn=process_fn,
|
| 206 |
+
)
|
| 207 |
+
|
| 208 |
+
if __name__ == "__main__":
|
| 209 |
+
demo.queue().launch(pwa=True)
|
checkpoint/checkpoints/best_model.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7c24d1ba5b4e6dbeb346b24734c0f7d0b15f3d3c417490f6d106f49d2f000673
|
| 3 |
+
size 79821244
|
checkpoint/train-args.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"dataset": "sod", "train_names": "data/sod/processed/train-names.txt", "valid_names": "data/sod/processed/valid-names.txt", "in_dir": "data/sod/processed/notes", "out_dir": "/data/herman/workspace/mtmt/exp/sod/ape", "batch_size": 8, "use_csv": false, "aug": true, "max_seq_len": 1024, "max_beat": 256, "dim": 512, "layers": 6, "heads": 8, "dropout": 0.2, "abs_pos_emb": true, "rel_pos_emb": false, "steps": 200000, "valid_steps": 1000, "early_stopping": true, "early_stopping_tolerance": 20, "learning_rate": 0.0005, "lr_warmup_steps": 5000, "lr_decay_steps": 100000, "lr_decay_multiplier": 0.1, "grad_norm_clip": 1.0, "gpu": 7, "jobs": 8, "quiet": false}
|
mmt/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
"""MMT model."""
|
mmt/encoding.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"resolution": 24, "max_beat": 1024, "max_duration": 384, "dimensions": ["type", "beat", "position", "pitch", "duration", "instrument"], "n_tokens": [5, 1026, 25, 129, 25, 65], "type_code_map": {"start-of-song": 0, "instrument": 1, "start-of-notes": 2, "note": 3, "end-of-song": 4}, "beat_code_map": {"0": 1, "1": 2, "2": 3, "3": 4, "4": 5, "5": 6, "6": 7, "7": 8, "8": 9, "9": 10, "10": 11, "11": 12, "12": 13, "13": 14, "14": 15, "15": 16, "16": 17, "17": 18, "18": 19, "19": 20, "20": 21, "21": 22, "22": 23, "23": 24, "24": 25, "25": 26, "26": 27, "27": 28, "28": 29, "29": 30, "30": 31, "31": 32, "32": 33, "33": 34, "34": 35, "35": 36, "36": 37, "37": 38, "38": 39, "39": 40, "40": 41, "41": 42, "42": 43, "43": 44, "44": 45, "45": 46, "46": 47, "47": 48, "48": 49, "49": 50, "50": 51, "51": 52, "52": 53, "53": 54, "54": 55, "55": 56, "56": 57, "57": 58, "58": 59, "59": 60, "60": 61, "61": 62, "62": 63, "63": 64, "64": 65, "65": 66, "66": 67, "67": 68, "68": 69, "69": 70, "70": 71, "71": 72, "72": 73, "73": 74, "74": 75, "75": 76, "76": 77, "77": 78, "78": 79, "79": 80, "80": 81, "81": 82, "82": 83, "83": 84, "84": 85, "85": 86, "86": 87, "87": 88, "88": 89, "89": 90, "90": 91, "91": 92, "92": 93, "93": 94, "94": 95, "95": 96, "96": 97, "97": 98, "98": 99, "99": 100, "100": 101, "101": 102, "102": 103, "103": 104, "104": 105, "105": 106, "106": 107, "107": 108, "108": 109, "109": 110, "110": 111, "111": 112, "112": 113, "113": 114, "114": 115, "115": 116, "116": 117, "117": 118, "118": 119, "119": 120, "120": 121, "121": 122, "122": 123, "123": 124, "124": 125, "125": 126, "126": 127, "127": 128, "128": 129, "129": 130, "130": 131, "131": 132, "132": 133, "133": 134, "134": 135, "135": 136, "136": 137, "137": 138, "138": 139, "139": 140, "140": 141, "141": 142, "142": 143, "143": 144, "144": 145, "145": 146, "146": 147, "147": 148, "148": 149, "149": 150, "150": 151, "151": 152, "152": 153, "153": 154, "154": 155, "155": 156, "156": 157, "157": 158, "158": 159, "159": 160, "160": 161, "161": 162, "162": 163, "163": 164, "164": 165, "165": 166, "166": 167, "167": 168, "168": 169, "169": 170, "170": 171, "171": 172, "172": 173, "173": 174, "174": 175, "175": 176, "176": 177, "177": 178, "178": 179, "179": 180, "180": 181, "181": 182, "182": 183, "183": 184, "184": 185, "185": 186, "186": 187, "187": 188, "188": 189, "189": 190, "190": 191, "191": 192, "192": 193, "193": 194, "194": 195, "195": 196, "196": 197, "197": 198, "198": 199, "199": 200, "200": 201, "201": 202, "202": 203, "203": 204, "204": 205, "205": 206, "206": 207, "207": 208, "208": 209, "209": 210, "210": 211, "211": 212, "212": 213, "213": 214, "214": 215, "215": 216, "216": 217, "217": 218, "218": 219, "219": 220, "220": 221, "221": 222, "222": 223, "223": 224, "224": 225, "225": 226, "226": 227, "227": 228, "228": 229, "229": 230, "230": 231, "231": 232, "232": 233, "233": 234, "234": 235, "235": 236, "236": 237, "237": 238, "238": 239, "239": 240, "240": 241, "241": 242, "242": 243, "243": 244, "244": 245, "245": 246, "246": 247, "247": 248, "248": 249, "249": 250, "250": 251, "251": 252, "252": 253, "253": 254, "254": 255, "255": 256, "256": 257, "257": 258, "258": 259, "259": 260, "260": 261, "261": 262, "262": 263, "263": 264, "264": 265, "265": 266, "266": 267, "267": 268, "268": 269, "269": 270, "270": 271, "271": 272, "272": 273, "273": 274, "274": 275, "275": 276, "276": 277, "277": 278, "278": 279, "279": 280, "280": 281, "281": 282, "282": 283, "283": 284, "284": 285, "285": 286, "286": 287, "287": 288, "288": 289, "289": 290, "290": 291, "291": 292, "292": 293, "293": 294, "294": 295, "295": 296, "296": 297, "297": 298, "298": 299, "299": 300, "300": 301, "301": 302, "302": 303, "303": 304, "304": 305, "305": 306, "306": 307, "307": 308, "308": 309, "309": 310, "310": 311, "311": 312, "312": 313, "313": 314, "314": 315, "315": 316, "316": 317, "317": 318, "318": 319, "319": 320, "320": 321, "321": 322, "322": 323, "323": 324, "324": 325, "325": 326, "326": 327, "327": 328, "328": 329, "329": 330, "330": 331, "331": 332, "332": 333, "333": 334, "334": 335, "335": 336, "336": 337, "337": 338, "338": 339, "339": 340, "340": 341, "341": 342, "342": 343, "343": 344, "344": 345, "345": 346, "346": 347, "347": 348, "348": 349, "349": 350, "350": 351, "351": 352, "352": 353, "353": 354, "354": 355, "355": 356, "356": 357, "357": 358, "358": 359, "359": 360, "360": 361, "361": 362, "362": 363, "363": 364, "364": 365, "365": 366, "366": 367, "367": 368, "368": 369, "369": 370, "370": 371, "371": 372, "372": 373, "373": 374, "374": 375, "375": 376, "376": 377, "377": 378, "378": 379, "379": 380, "380": 381, "381": 382, "382": 383, "383": 384, "384": 385, "385": 386, "386": 387, "387": 388, "388": 389, "389": 390, "390": 391, "391": 392, "392": 393, "393": 394, "394": 395, "395": 396, "396": 397, "397": 398, "398": 399, "399": 400, "400": 401, "401": 402, "402": 403, "403": 404, "404": 405, "405": 406, "406": 407, "407": 408, "408": 409, "409": 410, "410": 411, "411": 412, "412": 413, "413": 414, "414": 415, "415": 416, "416": 417, "417": 418, "418": 419, "419": 420, "420": 421, "421": 422, "422": 423, "423": 424, "424": 425, "425": 426, "426": 427, "427": 428, "428": 429, "429": 430, "430": 431, "431": 432, "432": 433, "433": 434, "434": 435, "435": 436, "436": 437, "437": 438, "438": 439, "439": 440, "440": 441, "441": 442, "442": 443, "443": 444, "444": 445, "445": 446, "446": 447, "447": 448, "448": 449, "449": 450, "450": 451, "451": 452, "452": 453, "453": 454, "454": 455, "455": 456, "456": 457, "457": 458, "458": 459, "459": 460, "460": 461, "461": 462, "462": 463, "463": 464, "464": 465, "465": 466, "466": 467, "467": 468, "468": 469, "469": 470, "470": 471, "471": 472, "472": 473, "473": 474, "474": 475, "475": 476, "476": 477, "477": 478, "478": 479, "479": 480, "480": 481, "481": 482, "482": 483, "483": 484, "484": 485, "485": 486, "486": 487, "487": 488, "488": 489, "489": 490, "490": 491, "491": 492, "492": 493, "493": 494, "494": 495, "495": 496, "496": 497, "497": 498, "498": 499, "499": 500, "500": 501, "501": 502, "502": 503, "503": 504, "504": 505, "505": 506, "506": 507, "507": 508, "508": 509, "509": 510, "510": 511, "511": 512, "512": 513, "513": 514, "514": 515, "515": 516, "516": 517, "517": 518, "518": 519, "519": 520, "520": 521, "521": 522, "522": 523, "523": 524, "524": 525, "525": 526, "526": 527, "527": 528, "528": 529, "529": 530, "530": 531, "531": 532, "532": 533, "533": 534, "534": 535, "535": 536, "536": 537, "537": 538, "538": 539, "539": 540, "540": 541, "541": 542, "542": 543, "543": 544, "544": 545, "545": 546, "546": 547, "547": 548, "548": 549, "549": 550, "550": 551, "551": 552, "552": 553, "553": 554, "554": 555, "555": 556, "556": 557, "557": 558, "558": 559, "559": 560, "560": 561, "561": 562, "562": 563, "563": 564, "564": 565, "565": 566, "566": 567, "567": 568, "568": 569, "569": 570, "570": 571, "571": 572, "572": 573, "573": 574, "574": 575, "575": 576, "576": 577, "577": 578, "578": 579, "579": 580, "580": 581, "581": 582, "582": 583, "583": 584, "584": 585, "585": 586, "586": 587, "587": 588, "588": 589, "589": 590, "590": 591, "591": 592, "592": 593, "593": 594, "594": 595, "595": 596, "596": 597, "597": 598, "598": 599, "599": 600, "600": 601, "601": 602, "602": 603, "603": 604, "604": 605, "605": 606, "606": 607, "607": 608, "608": 609, "609": 610, "610": 611, "611": 612, "612": 613, "613": 614, "614": 615, "615": 616, "616": 617, "617": 618, "618": 619, "619": 620, "620": 621, "621": 622, "622": 623, "623": 624, "624": 625, "625": 626, "626": 627, "627": 628, "628": 629, "629": 630, "630": 631, "631": 632, "632": 633, "633": 634, "634": 635, "635": 636, "636": 637, "637": 638, "638": 639, "639": 640, "640": 641, "641": 642, "642": 643, "643": 644, "644": 645, "645": 646, "646": 647, "647": 648, "648": 649, "649": 650, "650": 651, "651": 652, "652": 653, "653": 654, "654": 655, "655": 656, "656": 657, "657": 658, "658": 659, "659": 660, "660": 661, "661": 662, "662": 663, "663": 664, "664": 665, "665": 666, "666": 667, "667": 668, "668": 669, "669": 670, "670": 671, "671": 672, "672": 673, "673": 674, "674": 675, "675": 676, "676": 677, "677": 678, "678": 679, "679": 680, "680": 681, "681": 682, "682": 683, "683": 684, "684": 685, "685": 686, "686": 687, "687": 688, "688": 689, "689": 690, "690": 691, "691": 692, "692": 693, "693": 694, "694": 695, "695": 696, "696": 697, "697": 698, "698": 699, "699": 700, "700": 701, "701": 702, "702": 703, "703": 704, "704": 705, "705": 706, "706": 707, "707": 708, "708": 709, "709": 710, "710": 711, "711": 712, "712": 713, "713": 714, "714": 715, "715": 716, "716": 717, "717": 718, "718": 719, "719": 720, "720": 721, "721": 722, "722": 723, "723": 724, "724": 725, "725": 726, "726": 727, "727": 728, "728": 729, "729": 730, "730": 731, "731": 732, "732": 733, "733": 734, "734": 735, "735": 736, "736": 737, "737": 738, "738": 739, "739": 740, "740": 741, "741": 742, "742": 743, "743": 744, "744": 745, "745": 746, "746": 747, "747": 748, "748": 749, "749": 750, "750": 751, "751": 752, "752": 753, "753": 754, "754": 755, "755": 756, "756": 757, "757": 758, "758": 759, "759": 760, "760": 761, "761": 762, "762": 763, "763": 764, "764": 765, "765": 766, "766": 767, "767": 768, "768": 769, "769": 770, "770": 771, "771": 772, "772": 773, "773": 774, "774": 775, "775": 776, "776": 777, "777": 778, "778": 779, "779": 780, "780": 781, "781": 782, "782": 783, "783": 784, "784": 785, "785": 786, "786": 787, "787": 788, "788": 789, "789": 790, "790": 791, "791": 792, "792": 793, "793": 794, "794": 795, "795": 796, "796": 797, "797": 798, "798": 799, "799": 800, "800": 801, "801": 802, "802": 803, "803": 804, "804": 805, "805": 806, "806": 807, "807": 808, "808": 809, "809": 810, "810": 811, "811": 812, "812": 813, "813": 814, "814": 815, "815": 816, "816": 817, "817": 818, "818": 819, "819": 820, "820": 821, "821": 822, "822": 823, "823": 824, "824": 825, "825": 826, "826": 827, "827": 828, "828": 829, "829": 830, "830": 831, "831": 832, "832": 833, "833": 834, "834": 835, "835": 836, "836": 837, "837": 838, "838": 839, "839": 840, "840": 841, "841": 842, "842": 843, "843": 844, "844": 845, "845": 846, "846": 847, "847": 848, "848": 849, "849": 850, "850": 851, "851": 852, "852": 853, "853": 854, "854": 855, "855": 856, "856": 857, "857": 858, "858": 859, "859": 860, "860": 861, "861": 862, "862": 863, "863": 864, "864": 865, "865": 866, "866": 867, "867": 868, "868": 869, "869": 870, "870": 871, "871": 872, "872": 873, "873": 874, "874": 875, "875": 876, "876": 877, "877": 878, "878": 879, "879": 880, "880": 881, "881": 882, "882": 883, "883": 884, "884": 885, "885": 886, "886": 887, "887": 888, "888": 889, "889": 890, "890": 891, "891": 892, "892": 893, "893": 894, "894": 895, "895": 896, "896": 897, "897": 898, "898": 899, "899": 900, "900": 901, "901": 902, "902": 903, "903": 904, "904": 905, "905": 906, "906": 907, "907": 908, "908": 909, "909": 910, "910": 911, "911": 912, "912": 913, "913": 914, "914": 915, "915": 916, "916": 917, "917": 918, "918": 919, "919": 920, "920": 921, "921": 922, "922": 923, "923": 924, "924": 925, "925": 926, "926": 927, "927": 928, "928": 929, "929": 930, "930": 931, "931": 932, "932": 933, "933": 934, "934": 935, "935": 936, "936": 937, "937": 938, "938": 939, "939": 940, "940": 941, "941": 942, "942": 943, "943": 944, "944": 945, "945": 946, "946": 947, "947": 948, "948": 949, "949": 950, "950": 951, "951": 952, "952": 953, "953": 954, "954": 955, "955": 956, "956": 957, "957": 958, "958": 959, "959": 960, "960": 961, "961": 962, "962": 963, "963": 964, "964": 965, "965": 966, "966": 967, "967": 968, "968": 969, "969": 970, "970": 971, "971": 972, "972": 973, "973": 974, "974": 975, "975": 976, "976": 977, "977": 978, "978": 979, "979": 980, "980": 981, "981": 982, "982": 983, "983": 984, "984": 985, "985": 986, "986": 987, "987": 988, "988": 989, "989": 990, "990": 991, "991": 992, "992": 993, "993": 994, "994": 995, "995": 996, "996": 997, "997": 998, "998": 999, "999": 1000, "1000": 1001, "1001": 1002, "1002": 1003, "1003": 1004, "1004": 1005, "1005": 1006, "1006": 1007, "1007": 1008, "1008": 1009, "1009": 1010, "1010": 1011, "1011": 1012, "1012": 1013, "1013": 1014, "1014": 1015, "1015": 1016, "1016": 1017, "1017": 1018, "1018": 1019, "1019": 1020, "1020": 1021, "1021": 1022, "1022": 1023, "1023": 1024, "1024": 1025, "null": 0}, "position_code_map": {"0": 1, "1": 2, "2": 3, "3": 4, "4": 5, "5": 6, "6": 7, "7": 8, "8": 9, "9": 10, "10": 11, "11": 12, "12": 13, "13": 14, "14": 15, "15": 16, "16": 17, "17": 18, "18": 19, "19": 20, "20": 21, "21": 22, "22": 23, "23": 24, "null": 0}, "pitch_code_map": {"0": 1, "1": 2, "2": 3, "3": 4, "4": 5, "5": 6, "6": 7, "7": 8, "8": 9, "9": 10, "10": 11, "11": 12, "12": 13, "13": 14, "14": 15, "15": 16, "16": 17, "17": 18, "18": 19, "19": 20, "20": 21, "21": 22, "22": 23, "23": 24, "24": 25, "25": 26, "26": 27, "27": 28, "28": 29, "29": 30, "30": 31, "31": 32, "32": 33, "33": 34, "34": 35, "35": 36, "36": 37, "37": 38, "38": 39, "39": 40, "40": 41, "41": 42, "42": 43, "43": 44, "44": 45, "45": 46, "46": 47, "47": 48, "48": 49, "49": 50, "50": 51, "51": 52, "52": 53, "53": 54, "54": 55, "55": 56, "56": 57, "57": 58, "58": 59, "59": 60, "60": 61, "61": 62, "62": 63, "63": 64, "64": 65, "65": 66, "66": 67, "67": 68, "68": 69, "69": 70, "70": 71, "71": 72, "72": 73, "73": 74, "74": 75, "75": 76, "76": 77, "77": 78, "78": 79, "79": 80, "80": 81, "81": 82, "82": 83, "83": 84, "84": 85, "85": 86, "86": 87, "87": 88, "88": 89, "89": 90, "90": 91, "91": 92, "92": 93, "93": 94, "94": 95, "95": 96, "96": 97, "97": 98, "98": 99, "99": 100, "100": 101, "101": 102, "102": 103, "103": 104, "104": 105, "105": 106, "106": 107, "107": 108, "108": 109, "109": 110, "110": 111, "111": 112, "112": 113, "113": 114, "114": 115, "115": 116, "116": 117, "117": 118, "118": 119, "119": 120, "120": 121, "121": 122, "122": 123, "123": 124, "124": 125, "125": 126, "126": 127, "127": 128, "null": 0}, "duration_code_map": {"0": 1, "1": 1, "2": 2, "3": 3, "4": 3, "5": 3, "6": 3, "7": 3, "8": 4, "9": 4, "10": 4, "11": 4, "12": 4, "13": 4, "14": 5, "15": 5, "16": 6, "17": 6, "18": 7, "19": 7, "20": 8, "21": 9, "22": 9, "23": 10, "24": 10, "25": 10, "26": 10, "27": 10, "28": 11, "29": 11, "30": 11, "31": 11, "32": 11, "33": 11, "34": 12, "35": 12, "36": 12, "37": 12, "38": 12, "39": 13, "40": 13, "41": 13, "42": 14, "43": 14, "44": 14, "45": 14, "46": 15, "47": 15, "48": 15, "49": 15, "50": 15, "51": 15, "52": 15, "53": 15, "54": 15, "55": 16, "56": 16, "57": 16, "58": 16, "59": 16, "60": 16, "61": 16, "62": 16, "63": 16, "64": 16, "65": 16, "66": 16, "67": 17, "68": 17, "69": 17, "70": 17, "71": 17, "72": 17, "73": 17, "74": 17, "75": 17, "76": 17, "77": 17, "78": 17, "79": 18, "80": 18, "81": 18, "82": 18, "83": 18, "84": 18, "85": 18, "86": 18, "87": 18, "88": 18, "89": 18, "90": 18, "91": 19, "92": 19, "93": 19, "94": 19, "95": 19, "96": 19, "97": 19, "98": 19, "99": 19, "100": 19, "101": 19, "102": 19, "103": 19, "104": 19, "105": 19, "106": 19, "107": 19, "108": 19, "109": 20, "110": 20, "111": 20, "112": 20, "113": 20, "114": 20, "115": 20, "116": 20, "117": 20, "118": 20, "119": 20, "120": 20, "121": 20, "122": 20, "123": 20, "124": 20, "125": 20, "126": 20, "127": 20, "128": 20, "129": 20, "130": 20, "131": 20, "132": 20, "133": 21, "134": 21, "135": 21, "136": 21, "137": 21, "138": 21, "139": 21, "140": 21, "141": 21, "142": 21, "143": 21, "144": 21, "145": 21, "146": 21, "147": 21, "148": 21, "149": 21, "150": 21, "151": 21, "152": 21, "153": 21, "154": 21, "155": 21, "156": 21, "157": 22, "158": 22, "159": 22, "160": 22, "161": 22, "162": 22, "163": 22, "164": 22, "165": 22, "166": 22, "167": 22, "168": 22, "169": 22, "170": 22, "171": 22, "172": 22, "173": 22, "174": 22, "175": 22, "176": 22, "177": 22, "178": 22, "179": 22, "180": 22, "181": 23, "182": 23, "183": 23, "184": 23, "185": 23, "186": 23, "187": 23, "188": 23, "189": 23, "190": 23, "191": 23, "192": 23, "193": 23, "194": 23, "195": 23, "196": 23, "197": 23, "198": 23, "199": 23, "200": 23, "201": 23, "202": 23, "203": 23, "204": 23, "205": 23, "206": 23, "207": 23, "208": 23, "209": 23, "210": 23, "211": 23, "212": 23, "213": 23, "214": 23, "215": 23, "216": 23, "217": 23, "218": 23, "219": 23, "220": 23, "221": 23, "222": 23, "223": 23, "224": 23, "225": 23, "226": 23, "227": 23, "228": 23, "229": 23, "230": 23, "231": 23, "232": 23, "233": 23, "234": 23, "235": 23, "236": 23, "237": 23, "238": 23, "239": 23, "240": 23, "241": 23, "242": 23, "243": 23, "244": 23, "245": 23, "246": 23, "247": 23, "248": 23, "249": 23, "250": 23, "251": 23, "252": 23, "253": 23, "254": 23, "255": 23, "256": 23, "257": 23, "258": 23, "259": 23, "260": 23, "261": 23, "262": 23, "263": 23, "264": 23, "265": 23, "266": 23, "267": 23, "268": 23, "269": 23, "270": 23, "271": 23, "272": 23, "273": 23, "274": 23, "275": 23, "276": 23, "277": 23, "278": 23, "279": 23, "280": 23, "281": 23, "282": 23, "283": 23, "284": 23, "285": 23, "286": 23, "287": 23, "288": 23, "289": 24, "290": 24, "291": 24, "292": 24, "293": 24, "294": 24, "295": 24, "296": 24, "297": 24, "298": 24, "299": 24, "300": 24, "301": 24, "302": 24, "303": 24, "304": 24, "305": 24, "306": 24, "307": 24, "308": 24, "309": 24, "310": 24, "311": 24, "312": 24, "313": 24, "314": 24, "315": 24, "316": 24, "317": 24, "318": 24, "319": 24, "320": 24, "321": 24, "322": 24, "323": 24, "324": 24, "325": 24, "326": 24, "327": 24, "328": 24, "329": 24, "330": 24, "331": 24, "332": 24, "333": 24, "334": 24, "335": 24, "336": 24, "337": 24, "338": 24, "339": 24, "340": 24, "341": 24, "342": 24, "343": 24, "344": 24, "345": 24, "346": 24, "347": 24, "348": 24, "349": 24, "350": 24, "351": 24, "352": 24, "353": 24, "354": 24, "355": 24, "356": 24, "357": 24, "358": 24, "359": 24, "360": 24, "361": 24, "362": 24, "363": 24, "364": 24, "365": 24, "366": 24, "367": 24, "368": 24, "369": 24, "370": 24, "371": 24, "372": 24, "373": 24, "374": 24, "375": 24, "376": 24, "377": 24, "378": 24, "379": 24, "380": 24, "381": 24, "382": 24, "383": 24, "384": 24, "null": 0}, "instrument_code_map": {"piano": 1, "electric-piano": 2, "harpsichord": 3, "clavinet": 4, "celesta": 5, "glockenspiel": 6, "music-box": 7, "vibraphone": 8, "marimba": 9, "xylophone": 10, "tubular-bells": 11, "dulcimer": 12, "organ": 13, "church-organ": 14, "accordion": 15, "harmonica": 16, "bandoneon": 17, "nylon-string-guitar": 18, "steel-string-guitar": 19, "electric-guitar": 20, "bass": 21, "electric-bass": 22, "slap-bass": 23, "synth-bass": 24, "violin": 25, "viola": 26, "cello": 27, "contrabass": 28, "harp": 29, "timpani": 30, "strings": 31, "synth-strings": 32, "voices": 33, "orchestra-hit": 34, "trumpet": 35, "trombone": 36, "tuba": 37, "horn": 38, "brasses": 39, "synth-brasses": 40, "soprano-saxophone": 41, "alto-saxophone": 42, "tenor-saxophone": 43, "baritone-saxophone": 44, "oboe": 45, "english-horn": 46, "bassoon": 47, "clarinet": 48, "piccolo": 49, "flute": 50, "recorder": 51, "pan-flute": 52, "ocarina": 53, "lead": 54, "pad": 55, "sitar": 56, "banjo": 57, "shamisen": 58, "koto": 59, "kalimba": 60, "bag-pipe": 61, "shehnai": 62, "melodic-tom": 63, "synth-drums": 64, "null": 0}, "code_type_map": {"0": "start-of-song", "1": "instrument", "2": "start-of-notes", "3": "note", "4": "end-of-song"}, "code_beat_map": {"1": 0, "2": 1, "3": 2, "4": 3, "5": 4, "6": 5, "7": 6, "8": 7, "9": 8, "10": 9, "11": 10, "12": 11, "13": 12, "14": 13, "15": 14, "16": 15, "17": 16, "18": 17, "19": 18, "20": 19, "21": 20, "22": 21, "23": 22, "24": 23, "25": 24, "26": 25, "27": 26, "28": 27, "29": 28, "30": 29, "31": 30, "32": 31, "33": 32, "34": 33, "35": 34, "36": 35, "37": 36, "38": 37, "39": 38, "40": 39, "41": 40, "42": 41, "43": 42, "44": 43, "45": 44, "46": 45, "47": 46, "48": 47, "49": 48, "50": 49, "51": 50, "52": 51, "53": 52, "54": 53, "55": 54, "56": 55, "57": 56, "58": 57, "59": 58, "60": 59, "61": 60, "62": 61, "63": 62, "64": 63, "65": 64, "66": 65, "67": 66, "68": 67, "69": 68, "70": 69, "71": 70, "72": 71, "73": 72, "74": 73, "75": 74, "76": 75, "77": 76, "78": 77, "79": 78, "80": 79, "81": 80, "82": 81, "83": 82, "84": 83, "85": 84, "86": 85, "87": 86, "88": 87, "89": 88, "90": 89, "91": 90, "92": 91, "93": 92, "94": 93, "95": 94, "96": 95, "97": 96, "98": 97, "99": 98, "100": 99, "101": 100, "102": 101, "103": 102, "104": 103, "105": 104, "106": 105, "107": 106, "108": 107, "109": 108, "110": 109, "111": 110, "112": 111, "113": 112, "114": 113, "115": 114, "116": 115, "117": 116, "118": 117, "119": 118, "120": 119, "121": 120, "122": 121, "123": 122, "124": 123, "125": 124, "126": 125, "127": 126, "128": 127, "129": 128, "130": 129, "131": 130, "132": 131, "133": 132, "134": 133, "135": 134, "136": 135, "137": 136, "138": 137, "139": 138, "140": 139, "141": 140, "142": 141, "143": 142, "144": 143, "145": 144, "146": 145, "147": 146, "148": 147, "149": 148, "150": 149, "151": 150, "152": 151, "153": 152, "154": 153, "155": 154, "156": 155, "157": 156, "158": 157, "159": 158, "160": 159, "161": 160, "162": 161, "163": 162, "164": 163, "165": 164, "166": 165, "167": 166, "168": 167, "169": 168, "170": 169, "171": 170, "172": 171, "173": 172, "174": 173, "175": 174, "176": 175, "177": 176, "178": 177, "179": 178, "180": 179, "181": 180, "182": 181, "183": 182, "184": 183, "185": 184, "186": 185, "187": 186, "188": 187, "189": 188, "190": 189, "191": 190, "192": 191, "193": 192, "194": 193, "195": 194, "196": 195, "197": 196, "198": 197, "199": 198, "200": 199, "201": 200, "202": 201, "203": 202, "204": 203, "205": 204, "206": 205, "207": 206, "208": 207, "209": 208, "210": 209, "211": 210, "212": 211, "213": 212, "214": 213, "215": 214, "216": 215, "217": 216, "218": 217, "219": 218, "220": 219, "221": 220, "222": 221, "223": 222, "224": 223, "225": 224, "226": 225, "227": 226, "228": 227, "229": 228, "230": 229, "231": 230, "232": 231, "233": 232, "234": 233, "235": 234, "236": 235, "237": 236, "238": 237, "239": 238, "240": 239, "241": 240, "242": 241, "243": 242, "244": 243, "245": 244, "246": 245, "247": 246, "248": 247, "249": 248, "250": 249, "251": 250, "252": 251, "253": 252, "254": 253, "255": 254, "256": 255, "257": 256, "258": 257, "259": 258, "260": 259, "261": 260, "262": 261, "263": 262, "264": 263, "265": 264, "266": 265, "267": 266, "268": 267, "269": 268, "270": 269, "271": 270, "272": 271, "273": 272, "274": 273, "275": 274, "276": 275, "277": 276, "278": 277, "279": 278, "280": 279, "281": 280, "282": 281, "283": 282, "284": 283, "285": 284, "286": 285, "287": 286, "288": 287, "289": 288, "290": 289, "291": 290, "292": 291, "293": 292, "294": 293, "295": 294, "296": 295, "297": 296, "298": 297, "299": 298, "300": 299, "301": 300, "302": 301, "303": 302, "304": 303, "305": 304, "306": 305, "307": 306, "308": 307, "309": 308, "310": 309, "311": 310, "312": 311, "313": 312, "314": 313, "315": 314, "316": 315, "317": 316, "318": 317, "319": 318, "320": 319, "321": 320, "322": 321, "323": 322, "324": 323, "325": 324, "326": 325, "327": 326, "328": 327, "329": 328, "330": 329, "331": 330, "332": 331, "333": 332, "334": 333, "335": 334, "336": 335, "337": 336, "338": 337, "339": 338, "340": 339, "341": 340, "342": 341, "343": 342, "344": 343, "345": 344, "346": 345, "347": 346, "348": 347, "349": 348, "350": 349, "351": 350, "352": 351, "353": 352, "354": 353, "355": 354, "356": 355, "357": 356, "358": 357, "359": 358, "360": 359, "361": 360, "362": 361, "363": 362, "364": 363, "365": 364, "366": 365, "367": 366, "368": 367, "369": 368, "370": 369, "371": 370, "372": 371, "373": 372, "374": 373, "375": 374, "376": 375, "377": 376, "378": 377, "379": 378, "380": 379, "381": 380, "382": 381, "383": 382, "384": 383, "385": 384, "386": 385, "387": 386, "388": 387, "389": 388, "390": 389, "391": 390, "392": 391, "393": 392, "394": 393, "395": 394, "396": 395, "397": 396, "398": 397, "399": 398, "400": 399, "401": 400, "402": 401, "403": 402, "404": 403, "405": 404, "406": 405, "407": 406, "408": 407, "409": 408, "410": 409, "411": 410, "412": 411, "413": 412, "414": 413, "415": 414, "416": 415, "417": 416, "418": 417, "419": 418, "420": 419, "421": 420, "422": 421, "423": 422, "424": 423, "425": 424, "426": 425, "427": 426, "428": 427, "429": 428, "430": 429, "431": 430, "432": 431, "433": 432, "434": 433, "435": 434, "436": 435, "437": 436, "438": 437, "439": 438, "440": 439, "441": 440, "442": 441, "443": 442, "444": 443, "445": 444, "446": 445, "447": 446, "448": 447, "449": 448, "450": 449, "451": 450, "452": 451, "453": 452, "454": 453, "455": 454, "456": 455, "457": 456, "458": 457, "459": 458, "460": 459, "461": 460, "462": 461, "463": 462, "464": 463, "465": 464, "466": 465, "467": 466, "468": 467, "469": 468, "470": 469, "471": 470, "472": 471, "473": 472, "474": 473, "475": 474, "476": 475, "477": 476, "478": 477, "479": 478, "480": 479, "481": 480, "482": 481, "483": 482, "484": 483, "485": 484, "486": 485, "487": 486, "488": 487, "489": 488, "490": 489, "491": 490, "492": 491, "493": 492, "494": 493, "495": 494, "496": 495, "497": 496, "498": 497, "499": 498, "500": 499, "501": 500, "502": 501, "503": 502, "504": 503, "505": 504, "506": 505, "507": 506, "508": 507, "509": 508, "510": 509, "511": 510, "512": 511, "513": 512, "514": 513, "515": 514, "516": 515, "517": 516, "518": 517, "519": 518, "520": 519, "521": 520, "522": 521, "523": 522, "524": 523, "525": 524, "526": 525, "527": 526, "528": 527, "529": 528, "530": 529, "531": 530, "532": 531, "533": 532, "534": 533, "535": 534, "536": 535, "537": 536, "538": 537, "539": 538, "540": 539, "541": 540, "542": 541, "543": 542, "544": 543, "545": 544, "546": 545, "547": 546, "548": 547, "549": 548, "550": 549, "551": 550, "552": 551, "553": 552, "554": 553, "555": 554, "556": 555, "557": 556, "558": 557, "559": 558, "560": 559, "561": 560, "562": 561, "563": 562, "564": 563, "565": 564, "566": 565, "567": 566, "568": 567, "569": 568, "570": 569, "571": 570, "572": 571, "573": 572, "574": 573, "575": 574, "576": 575, "577": 576, "578": 577, "579": 578, "580": 579, "581": 580, "582": 581, "583": 582, "584": 583, "585": 584, "586": 585, "587": 586, "588": 587, "589": 588, "590": 589, "591": 590, "592": 591, "593": 592, "594": 593, "595": 594, "596": 595, "597": 596, "598": 597, "599": 598, "600": 599, "601": 600, "602": 601, "603": 602, "604": 603, "605": 604, "606": 605, "607": 606, "608": 607, "609": 608, "610": 609, "611": 610, "612": 611, "613": 612, "614": 613, "615": 614, "616": 615, "617": 616, "618": 617, "619": 618, "620": 619, "621": 620, "622": 621, "623": 622, "624": 623, "625": 624, "626": 625, "627": 626, "628": 627, "629": 628, "630": 629, "631": 630, "632": 631, "633": 632, "634": 633, "635": 634, "636": 635, "637": 636, "638": 637, "639": 638, "640": 639, "641": 640, "642": 641, "643": 642, "644": 643, "645": 644, "646": 645, "647": 646, "648": 647, "649": 648, "650": 649, "651": 650, "652": 651, "653": 652, "654": 653, "655": 654, "656": 655, "657": 656, "658": 657, "659": 658, "660": 659, "661": 660, "662": 661, "663": 662, "664": 663, "665": 664, "666": 665, "667": 666, "668": 667, "669": 668, "670": 669, "671": 670, "672": 671, "673": 672, "674": 673, "675": 674, "676": 675, "677": 676, "678": 677, "679": 678, "680": 679, "681": 680, "682": 681, "683": 682, "684": 683, "685": 684, "686": 685, "687": 686, "688": 687, "689": 688, "690": 689, "691": 690, "692": 691, "693": 692, "694": 693, "695": 694, "696": 695, "697": 696, "698": 697, "699": 698, "700": 699, "701": 700, "702": 701, "703": 702, "704": 703, "705": 704, "706": 705, "707": 706, "708": 707, "709": 708, "710": 709, "711": 710, "712": 711, "713": 712, "714": 713, "715": 714, "716": 715, "717": 716, "718": 717, "719": 718, "720": 719, "721": 720, "722": 721, "723": 722, "724": 723, "725": 724, "726": 725, "727": 726, "728": 727, "729": 728, "730": 729, "731": 730, "732": 731, "733": 732, "734": 733, "735": 734, "736": 735, "737": 736, "738": 737, "739": 738, "740": 739, "741": 740, "742": 741, "743": 742, "744": 743, "745": 744, "746": 745, "747": 746, "748": 747, "749": 748, "750": 749, "751": 750, "752": 751, "753": 752, "754": 753, "755": 754, "756": 755, "757": 756, "758": 757, "759": 758, "760": 759, "761": 760, "762": 761, "763": 762, "764": 763, "765": 764, "766": 765, "767": 766, "768": 767, "769": 768, "770": 769, "771": 770, "772": 771, "773": 772, "774": 773, "775": 774, "776": 775, "777": 776, "778": 777, "779": 778, "780": 779, "781": 780, "782": 781, "783": 782, "784": 783, "785": 784, "786": 785, "787": 786, "788": 787, "789": 788, "790": 789, "791": 790, "792": 791, "793": 792, "794": 793, "795": 794, "796": 795, "797": 796, "798": 797, "799": 798, "800": 799, "801": 800, "802": 801, "803": 802, "804": 803, "805": 804, "806": 805, "807": 806, "808": 807, "809": 808, "810": 809, "811": 810, "812": 811, "813": 812, "814": 813, "815": 814, "816": 815, "817": 816, "818": 817, "819": 818, "820": 819, "821": 820, "822": 821, "823": 822, "824": 823, "825": 824, "826": 825, "827": 826, "828": 827, "829": 828, "830": 829, "831": 830, "832": 831, "833": 832, "834": 833, "835": 834, "836": 835, "837": 836, "838": 837, "839": 838, "840": 839, "841": 840, "842": 841, "843": 842, "844": 843, "845": 844, "846": 845, "847": 846, "848": 847, "849": 848, "850": 849, "851": 850, "852": 851, "853": 852, "854": 853, "855": 854, "856": 855, "857": 856, "858": 857, "859": 858, "860": 859, "861": 860, "862": 861, "863": 862, "864": 863, "865": 864, "866": 865, "867": 866, "868": 867, "869": 868, "870": 869, "871": 870, "872": 871, "873": 872, "874": 873, "875": 874, "876": 875, "877": 876, "878": 877, "879": 878, "880": 879, "881": 880, "882": 881, "883": 882, "884": 883, "885": 884, "886": 885, "887": 886, "888": 887, "889": 888, "890": 889, "891": 890, "892": 891, "893": 892, "894": 893, "895": 894, "896": 895, "897": 896, "898": 897, "899": 898, "900": 899, "901": 900, "902": 901, "903": 902, "904": 903, "905": 904, "906": 905, "907": 906, "908": 907, "909": 908, "910": 909, "911": 910, "912": 911, "913": 912, "914": 913, "915": 914, "916": 915, "917": 916, "918": 917, "919": 918, "920": 919, "921": 920, "922": 921, "923": 922, "924": 923, "925": 924, "926": 925, "927": 926, "928": 927, "929": 928, "930": 929, "931": 930, "932": 931, "933": 932, "934": 933, "935": 934, "936": 935, "937": 936, "938": 937, "939": 938, "940": 939, "941": 940, "942": 941, "943": 942, "944": 943, "945": 944, "946": 945, "947": 946, "948": 947, "949": 948, "950": 949, "951": 950, "952": 951, "953": 952, "954": 953, "955": 954, "956": 955, "957": 956, "958": 957, "959": 958, "960": 959, "961": 960, "962": 961, "963": 962, "964": 963, "965": 964, "966": 965, "967": 966, "968": 967, "969": 968, "970": 969, "971": 970, "972": 971, "973": 972, "974": 973, "975": 974, "976": 975, "977": 976, "978": 977, "979": 978, "980": 979, "981": 980, "982": 981, "983": 982, "984": 983, "985": 984, "986": 985, "987": 986, "988": 987, "989": 988, "990": 989, "991": 990, "992": 991, "993": 992, "994": 993, "995": 994, "996": 995, "997": 996, "998": 997, "999": 998, "1000": 999, "1001": 1000, "1002": 1001, "1003": 1002, "1004": 1003, "1005": 1004, "1006": 1005, "1007": 1006, "1008": 1007, "1009": 1008, "1010": 1009, "1011": 1010, "1012": 1011, "1013": 1012, "1014": 1013, "1015": 1014, "1016": 1015, "1017": 1016, "1018": 1017, "1019": 1018, "1020": 1019, "1021": 1020, "1022": 1021, "1023": 1022, "1024": 1023, "1025": 1024, "0": null}, "code_position_map": {"1": 0, "2": 1, "3": 2, "4": 3, "5": 4, "6": 5, "7": 6, "8": 7, "9": 8, "10": 9, "11": 10, "12": 11, "13": 12, "14": 13, "15": 14, "16": 15, "17": 16, "18": 17, "19": 18, "20": 19, "21": 20, "22": 21, "23": 22, "24": 23, "0": null}, "code_pitch_map": {"1": 0, "2": 1, "3": 2, "4": 3, "5": 4, "6": 5, "7": 6, "8": 7, "9": 8, "10": 9, "11": 10, "12": 11, "13": 12, "14": 13, "15": 14, "16": 15, "17": 16, "18": 17, "19": 18, "20": 19, "21": 20, "22": 21, "23": 22, "24": 23, "25": 24, "26": 25, "27": 26, "28": 27, "29": 28, "30": 29, "31": 30, "32": 31, "33": 32, "34": 33, "35": 34, "36": 35, "37": 36, "38": 37, "39": 38, "40": 39, "41": 40, "42": 41, "43": 42, "44": 43, "45": 44, "46": 45, "47": 46, "48": 47, "49": 48, "50": 49, "51": 50, "52": 51, "53": 52, "54": 53, "55": 54, "56": 55, "57": 56, "58": 57, "59": 58, "60": 59, "61": 60, "62": 61, "63": 62, "64": 63, "65": 64, "66": 65, "67": 66, "68": 67, "69": 68, "70": 69, "71": 70, "72": 71, "73": 72, "74": 73, "75": 74, "76": 75, "77": 76, "78": 77, "79": 78, "80": 79, "81": 80, "82": 81, "83": 82, "84": 83, "85": 84, "86": 85, "87": 86, "88": 87, "89": 88, "90": 89, "91": 90, "92": 91, "93": 92, "94": 93, "95": 94, "96": 95, "97": 96, "98": 97, "99": 98, "100": 99, "101": 100, "102": 101, "103": 102, "104": 103, "105": 104, "106": 105, "107": 106, "108": 107, "109": 108, "110": 109, "111": 110, "112": 111, "113": 112, "114": 113, "115": 114, "116": 115, "117": 116, "118": 117, "119": 118, "120": 119, "121": 120, "122": 121, "123": 122, "124": 123, "125": 124, "126": 125, "127": 126, "128": 127, "0": null}, "code_duration_map": {"1": 1, "2": 2, "3": 3, "4": 12, "5": 15, "6": 16, "7": 18, "8": 20, "9": 21, "10": 24, "11": 30, "12": 36, "13": 40, "14": 42, "15": 48, "16": 60, "17": 72, "18": 84, "19": 96, "20": 120, "21": 144, "22": 168, "23": 192, "24": 384}, "code_instrument_map": {"1": "piano", "2": "electric-piano", "3": "harpsichord", "4": "clavinet", "5": "celesta", "6": "glockenspiel", "7": "music-box", "8": "vibraphone", "9": "marimba", "10": "xylophone", "11": "tubular-bells", "12": "dulcimer", "13": "organ", "14": "church-organ", "15": "accordion", "16": "harmonica", "17": "bandoneon", "18": "nylon-string-guitar", "19": "steel-string-guitar", "20": "electric-guitar", "21": "bass", "22": "electric-bass", "23": "slap-bass", "24": "synth-bass", "25": "violin", "26": "viola", "27": "cello", "28": "contrabass", "29": "harp", "30": "timpani", "31": "strings", "32": "synth-strings", "33": "voices", "34": "orchestra-hit", "35": "trumpet", "36": "trombone", "37": "tuba", "38": "horn", "39": "brasses", "40": "synth-brasses", "41": "soprano-saxophone", "42": "alto-saxophone", "43": "tenor-saxophone", "44": "baritone-saxophone", "45": "oboe", "46": "english-horn", "47": "bassoon", "48": "clarinet", "49": "piccolo", "50": "flute", "51": "recorder", "52": "pan-flute", "53": "ocarina", "54": "lead", "55": "pad", "56": "sitar", "57": "banjo", "58": "shamisen", "59": "koto", "60": "kalimba", "61": "bag-pipe", "62": "shehnai", "63": "melodic-tom", "64": "synth-drums", "0": null}, "program_instrument_map": {"0": "piano", "1": "piano", "2": "piano", "3": "piano", "4": "electric-piano", "5": "electric-piano", "6": "harpsichord", "7": "clavinet", "8": "celesta", "9": "glockenspiel", "10": "music-box", "11": "vibraphone", "12": "marimba", "13": "xylophone", "14": "tubular-bells", "15": "dulcimer", "16": "organ", "17": "organ", "18": "organ", "19": "church-organ", "20": "organ", "21": "accordion", "22": "harmonica", "23": "bandoneon", "24": "nylon-string-guitar", "25": "steel-string-guitar", "26": "electric-guitar", "27": "electric-guitar", "28": "electric-guitar", "29": "electric-guitar", "30": "electric-guitar", "31": "electric-guitar", "32": "bass", "33": "electric-bass", "34": "electric-bass", "35": "electric-bass", "36": "slap-bass", "37": "slap-bass", "38": "synth-bass", "39": "synth-bass", "40": "violin", "41": "viola", "42": "cello", "43": "contrabass", "44": "strings", "45": "strings", "46": "harp", "47": "timpani", "48": "strings", "49": "strings", "50": "synth-strings", "51": "synth-strings", "52": "voices", "53": "voices", "54": "voices", "55": "orchestra-hit", "56": "trumpet", "57": "trombone", "58": "tuba", "59": "trumpet", "60": "horn", "61": "brasses", "62": "synth-brasses", "63": "synth-brasses", "64": "soprano-saxophone", "65": "alto-saxophone", "66": "tenor-saxophone", "67": "baritone-saxophone", "68": "oboe", "69": "english-horn", "70": "bassoon", "71": "clarinet", "72": "piccolo", "73": "flute", "74": "recorder", "75": "pan-flute", "76": null, "77": null, "78": null, "79": "ocarina", "80": "lead", "81": "lead", "82": "lead", "83": "lead", "84": "lead", "85": "lead", "86": "lead", "87": "lead", "88": "pad", "89": "pad", "90": "pad", "91": "pad", "92": "pad", "93": "pad", "94": "pad", "95": "pad", "96": null, "97": null, "98": null, "99": null, "100": null, "101": null, "102": null, "103": null, "104": "sitar", "105": "banjo", "106": "shamisen", "107": "koto", "108": "kalimba", "109": "bag-pipe", "110": "violin", "111": "shehnai", "112": null, "113": null, "114": null, "115": null, "116": null, "117": "melodic-tom", "118": "synth-drums", "119": "synth-drums", "120": null, "121": null, "122": null, "123": null, "124": null, "125": null, "126": null, "127": null, "128": null}, "instrument_program_map": {"piano": 0, "electric-piano": 4, "harpsichord": 6, "clavinet": 7, "celesta": 8, "glockenspiel": 9, "music-box": 10, "vibraphone": 11, "marimba": 12, "xylophone": 13, "tubular-bells": 14, "dulcimer": 15, "organ": 16, "church-organ": 19, "accordion": 21, "harmonica": 22, "bandoneon": 23, "nylon-string-guitar": 24, "steel-string-guitar": 25, "electric-guitar": 26, "bass": 32, "electric-bass": 33, "slap-bass": 36, "synth-bass": 38, "violin": 40, "viola": 41, "cello": 42, "contrabass": 43, "harp": 46, "timpani": 47, "strings": 49, "synth-strings": 50, "voices": 52, "orchestra-hit": 55, "trumpet": 56, "trombone": 57, "tuba": 58, "horn": 60, "brasses": 61, "synth-brasses": 62, "soprano-saxophone": 64, "alto-saxophone": 65, "tenor-saxophone": 66, "baritone-saxophone": 67, "oboe": 68, "english-horn": 69, "bassoon": 70, "clarinet": 71, "piccolo": 72, "flute": 73, "recorder": 74, "pan-flute": 75, "ocarina": 79, "lead": 80, "pad": 88, "sitar": 104, "banjo": 105, "shamisen": 106, "koto": 107, "kalimba": 108, "bag-pipe": 109, "shehnai": 111, "melodic-tom": 117, "synth-drums": 118}}
|
mmt/music_x_transformers.py
ADDED
|
@@ -0,0 +1,579 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import logging
|
| 3 |
+
import pathlib
|
| 4 |
+
import pprint
|
| 5 |
+
import sys
|
| 6 |
+
|
| 7 |
+
import torch
|
| 8 |
+
import torch.nn.functional as F
|
| 9 |
+
from einops import repeat
|
| 10 |
+
from torch import nn
|
| 11 |
+
from x_transformers.autoregressive_wrapper import (
|
| 12 |
+
ENTMAX_ALPHA,
|
| 13 |
+
entmax,
|
| 14 |
+
exists,
|
| 15 |
+
top_a,
|
| 16 |
+
top_k,
|
| 17 |
+
top_p,
|
| 18 |
+
)
|
| 19 |
+
from x_transformers.x_transformers import (
|
| 20 |
+
AbsolutePositionalEmbedding,
|
| 21 |
+
AttentionLayers,
|
| 22 |
+
Decoder,
|
| 23 |
+
TokenEmbedding,
|
| 24 |
+
always,
|
| 25 |
+
default,
|
| 26 |
+
exists,
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
import representation
|
| 30 |
+
import utils
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
@utils.resolve_paths
|
| 34 |
+
def parse_args(args=None, namespace=None):
|
| 35 |
+
"""Parse command-line arguments."""
|
| 36 |
+
parser = argparse.ArgumentParser()
|
| 37 |
+
parser.add_argument(
|
| 38 |
+
"-d",
|
| 39 |
+
"--dataset",
|
| 40 |
+
choices=("sod", "lmd"),
|
| 41 |
+
required=True,
|
| 42 |
+
help="dataset key",
|
| 43 |
+
)
|
| 44 |
+
parser.add_argument(
|
| 45 |
+
"-i", "--in_dir", type=pathlib.Path, help="input data directory"
|
| 46 |
+
)
|
| 47 |
+
parser.add_argument(
|
| 48 |
+
"-q", "--quiet", action="store_true", help="show warnings only"
|
| 49 |
+
)
|
| 50 |
+
return parser.parse_args(args=args, namespace=namespace)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class MusicTransformerWrapper(nn.Module):
|
| 54 |
+
def __init__(
|
| 55 |
+
self,
|
| 56 |
+
*,
|
| 57 |
+
encoding,
|
| 58 |
+
max_seq_len,
|
| 59 |
+
attn_layers,
|
| 60 |
+
emb_dim=None,
|
| 61 |
+
max_beat=None,
|
| 62 |
+
max_mem_len=0.0,
|
| 63 |
+
shift_mem_down=0,
|
| 64 |
+
emb_dropout=0.0,
|
| 65 |
+
num_memory_tokens=None,
|
| 66 |
+
tie_embedding=False,
|
| 67 |
+
use_abs_pos_emb=True,
|
| 68 |
+
l2norm_embed=False,
|
| 69 |
+
):
|
| 70 |
+
super().__init__()
|
| 71 |
+
assert isinstance(
|
| 72 |
+
attn_layers, AttentionLayers
|
| 73 |
+
), "attention layers must be one of Encoder or Decoder"
|
| 74 |
+
|
| 75 |
+
dim = attn_layers.dim
|
| 76 |
+
emb_dim = default(emb_dim, dim)
|
| 77 |
+
|
| 78 |
+
self.max_seq_len = max_seq_len
|
| 79 |
+
self.max_mem_len = max_mem_len
|
| 80 |
+
self.shift_mem_down = shift_mem_down
|
| 81 |
+
|
| 82 |
+
n_tokens = encoding["n_tokens"]
|
| 83 |
+
if max_beat is not None:
|
| 84 |
+
beat_dim = encoding["dimensions"].index("beat")
|
| 85 |
+
n_tokens[beat_dim] = max_beat + 1
|
| 86 |
+
|
| 87 |
+
self.l2norm_embed = l2norm_embed
|
| 88 |
+
self.token_emb = nn.ModuleList(
|
| 89 |
+
[
|
| 90 |
+
TokenEmbedding(emb_dim, n, l2norm_embed=l2norm_embed)
|
| 91 |
+
for n in n_tokens
|
| 92 |
+
]
|
| 93 |
+
)
|
| 94 |
+
self.pos_emb = (
|
| 95 |
+
AbsolutePositionalEmbedding(
|
| 96 |
+
emb_dim, max_seq_len, l2norm_embed=l2norm_embed
|
| 97 |
+
)
|
| 98 |
+
if (use_abs_pos_emb and not attn_layers.has_pos_emb)
|
| 99 |
+
else always(0)
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
self.emb_dropout = nn.Dropout(emb_dropout)
|
| 103 |
+
|
| 104 |
+
self.project_emb = (
|
| 105 |
+
nn.Linear(emb_dim, dim) if emb_dim != dim else nn.Identity()
|
| 106 |
+
)
|
| 107 |
+
self.attn_layers = attn_layers
|
| 108 |
+
self.norm = nn.LayerNorm(dim)
|
| 109 |
+
|
| 110 |
+
self.init_()
|
| 111 |
+
|
| 112 |
+
self.to_logits = (
|
| 113 |
+
nn.ModuleList([nn.Linear(dim, n) for n in n_tokens])
|
| 114 |
+
if not tie_embedding
|
| 115 |
+
else [lambda t: t @ emb.weight.t() for emb in self.token_emb]
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
# memory tokens (like [cls]) from Memory Transformers paper
|
| 119 |
+
num_memory_tokens = default(num_memory_tokens, 0)
|
| 120 |
+
self.num_memory_tokens = num_memory_tokens
|
| 121 |
+
if num_memory_tokens > 0:
|
| 122 |
+
self.memory_tokens = nn.Parameter(
|
| 123 |
+
torch.randn(num_memory_tokens, dim)
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
def init_(self):
|
| 127 |
+
if self.l2norm_embed:
|
| 128 |
+
for emb in self.token_emb:
|
| 129 |
+
nn.init.normal_(emb.emb.weight, std=1e-5)
|
| 130 |
+
nn.init.normal_(self.pos_emb.emb.weight, std=1e-5)
|
| 131 |
+
return
|
| 132 |
+
|
| 133 |
+
for emb in self.token_emb:
|
| 134 |
+
nn.init.kaiming_normal_(emb.emb.weight)
|
| 135 |
+
|
| 136 |
+
def forward(
|
| 137 |
+
self,
|
| 138 |
+
x, # shape : (b, n , d)
|
| 139 |
+
return_embeddings=False,
|
| 140 |
+
mask=None,
|
| 141 |
+
return_mems=False,
|
| 142 |
+
return_attn=False,
|
| 143 |
+
mems=None,
|
| 144 |
+
**kwargs,
|
| 145 |
+
):
|
| 146 |
+
b, _, _ = x.shape
|
| 147 |
+
num_mem = self.num_memory_tokens
|
| 148 |
+
|
| 149 |
+
x = sum(
|
| 150 |
+
emb(x[..., i]) for i, emb in enumerate(self.token_emb)
|
| 151 |
+
) + self.pos_emb(x)
|
| 152 |
+
x = self.emb_dropout(x)
|
| 153 |
+
|
| 154 |
+
x = self.project_emb(x)
|
| 155 |
+
|
| 156 |
+
if num_mem > 0:
|
| 157 |
+
mem = repeat(self.memory_tokens, "n d -> b n d", b=b)
|
| 158 |
+
x = torch.cat((mem, x), dim=1)
|
| 159 |
+
|
| 160 |
+
# auto-handle masking after appending memory tokens
|
| 161 |
+
if exists(mask):
|
| 162 |
+
mask = F.pad(mask, (num_mem, 0), value=True)
|
| 163 |
+
|
| 164 |
+
if self.shift_mem_down and exists(mems):
|
| 165 |
+
mems_l, mems_r = (
|
| 166 |
+
mems[: self.shift_mem_down],
|
| 167 |
+
mems[self.shift_mem_down :],
|
| 168 |
+
)
|
| 169 |
+
mems = [*mems_r, *mems_l]
|
| 170 |
+
|
| 171 |
+
x, intermediates = self.attn_layers(
|
| 172 |
+
x, mask=mask, mems=mems, return_hiddens=True, **kwargs
|
| 173 |
+
)
|
| 174 |
+
x = self.norm(x)
|
| 175 |
+
|
| 176 |
+
mem, x = x[:, :num_mem], x[:, num_mem:]
|
| 177 |
+
|
| 178 |
+
out = (
|
| 179 |
+
[to_logit(x) for to_logit in self.to_logits]
|
| 180 |
+
if not return_embeddings
|
| 181 |
+
else x
|
| 182 |
+
)
|
| 183 |
+
|
| 184 |
+
if return_mems:
|
| 185 |
+
hiddens = intermediates.hiddens
|
| 186 |
+
new_mems = (
|
| 187 |
+
list(
|
| 188 |
+
map(
|
| 189 |
+
lambda pair: torch.cat(pair, dim=-2),
|
| 190 |
+
zip(mems, hiddens),
|
| 191 |
+
)
|
| 192 |
+
)
|
| 193 |
+
if exists(mems)
|
| 194 |
+
else hiddens
|
| 195 |
+
)
|
| 196 |
+
new_mems = list(
|
| 197 |
+
map(
|
| 198 |
+
lambda t: t[..., -self.max_mem_len :, :].detach(), new_mems
|
| 199 |
+
)
|
| 200 |
+
)
|
| 201 |
+
return out, new_mems
|
| 202 |
+
|
| 203 |
+
if return_attn:
|
| 204 |
+
attn_maps = list(
|
| 205 |
+
map(
|
| 206 |
+
lambda t: t.post_softmax_attn,
|
| 207 |
+
intermediates.attn_intermediates,
|
| 208 |
+
)
|
| 209 |
+
)
|
| 210 |
+
return out, attn_maps
|
| 211 |
+
|
| 212 |
+
return out
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
def sample(logits, kind, threshold, temperature, min_p_pow, min_p_ratio):
|
| 216 |
+
"""Sample from the logits with a specific sampling strategy."""
|
| 217 |
+
if kind == "top_k":
|
| 218 |
+
probs = F.softmax(top_k(logits, thres=threshold) / temperature, dim=-1)
|
| 219 |
+
elif kind == "top_p":
|
| 220 |
+
probs = F.softmax(top_p(logits, thres=threshold) / temperature, dim=-1)
|
| 221 |
+
elif kind == "top_a":
|
| 222 |
+
probs = F.softmax(
|
| 223 |
+
top_a(logits, min_p_pow=min_p_pow, min_p_ratio=min_p_ratio)
|
| 224 |
+
/ temperature,
|
| 225 |
+
dim=-1,
|
| 226 |
+
)
|
| 227 |
+
elif kind == "entmax":
|
| 228 |
+
probs = entmax(logits / temperature, alpha=ENTMAX_ALPHA, dim=-1)
|
| 229 |
+
else:
|
| 230 |
+
raise ValueError(f"Unknown sampling strategy: {kind}")
|
| 231 |
+
|
| 232 |
+
return torch.multinomial(probs, 1)
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
class MusicAutoregressiveWrapper(nn.Module):
|
| 236 |
+
def __init__(self, net, encoding, ignore_index=-100, pad_value=0):
|
| 237 |
+
super().__init__()
|
| 238 |
+
self.pad_value = pad_value
|
| 239 |
+
self.ignore_index = ignore_index
|
| 240 |
+
|
| 241 |
+
self.net = net
|
| 242 |
+
self.max_seq_len = net.max_seq_len
|
| 243 |
+
|
| 244 |
+
# Get the type codes
|
| 245 |
+
self.sos_type_code = encoding["type_code_map"]["start-of-song"]
|
| 246 |
+
self.eos_type_code = encoding["type_code_map"]["end-of-song"]
|
| 247 |
+
self.son_type_code = encoding["type_code_map"]["start-of-notes"]
|
| 248 |
+
self.instrument_type_code = encoding["type_code_map"]["instrument"]
|
| 249 |
+
self.note_type_code = encoding["type_code_map"]["note"]
|
| 250 |
+
|
| 251 |
+
# Get the dimension indices
|
| 252 |
+
self.dimensions = {
|
| 253 |
+
key: encoding["dimensions"].index(key)
|
| 254 |
+
for key in (
|
| 255 |
+
"type",
|
| 256 |
+
"beat",
|
| 257 |
+
"position",
|
| 258 |
+
"pitch",
|
| 259 |
+
"duration",
|
| 260 |
+
"instrument",
|
| 261 |
+
)
|
| 262 |
+
}
|
| 263 |
+
assert self.dimensions["type"] == 0
|
| 264 |
+
|
| 265 |
+
@torch.no_grad()
|
| 266 |
+
def generate(
|
| 267 |
+
self,
|
| 268 |
+
start_tokens, # shape : (b, n, d)
|
| 269 |
+
seq_len,
|
| 270 |
+
eos_token=None,
|
| 271 |
+
temperature=1.0, # int or list of int
|
| 272 |
+
filter_logits_fn="top_k", # str or list of str
|
| 273 |
+
filter_thres=0.9, # int or list of int
|
| 274 |
+
min_p_pow=2.0,
|
| 275 |
+
min_p_ratio=0.02,
|
| 276 |
+
monotonicity_dim=None,
|
| 277 |
+
return_attn=False,
|
| 278 |
+
**kwargs,
|
| 279 |
+
):
|
| 280 |
+
_, t, dim = start_tokens.shape
|
| 281 |
+
|
| 282 |
+
if isinstance(temperature, (float, int)):
|
| 283 |
+
temperature = [temperature] * dim
|
| 284 |
+
elif len(temperature) == 1:
|
| 285 |
+
temperature = temperature * dim
|
| 286 |
+
else:
|
| 287 |
+
assert (
|
| 288 |
+
len(temperature) == dim
|
| 289 |
+
), f"`temperature` must be of length {dim}"
|
| 290 |
+
|
| 291 |
+
if isinstance(filter_logits_fn, str):
|
| 292 |
+
filter_logits_fn = [filter_logits_fn] * dim
|
| 293 |
+
elif len(filter_logits_fn) == 1:
|
| 294 |
+
filter_logits_fn = filter_logits_fn * dim
|
| 295 |
+
else:
|
| 296 |
+
assert (
|
| 297 |
+
len(filter_logits_fn) == dim
|
| 298 |
+
), f"`filter_logits_fn` must be of length {dim}"
|
| 299 |
+
|
| 300 |
+
if isinstance(filter_thres, (float, int)):
|
| 301 |
+
filter_thres = [filter_thres] * dim
|
| 302 |
+
elif len(filter_thres) == 1:
|
| 303 |
+
filter_thres = filter_thres * dim
|
| 304 |
+
else:
|
| 305 |
+
assert (
|
| 306 |
+
len(filter_thres) == dim
|
| 307 |
+
), f"`filter_thres` must be of length {dim}"
|
| 308 |
+
|
| 309 |
+
if isinstance(monotonicity_dim, str):
|
| 310 |
+
monotonicity_dim = [self.dimensions[monotonicity_dim]]
|
| 311 |
+
else:
|
| 312 |
+
monotonicity_dim = [self.dimensions[d] for d in monotonicity_dim]
|
| 313 |
+
|
| 314 |
+
was_training = self.net.training
|
| 315 |
+
num_dims = len(start_tokens.shape)
|
| 316 |
+
|
| 317 |
+
if num_dims == 2:
|
| 318 |
+
start_tokens = start_tokens[None, :, :]
|
| 319 |
+
|
| 320 |
+
self.net.eval()
|
| 321 |
+
out = start_tokens
|
| 322 |
+
mask = kwargs.pop("mask", None)
|
| 323 |
+
|
| 324 |
+
if mask is None:
|
| 325 |
+
mask = torch.ones(
|
| 326 |
+
(out.shape[0], out.shape[1]),
|
| 327 |
+
dtype=torch.bool,
|
| 328 |
+
device=out.device,
|
| 329 |
+
)
|
| 330 |
+
|
| 331 |
+
if monotonicity_dim is not None:
|
| 332 |
+
current_values = {
|
| 333 |
+
d: torch.max(start_tokens[:, :, d], 1)[0]
|
| 334 |
+
for d in monotonicity_dim
|
| 335 |
+
}
|
| 336 |
+
else:
|
| 337 |
+
current_values = None
|
| 338 |
+
|
| 339 |
+
instrument_dim = self.dimensions["instrument"]
|
| 340 |
+
type_dim = self.dimensions["type"]
|
| 341 |
+
for _ in range(seq_len):
|
| 342 |
+
x = out[:, -self.max_seq_len :]
|
| 343 |
+
mask = mask[:, -self.max_seq_len :]
|
| 344 |
+
|
| 345 |
+
if return_attn:
|
| 346 |
+
logits, attn = self.net(
|
| 347 |
+
x, mask=mask, return_attn=True, **kwargs
|
| 348 |
+
)
|
| 349 |
+
logits = [l[:, -1, :] for l in logits]
|
| 350 |
+
else:
|
| 351 |
+
logits = [
|
| 352 |
+
l[:, -1, :] for l in self.net(x, mask=mask, **kwargs)
|
| 353 |
+
]
|
| 354 |
+
|
| 355 |
+
# Enforce monotonicity
|
| 356 |
+
if monotonicity_dim is not None and 0 in monotonicity_dim:
|
| 357 |
+
for i, v in enumerate(current_values[0]):
|
| 358 |
+
logits[0][i, :v] = -float("inf")
|
| 359 |
+
|
| 360 |
+
# Filter out sos token
|
| 361 |
+
logits[0][type_dim, 0] = -float("inf")
|
| 362 |
+
|
| 363 |
+
# Sample from the logits
|
| 364 |
+
sample_type = sample(
|
| 365 |
+
logits[0],
|
| 366 |
+
filter_logits_fn[0],
|
| 367 |
+
filter_thres[0],
|
| 368 |
+
temperature[0],
|
| 369 |
+
min_p_pow,
|
| 370 |
+
min_p_ratio,
|
| 371 |
+
)
|
| 372 |
+
|
| 373 |
+
# Update current values
|
| 374 |
+
if monotonicity_dim is not None and 0 in monotonicity_dim:
|
| 375 |
+
current_values[0] = torch.maximum(
|
| 376 |
+
current_values[0], sample_type.reshape(-1)
|
| 377 |
+
)
|
| 378 |
+
|
| 379 |
+
# Iterate after each sample
|
| 380 |
+
samples = [[s_type] for s_type in sample_type]
|
| 381 |
+
for idx, s_type in enumerate(sample_type):
|
| 382 |
+
# A start-of-song, end-of-song or start-of-notes code
|
| 383 |
+
if s_type in (
|
| 384 |
+
self.sos_type_code,
|
| 385 |
+
self.eos_type_code,
|
| 386 |
+
self.son_type_code,
|
| 387 |
+
):
|
| 388 |
+
samples[idx] += [torch.zeros_like(s_type)] * (
|
| 389 |
+
len(logits) - 1
|
| 390 |
+
)
|
| 391 |
+
# An instrument code
|
| 392 |
+
elif s_type == self.instrument_type_code:
|
| 393 |
+
samples[idx] += [torch.zeros_like(s_type)] * (
|
| 394 |
+
len(logits) - 2
|
| 395 |
+
)
|
| 396 |
+
logits[instrument_dim][:, 0] = -float("inf") # avoid none
|
| 397 |
+
sampled = sample(
|
| 398 |
+
logits[instrument_dim][idx : idx + 1],
|
| 399 |
+
filter_logits_fn[instrument_dim],
|
| 400 |
+
filter_thres[instrument_dim],
|
| 401 |
+
temperature[instrument_dim],
|
| 402 |
+
min_p_pow,
|
| 403 |
+
min_p_ratio,
|
| 404 |
+
)[0]
|
| 405 |
+
samples[idx].append(sampled)
|
| 406 |
+
# A note code
|
| 407 |
+
elif s_type == self.note_type_code:
|
| 408 |
+
for d in range(1, dim):
|
| 409 |
+
# Enforce monotonicity
|
| 410 |
+
if (
|
| 411 |
+
monotonicity_dim is not None
|
| 412 |
+
and d in monotonicity_dim
|
| 413 |
+
):
|
| 414 |
+
logits[d][idx, : current_values[d][idx]] = -float(
|
| 415 |
+
"inf"
|
| 416 |
+
)
|
| 417 |
+
|
| 418 |
+
# Sample from the logits
|
| 419 |
+
logits[d][:, 0] = -float("inf") # avoid none
|
| 420 |
+
sampled = sample(
|
| 421 |
+
logits[d][idx : idx + 1],
|
| 422 |
+
filter_logits_fn[d],
|
| 423 |
+
filter_thres[d],
|
| 424 |
+
temperature[d],
|
| 425 |
+
min_p_pow,
|
| 426 |
+
min_p_ratio,
|
| 427 |
+
)[0]
|
| 428 |
+
samples[idx].append(sampled)
|
| 429 |
+
|
| 430 |
+
# Update current values
|
| 431 |
+
if (
|
| 432 |
+
monotonicity_dim is not None
|
| 433 |
+
and d in monotonicity_dim
|
| 434 |
+
):
|
| 435 |
+
current_values[d][idx] = torch.max(
|
| 436 |
+
current_values[d][idx], sampled
|
| 437 |
+
)[0]
|
| 438 |
+
else:
|
| 439 |
+
raise ValueError(f"Unknown event type code: {s_type}")
|
| 440 |
+
|
| 441 |
+
stacked = torch.stack(
|
| 442 |
+
[torch.cat(s).expand(1, -1) for s in samples], 0
|
| 443 |
+
)
|
| 444 |
+
out = torch.cat((out, stacked), dim=1)
|
| 445 |
+
mask = F.pad(mask, (0, 1), value=True)
|
| 446 |
+
|
| 447 |
+
if exists(eos_token):
|
| 448 |
+
is_eos_tokens = out[..., 0] == eos_token
|
| 449 |
+
|
| 450 |
+
# Mask out everything after the eos tokens
|
| 451 |
+
if is_eos_tokens.any(dim=1).all():
|
| 452 |
+
for i, is_eos_token in enumerate(is_eos_tokens):
|
| 453 |
+
idx = torch.argmax(is_eos_token.byte())
|
| 454 |
+
out[i, idx + 1 :] = self.pad_value
|
| 455 |
+
break
|
| 456 |
+
|
| 457 |
+
out = out[:, t:]
|
| 458 |
+
|
| 459 |
+
if num_dims == 1:
|
| 460 |
+
out = out.squeeze(0)
|
| 461 |
+
|
| 462 |
+
self.net.train(was_training)
|
| 463 |
+
|
| 464 |
+
if return_attn:
|
| 465 |
+
return out, attn
|
| 466 |
+
|
| 467 |
+
return out
|
| 468 |
+
|
| 469 |
+
def forward(self, x, return_list=False, **kwargs):
|
| 470 |
+
xi = x[:, :-1]
|
| 471 |
+
xo = x[:, 1:]
|
| 472 |
+
|
| 473 |
+
# help auto-solve a frequent area of confusion around input masks in auto-regressive
|
| 474 |
+
# if user supplies a mask that is only off by one from the source sequence, resolve it for them
|
| 475 |
+
mask = kwargs.get("mask", None)
|
| 476 |
+
if mask is not None and mask.shape[1] == x.shape[1]:
|
| 477 |
+
mask = mask[:, :-1]
|
| 478 |
+
kwargs["mask"] = mask
|
| 479 |
+
|
| 480 |
+
out = self.net(xi, **kwargs)
|
| 481 |
+
losses = [
|
| 482 |
+
F.cross_entropy(
|
| 483 |
+
out[i].transpose(1, 2),
|
| 484 |
+
xo[..., i],
|
| 485 |
+
ignore_index=self.ignore_index,
|
| 486 |
+
)
|
| 487 |
+
for i in range(len(out))
|
| 488 |
+
]
|
| 489 |
+
loss = sum(losses)
|
| 490 |
+
|
| 491 |
+
if return_list:
|
| 492 |
+
return loss, losses
|
| 493 |
+
return loss
|
| 494 |
+
|
| 495 |
+
|
| 496 |
+
class MusicXTransformer(nn.Module):
|
| 497 |
+
def __init__(self, *, dim, encoding, **kwargs):
|
| 498 |
+
super().__init__()
|
| 499 |
+
assert "dim" not in kwargs, "dimension must be set with `dim` keyword"
|
| 500 |
+
transformer_kwargs = {
|
| 501 |
+
"max_seq_len": kwargs.pop("max_seq_len"),
|
| 502 |
+
"max_beat": kwargs.pop("max_beat"),
|
| 503 |
+
"emb_dropout": kwargs.pop("emb_dropout", 0),
|
| 504 |
+
"use_abs_pos_emb": kwargs.pop("use_abs_pos_emb", True),
|
| 505 |
+
}
|
| 506 |
+
self.decoder = MusicTransformerWrapper(
|
| 507 |
+
encoding=encoding,
|
| 508 |
+
attn_layers=Decoder(dim=dim, **kwargs),
|
| 509 |
+
**transformer_kwargs,
|
| 510 |
+
)
|
| 511 |
+
self.decoder = MusicAutoregressiveWrapper(
|
| 512 |
+
self.decoder, encoding=encoding
|
| 513 |
+
)
|
| 514 |
+
|
| 515 |
+
@torch.no_grad()
|
| 516 |
+
def generate(self, seq_in, seq_len, **kwargs):
|
| 517 |
+
return self.decoder.generate(seq_in, seq_len, **kwargs)
|
| 518 |
+
|
| 519 |
+
def forward(self, seq, mask=None, **kwargs):
|
| 520 |
+
return self.decoder(seq, mask=mask, **kwargs)
|
| 521 |
+
|
| 522 |
+
|
| 523 |
+
def main():
|
| 524 |
+
"""Main function."""
|
| 525 |
+
# Parse the command-line arguments
|
| 526 |
+
args = parse_args()
|
| 527 |
+
|
| 528 |
+
# Set default arguments
|
| 529 |
+
if args.dataset is not None:
|
| 530 |
+
if args.in_dir is None:
|
| 531 |
+
args.in_dir = pathlib.Path(f"data/{args.dataset}/processed/notes")
|
| 532 |
+
|
| 533 |
+
# Set up the logger
|
| 534 |
+
logging.basicConfig(
|
| 535 |
+
stream=sys.stdout,
|
| 536 |
+
level=logging.ERROR if args.quiet else logging.INFO,
|
| 537 |
+
format="%(levelname)-8s %(message)s",
|
| 538 |
+
)
|
| 539 |
+
|
| 540 |
+
# Log arguments
|
| 541 |
+
logging.info(f"Using arguments:\n{pprint.pformat(vars(args))}")
|
| 542 |
+
|
| 543 |
+
# Load the encoding
|
| 544 |
+
encoding = representation.load_encoding(args.in_dir / "encoding.json")
|
| 545 |
+
|
| 546 |
+
# Create the model
|
| 547 |
+
model = MusicXTransformer(
|
| 548 |
+
dim=128,
|
| 549 |
+
encoding=encoding,
|
| 550 |
+
depth=3,
|
| 551 |
+
heads=4,
|
| 552 |
+
max_seq_len=1024,
|
| 553 |
+
max_beat=256,
|
| 554 |
+
rel_pos_bias=True, # relative positional bias
|
| 555 |
+
rotary_pos_emb=True, # rotary positional encoding
|
| 556 |
+
emb_dropout=0.1,
|
| 557 |
+
attn_dropout=0.1,
|
| 558 |
+
ff_dropout=0.1,
|
| 559 |
+
)
|
| 560 |
+
|
| 561 |
+
# Summarize the model
|
| 562 |
+
n_parameters = sum(p.numel() for p in model.parameters())
|
| 563 |
+
n_trainables = sum(
|
| 564 |
+
p.numel() for p in model.parameters() if p.requires_grad
|
| 565 |
+
)
|
| 566 |
+
print(f"Number of parameters: {n_parameters}")
|
| 567 |
+
print(f"Number of trainable parameters: {n_trainables}")
|
| 568 |
+
|
| 569 |
+
# Create test data
|
| 570 |
+
seq = torch.randint(0, 4, (1, 1024, 6))
|
| 571 |
+
mask = torch.ones((1, 1024)).bool()
|
| 572 |
+
|
| 573 |
+
# Pass test data through the model
|
| 574 |
+
loss = model(seq, mask=mask)
|
| 575 |
+
loss.backward()
|
| 576 |
+
|
| 577 |
+
|
| 578 |
+
if __name__ == "__main__":
|
| 579 |
+
main()
|
mmt/representation.py
ADDED
|
@@ -0,0 +1,756 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Representation utilities."""
|
| 2 |
+
import pathlib
|
| 3 |
+
import pprint
|
| 4 |
+
|
| 5 |
+
import muspy
|
| 6 |
+
import numpy as np
|
| 7 |
+
import pretty_midi
|
| 8 |
+
|
| 9 |
+
import utils
|
| 10 |
+
|
| 11 |
+
# Configuration
|
| 12 |
+
RESOLUTION = 12
|
| 13 |
+
MAX_BEAT = 1024
|
| 14 |
+
MAX_DURATION = 384 # Remember to modify known durations as well!
|
| 15 |
+
|
| 16 |
+
# Dimensions
|
| 17 |
+
# (NOTE: "type" must be the first dimension!)
|
| 18 |
+
# (NOTE: Remember to modify N_TOKENS as well!)
|
| 19 |
+
DIMENSIONS = ["type", "beat", "position", "pitch", "duration", "instrument"]
|
| 20 |
+
assert DIMENSIONS[0] == "type"
|
| 21 |
+
|
| 22 |
+
# Type
|
| 23 |
+
TYPE_CODE_MAP = {
|
| 24 |
+
"start-of-song": 0,
|
| 25 |
+
"instrument": 1,
|
| 26 |
+
"start-of-notes": 2,
|
| 27 |
+
"note": 3,
|
| 28 |
+
"end-of-song": 4,
|
| 29 |
+
}
|
| 30 |
+
CODE_TYPE_MAP = utils.inverse_dict(TYPE_CODE_MAP)
|
| 31 |
+
|
| 32 |
+
# Beat
|
| 33 |
+
BEAT_CODE_MAP = {i: i + 1 for i in range(MAX_BEAT + 1)}
|
| 34 |
+
BEAT_CODE_MAP[None] = 0
|
| 35 |
+
CODE_BEAT_MAP = utils.inverse_dict(BEAT_CODE_MAP)
|
| 36 |
+
|
| 37 |
+
# Position
|
| 38 |
+
POSITION_CODE_MAP = {i: i + 1 for i in range(RESOLUTION)}
|
| 39 |
+
POSITION_CODE_MAP[None] = 0
|
| 40 |
+
CODE_POSITION_MAP = utils.inverse_dict(POSITION_CODE_MAP)
|
| 41 |
+
|
| 42 |
+
# Pitch
|
| 43 |
+
PITCH_CODE_MAP = {i: i + 1 for i in range(128)}
|
| 44 |
+
PITCH_CODE_MAP[None] = 0
|
| 45 |
+
CODE_PITCH_MAP = utils.inverse_dict(PITCH_CODE_MAP)
|
| 46 |
+
|
| 47 |
+
# Duration
|
| 48 |
+
KNOWN_DURATIONS = [
|
| 49 |
+
1,
|
| 50 |
+
2,
|
| 51 |
+
3,
|
| 52 |
+
4,
|
| 53 |
+
5,
|
| 54 |
+
6,
|
| 55 |
+
7,
|
| 56 |
+
8,
|
| 57 |
+
9,
|
| 58 |
+
10,
|
| 59 |
+
11,
|
| 60 |
+
12,
|
| 61 |
+
15,
|
| 62 |
+
16,
|
| 63 |
+
18,
|
| 64 |
+
20,
|
| 65 |
+
21,
|
| 66 |
+
24,
|
| 67 |
+
30,
|
| 68 |
+
36,
|
| 69 |
+
40,
|
| 70 |
+
42,
|
| 71 |
+
48,
|
| 72 |
+
60,
|
| 73 |
+
72,
|
| 74 |
+
84,
|
| 75 |
+
96,
|
| 76 |
+
120,
|
| 77 |
+
144,
|
| 78 |
+
168,
|
| 79 |
+
192,
|
| 80 |
+
384,
|
| 81 |
+
]
|
| 82 |
+
DURATION_CODE_MAP = {
|
| 83 |
+
i: int(np.argmin(np.abs(np.array(KNOWN_DURATIONS) - i))) + 1
|
| 84 |
+
for i in range(MAX_DURATION + 1)
|
| 85 |
+
}
|
| 86 |
+
DURATION_CODE_MAP[None] = 0
|
| 87 |
+
CODE_DURATION_MAP = {
|
| 88 |
+
i + 1: duration for i, duration in enumerate(KNOWN_DURATIONS)
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
# Instrument
|
| 92 |
+
PROGRAM_INSTRUMENT_MAP = {
|
| 93 |
+
# Pianos
|
| 94 |
+
0: "piano",
|
| 95 |
+
1: "piano",
|
| 96 |
+
2: "piano",
|
| 97 |
+
3: "piano",
|
| 98 |
+
4: "electric-piano",
|
| 99 |
+
5: "electric-piano",
|
| 100 |
+
6: "harpsichord",
|
| 101 |
+
7: "clavinet",
|
| 102 |
+
# Chromatic Percussion
|
| 103 |
+
8: "celesta",
|
| 104 |
+
9: "glockenspiel",
|
| 105 |
+
10: "music-box",
|
| 106 |
+
11: "vibraphone",
|
| 107 |
+
12: "marimba",
|
| 108 |
+
13: "xylophone",
|
| 109 |
+
14: "tubular-bells",
|
| 110 |
+
15: "dulcimer",
|
| 111 |
+
# Organs
|
| 112 |
+
16: "organ",
|
| 113 |
+
17: "organ",
|
| 114 |
+
18: "organ",
|
| 115 |
+
19: "church-organ",
|
| 116 |
+
20: "organ",
|
| 117 |
+
21: "accordion",
|
| 118 |
+
22: "harmonica",
|
| 119 |
+
23: "bandoneon",
|
| 120 |
+
# Guitars
|
| 121 |
+
24: "nylon-string-guitar",
|
| 122 |
+
25: "steel-string-guitar",
|
| 123 |
+
26: "electric-guitar",
|
| 124 |
+
27: "electric-guitar",
|
| 125 |
+
28: "electric-guitar",
|
| 126 |
+
29: "electric-guitar",
|
| 127 |
+
30: "electric-guitar",
|
| 128 |
+
31: "electric-guitar",
|
| 129 |
+
# Basses
|
| 130 |
+
32: "bass",
|
| 131 |
+
33: "electric-bass",
|
| 132 |
+
34: "electric-bass",
|
| 133 |
+
35: "electric-bass",
|
| 134 |
+
36: "slap-bass",
|
| 135 |
+
37: "slap-bass",
|
| 136 |
+
38: "synth-bass",
|
| 137 |
+
39: "synth-bass",
|
| 138 |
+
# Strings
|
| 139 |
+
40: "violin",
|
| 140 |
+
41: "viola",
|
| 141 |
+
42: "cello",
|
| 142 |
+
43: "contrabass",
|
| 143 |
+
44: "strings",
|
| 144 |
+
45: "strings",
|
| 145 |
+
46: "harp",
|
| 146 |
+
47: "timpani",
|
| 147 |
+
# Ensemble
|
| 148 |
+
48: "strings",
|
| 149 |
+
49: "strings",
|
| 150 |
+
50: "synth-strings",
|
| 151 |
+
51: "synth-strings",
|
| 152 |
+
52: "voices",
|
| 153 |
+
53: "voices",
|
| 154 |
+
54: "voices",
|
| 155 |
+
55: "orchestra-hit",
|
| 156 |
+
# Brass
|
| 157 |
+
56: "trumpet",
|
| 158 |
+
57: "trombone",
|
| 159 |
+
58: "tuba",
|
| 160 |
+
59: "trumpet",
|
| 161 |
+
60: "horn",
|
| 162 |
+
61: "brasses",
|
| 163 |
+
62: "synth-brasses",
|
| 164 |
+
63: "synth-brasses",
|
| 165 |
+
# Reed
|
| 166 |
+
64: "soprano-saxophone",
|
| 167 |
+
65: "alto-saxophone",
|
| 168 |
+
66: "tenor-saxophone",
|
| 169 |
+
67: "baritone-saxophone",
|
| 170 |
+
68: "oboe",
|
| 171 |
+
69: "english-horn",
|
| 172 |
+
70: "bassoon",
|
| 173 |
+
71: "clarinet",
|
| 174 |
+
# Pipe
|
| 175 |
+
72: "piccolo",
|
| 176 |
+
73: "flute",
|
| 177 |
+
74: "recorder",
|
| 178 |
+
75: "pan-flute",
|
| 179 |
+
76: None,
|
| 180 |
+
77: None,
|
| 181 |
+
78: None,
|
| 182 |
+
79: "ocarina",
|
| 183 |
+
# Synth Lead
|
| 184 |
+
80: "lead",
|
| 185 |
+
81: "lead",
|
| 186 |
+
82: "lead",
|
| 187 |
+
83: "lead",
|
| 188 |
+
84: "lead",
|
| 189 |
+
85: "lead",
|
| 190 |
+
86: "lead",
|
| 191 |
+
87: "lead",
|
| 192 |
+
# Synth Pad
|
| 193 |
+
88: "pad",
|
| 194 |
+
89: "pad",
|
| 195 |
+
90: "pad",
|
| 196 |
+
91: "pad",
|
| 197 |
+
92: "pad",
|
| 198 |
+
93: "pad",
|
| 199 |
+
94: "pad",
|
| 200 |
+
95: "pad",
|
| 201 |
+
# Synth Effects
|
| 202 |
+
96: None,
|
| 203 |
+
97: None,
|
| 204 |
+
98: None,
|
| 205 |
+
99: None,
|
| 206 |
+
100: None,
|
| 207 |
+
101: None,
|
| 208 |
+
102: None,
|
| 209 |
+
103: None,
|
| 210 |
+
# Ethnic
|
| 211 |
+
104: "sitar",
|
| 212 |
+
105: "banjo",
|
| 213 |
+
106: "shamisen",
|
| 214 |
+
107: "koto",
|
| 215 |
+
108: "kalimba",
|
| 216 |
+
109: "bag-pipe",
|
| 217 |
+
110: "violin",
|
| 218 |
+
111: "shehnai",
|
| 219 |
+
# Percussive
|
| 220 |
+
112: None,
|
| 221 |
+
113: None,
|
| 222 |
+
114: None,
|
| 223 |
+
115: None,
|
| 224 |
+
116: None,
|
| 225 |
+
117: "melodic-tom",
|
| 226 |
+
118: "synth-drums",
|
| 227 |
+
119: "synth-drums",
|
| 228 |
+
# Sound effects
|
| 229 |
+
120: None,
|
| 230 |
+
121: None,
|
| 231 |
+
122: None,
|
| 232 |
+
123: None,
|
| 233 |
+
124: None,
|
| 234 |
+
125: None,
|
| 235 |
+
126: None,
|
| 236 |
+
127: None,
|
| 237 |
+
}
|
| 238 |
+
INSTRUMENT_PROGRAM_MAP = {
|
| 239 |
+
# Pianos
|
| 240 |
+
"piano": 0,
|
| 241 |
+
"electric-piano": 4,
|
| 242 |
+
"harpsichord": 6,
|
| 243 |
+
"clavinet": 7,
|
| 244 |
+
# Chromatic Percussion
|
| 245 |
+
"celesta": 8,
|
| 246 |
+
"glockenspiel": 9,
|
| 247 |
+
"music-box": 10,
|
| 248 |
+
"vibraphone": 11,
|
| 249 |
+
"marimba": 12,
|
| 250 |
+
"xylophone": 13,
|
| 251 |
+
"tubular-bells": 14,
|
| 252 |
+
"dulcimer": 15,
|
| 253 |
+
# Organs
|
| 254 |
+
"organ": 16,
|
| 255 |
+
"church-organ": 19,
|
| 256 |
+
"accordion": 21,
|
| 257 |
+
"harmonica": 22,
|
| 258 |
+
"bandoneon": 23,
|
| 259 |
+
# Guitars
|
| 260 |
+
"nylon-string-guitar": 24,
|
| 261 |
+
"steel-string-guitar": 25,
|
| 262 |
+
"electric-guitar": 26,
|
| 263 |
+
# Basses
|
| 264 |
+
"bass": 32,
|
| 265 |
+
"electric-bass": 33,
|
| 266 |
+
"slap-bass": 36,
|
| 267 |
+
"synth-bass": 38,
|
| 268 |
+
# Strings
|
| 269 |
+
"violin": 40,
|
| 270 |
+
"viola": 41,
|
| 271 |
+
"cello": 42,
|
| 272 |
+
"contrabass": 43,
|
| 273 |
+
"harp": 46,
|
| 274 |
+
"timpani": 47,
|
| 275 |
+
# Ensemble
|
| 276 |
+
"strings": 49,
|
| 277 |
+
"synth-strings": 50,
|
| 278 |
+
"voices": 52,
|
| 279 |
+
"orchestra-hit": 55,
|
| 280 |
+
# Brass
|
| 281 |
+
"trumpet": 56,
|
| 282 |
+
"trombone": 57,
|
| 283 |
+
"tuba": 58,
|
| 284 |
+
"horn": 60,
|
| 285 |
+
"brasses": 61,
|
| 286 |
+
"synth-brasses": 62,
|
| 287 |
+
# Reed
|
| 288 |
+
"soprano-saxophone": 64,
|
| 289 |
+
"alto-saxophone": 65,
|
| 290 |
+
"tenor-saxophone": 66,
|
| 291 |
+
"baritone-saxophone": 67,
|
| 292 |
+
"oboe": 68,
|
| 293 |
+
"english-horn": 69,
|
| 294 |
+
"bassoon": 70,
|
| 295 |
+
"clarinet": 71,
|
| 296 |
+
# Pipe
|
| 297 |
+
"piccolo": 72,
|
| 298 |
+
"flute": 73,
|
| 299 |
+
"recorder": 74,
|
| 300 |
+
"pan-flute": 75,
|
| 301 |
+
"ocarina": 79,
|
| 302 |
+
# Synth Lead
|
| 303 |
+
"lead": 80,
|
| 304 |
+
# Synth Pad
|
| 305 |
+
"pad": 88,
|
| 306 |
+
# Ethnic
|
| 307 |
+
"sitar": 104,
|
| 308 |
+
"banjo": 105,
|
| 309 |
+
"shamisen": 106,
|
| 310 |
+
"koto": 107,
|
| 311 |
+
"kalimba": 108,
|
| 312 |
+
"bag-pipe": 109,
|
| 313 |
+
"shehnai": 111,
|
| 314 |
+
# Percussive
|
| 315 |
+
"melodic-tom": 117,
|
| 316 |
+
"synth-drums": 118,
|
| 317 |
+
}
|
| 318 |
+
KNOWN_PROGRAMS = list(
|
| 319 |
+
k for k, v in PROGRAM_INSTRUMENT_MAP.items() if v is not None
|
| 320 |
+
)
|
| 321 |
+
KNOWN_INSTRUMENTS = list(dict.fromkeys(INSTRUMENT_PROGRAM_MAP.keys()))
|
| 322 |
+
INSTRUMENT_CODE_MAP = {
|
| 323 |
+
instrument: i + 1 for i, instrument in enumerate(KNOWN_INSTRUMENTS)
|
| 324 |
+
}
|
| 325 |
+
INSTRUMENT_CODE_MAP[None] = 0
|
| 326 |
+
CODE_INSTRUMENT_MAP = utils.inverse_dict(INSTRUMENT_CODE_MAP)
|
| 327 |
+
|
| 328 |
+
N_TOKENS = [
|
| 329 |
+
max(TYPE_CODE_MAP.values()) + 1,
|
| 330 |
+
max(BEAT_CODE_MAP.values()) + 1,
|
| 331 |
+
max(POSITION_CODE_MAP.values()) + 1,
|
| 332 |
+
max(PITCH_CODE_MAP.values()) + 1,
|
| 333 |
+
max(DURATION_CODE_MAP.values()) + 1,
|
| 334 |
+
max(INSTRUMENT_CODE_MAP.values()) + 1,
|
| 335 |
+
]
|
| 336 |
+
|
| 337 |
+
|
| 338 |
+
def get_encoding():
|
| 339 |
+
"""Return the encoding configurations."""
|
| 340 |
+
return {
|
| 341 |
+
"resolution": RESOLUTION,
|
| 342 |
+
"max_beat": MAX_BEAT,
|
| 343 |
+
"max_duration": MAX_DURATION,
|
| 344 |
+
"dimensions": DIMENSIONS,
|
| 345 |
+
"n_tokens": N_TOKENS,
|
| 346 |
+
"type_code_map": TYPE_CODE_MAP,
|
| 347 |
+
"beat_code_map": BEAT_CODE_MAP,
|
| 348 |
+
"position_code_map": POSITION_CODE_MAP,
|
| 349 |
+
"pitch_code_map": PITCH_CODE_MAP,
|
| 350 |
+
"duration_code_map": DURATION_CODE_MAP,
|
| 351 |
+
"instrument_code_map": INSTRUMENT_CODE_MAP,
|
| 352 |
+
"code_type_map": CODE_TYPE_MAP,
|
| 353 |
+
"code_beat_map": CODE_BEAT_MAP,
|
| 354 |
+
"code_position_map": CODE_POSITION_MAP,
|
| 355 |
+
"code_pitch_map": CODE_PITCH_MAP,
|
| 356 |
+
"code_duration_map": CODE_DURATION_MAP,
|
| 357 |
+
"code_instrument_map": CODE_INSTRUMENT_MAP,
|
| 358 |
+
"program_instrument_map": PROGRAM_INSTRUMENT_MAP,
|
| 359 |
+
"instrument_program_map": INSTRUMENT_PROGRAM_MAP,
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
|
| 363 |
+
def load_encoding(filename):
|
| 364 |
+
"""Load encoding configurations from a JSON file."""
|
| 365 |
+
encoding = utils.load_json(filename)
|
| 366 |
+
for key in (
|
| 367 |
+
"code_type_map",
|
| 368 |
+
"code_beat_map",
|
| 369 |
+
"code_position_map",
|
| 370 |
+
"code_duration_map",
|
| 371 |
+
"code_pitch_map",
|
| 372 |
+
"code_instrument_map",
|
| 373 |
+
"beat_code_map",
|
| 374 |
+
"position_code_map",
|
| 375 |
+
"duration_code_map",
|
| 376 |
+
"pitch_code_map",
|
| 377 |
+
"program_instrument_map",
|
| 378 |
+
):
|
| 379 |
+
encoding[key] = {
|
| 380 |
+
int(k) if k != "null" else None: v
|
| 381 |
+
for k, v in encoding[key].items()
|
| 382 |
+
}
|
| 383 |
+
return encoding
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
def extract_notes(music, resolution):
|
| 387 |
+
"""Return a MusPy music object as a note sequence.
|
| 388 |
+
|
| 389 |
+
Each row of the output is a note specified as follows.
|
| 390 |
+
|
| 391 |
+
(beat, position, pitch, duration, program)
|
| 392 |
+
|
| 393 |
+
"""
|
| 394 |
+
# Check resolution
|
| 395 |
+
assert music.resolution == resolution
|
| 396 |
+
|
| 397 |
+
# Extract notes
|
| 398 |
+
notes = []
|
| 399 |
+
for track in music:
|
| 400 |
+
if track.is_drum or track.program not in KNOWN_PROGRAMS:
|
| 401 |
+
continue
|
| 402 |
+
for note in track:
|
| 403 |
+
beat, position = divmod(note.time, resolution)
|
| 404 |
+
notes.append(
|
| 405 |
+
(beat, position, note.pitch, note.duration, track.program)
|
| 406 |
+
)
|
| 407 |
+
|
| 408 |
+
# Deduplicate and sort the notes
|
| 409 |
+
notes = sorted(set(notes))
|
| 410 |
+
|
| 411 |
+
return np.array(notes)
|
| 412 |
+
|
| 413 |
+
|
| 414 |
+
def encode_notes(notes, encoding):
|
| 415 |
+
"""Encode a note sequence into a sequence of codes.
|
| 416 |
+
|
| 417 |
+
Each row of the input is a note specified as follows.
|
| 418 |
+
|
| 419 |
+
(beat, position, pitch, duration, program)
|
| 420 |
+
|
| 421 |
+
Each row of the output is encoded as follows.
|
| 422 |
+
|
| 423 |
+
(event_type, beat, position, pitch, duration, instrument)
|
| 424 |
+
|
| 425 |
+
"""
|
| 426 |
+
# Get variables
|
| 427 |
+
max_beat = encoding["max_beat"]
|
| 428 |
+
max_duration = encoding["max_duration"]
|
| 429 |
+
|
| 430 |
+
# Get maps
|
| 431 |
+
type_code_map = encoding["type_code_map"]
|
| 432 |
+
beat_code_map = encoding["beat_code_map"]
|
| 433 |
+
position_code_map = encoding["position_code_map"]
|
| 434 |
+
pitch_code_map = encoding["pitch_code_map"]
|
| 435 |
+
duration_code_map = encoding["duration_code_map"]
|
| 436 |
+
instrument_code_map = encoding["instrument_code_map"]
|
| 437 |
+
program_instrument_map = encoding["program_instrument_map"]
|
| 438 |
+
|
| 439 |
+
# Get the dimension indices
|
| 440 |
+
beat_dim = encoding["dimensions"].index("beat")
|
| 441 |
+
position_dim = encoding["dimensions"].index("position")
|
| 442 |
+
pitch_dim = encoding["dimensions"].index("pitch")
|
| 443 |
+
duration_dim = encoding["dimensions"].index("duration")
|
| 444 |
+
instrument_dim = encoding["dimensions"].index("instrument")
|
| 445 |
+
|
| 446 |
+
# Start the codes with an SOS row
|
| 447 |
+
codes = [(type_code_map["start-of-song"], 0, 0, 0, 0, 0)]
|
| 448 |
+
|
| 449 |
+
# Extract instruments
|
| 450 |
+
instruments = set(program_instrument_map[note[-1]] for note in notes)
|
| 451 |
+
|
| 452 |
+
# Encode the instruments
|
| 453 |
+
instrument_codes = []
|
| 454 |
+
for instrument in instruments:
|
| 455 |
+
# Skip unknown instruments
|
| 456 |
+
if instrument is None:
|
| 457 |
+
continue
|
| 458 |
+
row = [type_code_map["instrument"], 0, 0, 0, 0, 0]
|
| 459 |
+
row[instrument_dim] = instrument_code_map[instrument]
|
| 460 |
+
instrument_codes.append(row)
|
| 461 |
+
|
| 462 |
+
# Sort the instruments and append them to the code sequence
|
| 463 |
+
instrument_codes.sort()
|
| 464 |
+
codes.extend(instrument_codes)
|
| 465 |
+
|
| 466 |
+
# Encode the notes
|
| 467 |
+
codes.append((type_code_map["start-of-notes"], 0, 0, 0, 0, 0))
|
| 468 |
+
for beat, position, pitch, duration, program in notes:
|
| 469 |
+
# Skip if max_beat has reached
|
| 470 |
+
if beat > max_beat:
|
| 471 |
+
continue
|
| 472 |
+
# Skip unknown instruments
|
| 473 |
+
instrument = program_instrument_map[program]
|
| 474 |
+
if instrument is None:
|
| 475 |
+
continue
|
| 476 |
+
# Encode the note
|
| 477 |
+
row = [type_code_map["note"], 0, 0, 0, 0, 0]
|
| 478 |
+
row[beat_dim] = beat_code_map[beat]
|
| 479 |
+
row[position_dim] = position_code_map[position]
|
| 480 |
+
row[pitch_dim] = pitch_code_map[pitch]
|
| 481 |
+
row[duration_dim] = duration_code_map[min(duration, max_duration)]
|
| 482 |
+
row[instrument_dim] = instrument_code_map[instrument]
|
| 483 |
+
codes.append(row)
|
| 484 |
+
|
| 485 |
+
# End the codes with an EOS row
|
| 486 |
+
codes.append((type_code_map["end-of-song"], 0, 0, 0, 0, 0))
|
| 487 |
+
|
| 488 |
+
return np.array(codes)
|
| 489 |
+
|
| 490 |
+
|
| 491 |
+
def encode(music, encoding):
|
| 492 |
+
"""Encode a MusPy music object into a sequence of codes.
|
| 493 |
+
|
| 494 |
+
Each row of the input is encoded as follows.
|
| 495 |
+
|
| 496 |
+
(event_type, beat, position, pitch, duration, instrument)
|
| 497 |
+
|
| 498 |
+
Each row of the output is a note specified as follows.
|
| 499 |
+
|
| 500 |
+
(beat, position, pitch, duration, program)
|
| 501 |
+
|
| 502 |
+
"""
|
| 503 |
+
# Extract notes
|
| 504 |
+
notes = extract_notes(music, encoding["resolution"])
|
| 505 |
+
|
| 506 |
+
# Encode the notes
|
| 507 |
+
codes = encode_notes(notes, encoding)
|
| 508 |
+
|
| 509 |
+
return codes
|
| 510 |
+
|
| 511 |
+
|
| 512 |
+
def decode_notes(codes, encoding):
|
| 513 |
+
"""Decode codes into a note sequence.
|
| 514 |
+
|
| 515 |
+
Each row of the input is encoded as follows.
|
| 516 |
+
|
| 517 |
+
(event_type, beat, position, pitch, duration, instrument)
|
| 518 |
+
|
| 519 |
+
"""
|
| 520 |
+
# Get variables and maps
|
| 521 |
+
code_type_map = encoding["code_type_map"]
|
| 522 |
+
code_beat_map = encoding["code_beat_map"]
|
| 523 |
+
code_position_map = encoding["code_position_map"]
|
| 524 |
+
code_pitch_map = encoding["code_pitch_map"]
|
| 525 |
+
code_duration_map = encoding["code_duration_map"]
|
| 526 |
+
code_instrument_map = encoding["code_instrument_map"]
|
| 527 |
+
instrument_program_map = encoding["instrument_program_map"]
|
| 528 |
+
|
| 529 |
+
# Get the dimension indices
|
| 530 |
+
beat_dim = encoding["dimensions"].index("beat")
|
| 531 |
+
position_dim = encoding["dimensions"].index("position")
|
| 532 |
+
pitch_dim = encoding["dimensions"].index("pitch")
|
| 533 |
+
duration_dim = encoding["dimensions"].index("duration")
|
| 534 |
+
instrument_dim = encoding["dimensions"].index("instrument")
|
| 535 |
+
|
| 536 |
+
# Decode the codes into a sequence of notes
|
| 537 |
+
notes = []
|
| 538 |
+
for row in codes:
|
| 539 |
+
event_type = code_type_map[int(row[0])]
|
| 540 |
+
if event_type in ("start-of-song", "instrument", "start-of-notes"):
|
| 541 |
+
continue
|
| 542 |
+
elif event_type == "end-of-song":
|
| 543 |
+
break
|
| 544 |
+
elif event_type == "note":
|
| 545 |
+
beat = code_beat_map[int(row[beat_dim])]
|
| 546 |
+
position = code_position_map[int(row[position_dim])]
|
| 547 |
+
pitch = code_pitch_map[int(row[pitch_dim])]
|
| 548 |
+
duration = code_duration_map[int(row[duration_dim])]
|
| 549 |
+
instrument = code_instrument_map[int(row[instrument_dim])]
|
| 550 |
+
program = instrument_program_map[instrument]
|
| 551 |
+
notes.append((beat, position, pitch, duration, program))
|
| 552 |
+
else:
|
| 553 |
+
raise ValueError("Unknown event type.")
|
| 554 |
+
|
| 555 |
+
return notes
|
| 556 |
+
|
| 557 |
+
|
| 558 |
+
def reconstruct(notes, resolution):
|
| 559 |
+
"""Reconstruct a note sequence to a MusPy Music object."""
|
| 560 |
+
# Construct the MusPy Music object
|
| 561 |
+
music = muspy.Music(resolution=resolution, tempos=[muspy.Tempo(0, 100)])
|
| 562 |
+
|
| 563 |
+
# Append the tracks
|
| 564 |
+
programs = sorted(set(note[-1] for note in notes))
|
| 565 |
+
for program in programs:
|
| 566 |
+
music.tracks.append(muspy.Track(program))
|
| 567 |
+
|
| 568 |
+
# Append the notes
|
| 569 |
+
for beat, position, pitch, duration, program in notes:
|
| 570 |
+
time = beat * resolution + position
|
| 571 |
+
track_idx = programs.index(program)
|
| 572 |
+
music[track_idx].notes.append(muspy.Note(time, pitch, duration))
|
| 573 |
+
|
| 574 |
+
return music
|
| 575 |
+
|
| 576 |
+
|
| 577 |
+
def decode(codes, encoding):
|
| 578 |
+
"""Decode codes into a MusPy Music object.
|
| 579 |
+
|
| 580 |
+
Each row of the input is encoded as follows.
|
| 581 |
+
|
| 582 |
+
(event_type, beat, position, pitch, duration, instrument)
|
| 583 |
+
|
| 584 |
+
"""
|
| 585 |
+
# Get resolution
|
| 586 |
+
resolution = encoding["resolution"]
|
| 587 |
+
|
| 588 |
+
# Decode codes into a note sequence
|
| 589 |
+
notes = decode_notes(codes, encoding)
|
| 590 |
+
|
| 591 |
+
# Reconstruct the music object
|
| 592 |
+
music = reconstruct(notes, resolution)
|
| 593 |
+
|
| 594 |
+
return music
|
| 595 |
+
|
| 596 |
+
|
| 597 |
+
def dump(data, encoding):
|
| 598 |
+
"""Decode the codes and dump as a string."""
|
| 599 |
+
# Get maps
|
| 600 |
+
code_type_map = encoding["code_type_map"]
|
| 601 |
+
code_beat_map = encoding["code_beat_map"]
|
| 602 |
+
code_position_map = encoding["code_position_map"]
|
| 603 |
+
code_pitch_map = encoding["code_pitch_map"]
|
| 604 |
+
code_duration_map = encoding["code_duration_map"]
|
| 605 |
+
code_instrument_map = encoding["code_instrument_map"]
|
| 606 |
+
|
| 607 |
+
# Get the dimension indices
|
| 608 |
+
beat_dim = encoding["dimensions"].index("beat")
|
| 609 |
+
position_dim = encoding["dimensions"].index("position")
|
| 610 |
+
pitch_dim = encoding["dimensions"].index("pitch")
|
| 611 |
+
duration_dim = encoding["dimensions"].index("duration")
|
| 612 |
+
instrument_dim = encoding["dimensions"].index("instrument")
|
| 613 |
+
|
| 614 |
+
# Iterate over the rows
|
| 615 |
+
lines = []
|
| 616 |
+
for row in data:
|
| 617 |
+
event_type = code_type_map[int(row[0])]
|
| 618 |
+
if event_type == "start-of-song":
|
| 619 |
+
lines.append("Start of song")
|
| 620 |
+
elif event_type == "end-of-song":
|
| 621 |
+
lines.append("End of song")
|
| 622 |
+
elif event_type == "instrument":
|
| 623 |
+
instrument = code_instrument_map[int(row[instrument_dim])]
|
| 624 |
+
lines.append(f"Instrument: {instrument}")
|
| 625 |
+
elif event_type == "start-of-notes":
|
| 626 |
+
lines.append("Start of notes")
|
| 627 |
+
elif event_type == "note":
|
| 628 |
+
beat = code_beat_map[int(row[beat_dim])]
|
| 629 |
+
position = code_position_map[int(row[position_dim])]
|
| 630 |
+
pitch = pretty_midi.note_number_to_name(
|
| 631 |
+
code_pitch_map[int(row[pitch_dim])]
|
| 632 |
+
)
|
| 633 |
+
duration = code_duration_map[int(row[duration_dim])]
|
| 634 |
+
instrument = code_instrument_map[int(row[instrument_dim])]
|
| 635 |
+
lines.append(
|
| 636 |
+
f"Note: beat={beat}, position={position}, pitch={pitch}, "
|
| 637 |
+
f"duration={duration}, instrument={instrument}"
|
| 638 |
+
)
|
| 639 |
+
else:
|
| 640 |
+
raise ValueError(f"Unknown event type: {event_type}")
|
| 641 |
+
|
| 642 |
+
return "\n".join(lines)
|
| 643 |
+
|
| 644 |
+
|
| 645 |
+
def save_txt(filename, data, encoding):
|
| 646 |
+
"""Dump the codes into a TXT file."""
|
| 647 |
+
with open(filename, "w") as f:
|
| 648 |
+
f.write(dump(data, encoding))
|
| 649 |
+
|
| 650 |
+
|
| 651 |
+
def save_csv_notes(filename, data):
|
| 652 |
+
"""Save the representation as a CSV file."""
|
| 653 |
+
assert data.shape[1] == 5
|
| 654 |
+
np.savetxt(
|
| 655 |
+
filename,
|
| 656 |
+
data,
|
| 657 |
+
fmt="%d",
|
| 658 |
+
delimiter=",",
|
| 659 |
+
header="beat,position,pitch,duration,program",
|
| 660 |
+
comments="",
|
| 661 |
+
)
|
| 662 |
+
|
| 663 |
+
|
| 664 |
+
def save_csv_codes(filename, data):
|
| 665 |
+
"""Save the representation as a CSV file."""
|
| 666 |
+
assert data.shape[1] == 6
|
| 667 |
+
np.savetxt(
|
| 668 |
+
filename,
|
| 669 |
+
data,
|
| 670 |
+
fmt="%d",
|
| 671 |
+
delimiter=",",
|
| 672 |
+
header="type,beat,position,pitch,duration,instrument",
|
| 673 |
+
comments="",
|
| 674 |
+
)
|
| 675 |
+
|
| 676 |
+
|
| 677 |
+
def main():
|
| 678 |
+
"""Main function."""
|
| 679 |
+
# Get the encoding
|
| 680 |
+
encoding = get_encoding()
|
| 681 |
+
|
| 682 |
+
# Save the encoding
|
| 683 |
+
filename = pathlib.Path(__file__).parent / "encoding.json"
|
| 684 |
+
utils.save_json(filename, encoding)
|
| 685 |
+
|
| 686 |
+
# Load encoding
|
| 687 |
+
encoding = load_encoding(filename)
|
| 688 |
+
|
| 689 |
+
# Print the maps
|
| 690 |
+
print(f"{' Maps ':=^40}")
|
| 691 |
+
for key, value in encoding.items():
|
| 692 |
+
if key in (
|
| 693 |
+
"instrument_code_map",
|
| 694 |
+
"code_instrument_map",
|
| 695 |
+
"program_instrument_map",
|
| 696 |
+
"instrument_program_map",
|
| 697 |
+
):
|
| 698 |
+
print("-" * 40)
|
| 699 |
+
print(f"{key}:")
|
| 700 |
+
pprint.pprint(value, indent=2)
|
| 701 |
+
|
| 702 |
+
# Print the variables
|
| 703 |
+
print(f"{' Variables ':=^40}")
|
| 704 |
+
print(f"resolution: {encoding['resolution']}")
|
| 705 |
+
print(f"max_beat: {encoding['max_beat']}")
|
| 706 |
+
print(f"max_duration: {encoding['max_duration']}")
|
| 707 |
+
|
| 708 |
+
# Print the number of tokens
|
| 709 |
+
print(f"{' Number of tokens ':=^40}")
|
| 710 |
+
keys = ("type", "beat", "position", "pitch", "duration", "instrument")
|
| 711 |
+
for key, value in zip(keys, N_TOKENS):
|
| 712 |
+
print(f"{key}: {value}")
|
| 713 |
+
|
| 714 |
+
# Print an example
|
| 715 |
+
print(f"{'Example':=^40}")
|
| 716 |
+
codes = np.array(
|
| 717 |
+
(
|
| 718 |
+
(0, 0, 0, 0, 0, 0),
|
| 719 |
+
(1, 0, 0, 0, 0, 3),
|
| 720 |
+
(1, 0, 0, 0, 0, 33),
|
| 721 |
+
(2, 0, 0, 0, 0, 0),
|
| 722 |
+
(3, 1, 1, 49, 15, 3),
|
| 723 |
+
(3, 1, 1, 61, 15, 3),
|
| 724 |
+
(3, 1, 1, 65, 15, 3),
|
| 725 |
+
(3, 1, 1, 68, 10, 33),
|
| 726 |
+
(3, 1, 1, 68, 15, 3),
|
| 727 |
+
(3, 2, 1, 68, 10, 33),
|
| 728 |
+
(3, 3, 1, 68, 10, 33),
|
| 729 |
+
(3, 4, 1, 61, 10, 33),
|
| 730 |
+
(3, 4, 1, 61, 15, 3),
|
| 731 |
+
(3, 4, 1, 65, 4, 33),
|
| 732 |
+
(3, 4, 1, 65, 10, 3),
|
| 733 |
+
(3, 4, 1, 68, 10, 3),
|
| 734 |
+
(3, 4, 1, 73, 10, 3),
|
| 735 |
+
(3, 4, 13, 63, 4, 33),
|
| 736 |
+
(4, 0, 0, 0, 0, 0),
|
| 737 |
+
),
|
| 738 |
+
int,
|
| 739 |
+
)
|
| 740 |
+
print(f"Codes:\n{codes}")
|
| 741 |
+
|
| 742 |
+
print("-" * 40)
|
| 743 |
+
print(f"Decoded:\n{dump(codes, encoding)}")
|
| 744 |
+
|
| 745 |
+
music = decode(codes, encoding)
|
| 746 |
+
print("-" * 40)
|
| 747 |
+
print(f"Decoded music:\n{music}")
|
| 748 |
+
|
| 749 |
+
encoded = encode(music, encoding)
|
| 750 |
+
print("-" * 40)
|
| 751 |
+
print(f"Encoded:\n{encoded}")
|
| 752 |
+
assert np.all(codes == encoded)
|
| 753 |
+
|
| 754 |
+
|
| 755 |
+
if __name__ == "__main__":
|
| 756 |
+
main()
|
mmt/utils.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Utility functions."""
|
| 2 |
+
import json
|
| 3 |
+
import pathlib
|
| 4 |
+
import warnings
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def save_args(filename, args):
|
| 10 |
+
"""Save the command-line arguments."""
|
| 11 |
+
args_dict = {}
|
| 12 |
+
for key, value in vars(args).items():
|
| 13 |
+
if isinstance(value, pathlib.Path):
|
| 14 |
+
args_dict[key] = str(value)
|
| 15 |
+
else:
|
| 16 |
+
args_dict[key] = value
|
| 17 |
+
save_json(filename, args_dict)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def inverse_dict(d):
|
| 21 |
+
"""Return the inverse dictionary."""
|
| 22 |
+
return {v: k for k, v in d.items()}
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def save_txt(filename, data):
|
| 26 |
+
"""Save a list to a TXT file."""
|
| 27 |
+
with open(filename, "w", encoding="utf8") as f:
|
| 28 |
+
for item in data:
|
| 29 |
+
f.write(f"{item}\n")
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def load_txt(filename):
|
| 33 |
+
"""Load a TXT file as a list."""
|
| 34 |
+
with open(filename, encoding="utf8") as f:
|
| 35 |
+
return [line.strip() for line in f]
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def save_json(filename, data):
|
| 39 |
+
"""Save data as a JSON file."""
|
| 40 |
+
with open(filename, "w", encoding="utf8") as f:
|
| 41 |
+
json.dump(data, f)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def load_json(filename):
|
| 45 |
+
"""Load data from a JSON file."""
|
| 46 |
+
with open(filename, encoding="utf8") as f:
|
| 47 |
+
return json.load(f)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def save_csv(filename, data, header=""):
|
| 51 |
+
"""Save data as a CSV file."""
|
| 52 |
+
np.savetxt(
|
| 53 |
+
filename, data, fmt="%d", delimiter=",", header=header, comments=""
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def load_csv(filename, skiprows=1):
|
| 58 |
+
"""Load data from a CSV file."""
|
| 59 |
+
return np.loadtxt(filename, dtype=int, delimiter=",", skiprows=skiprows)
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def ignore_exceptions(func):
|
| 63 |
+
"""Decorator that ignores all errors and warnings."""
|
| 64 |
+
|
| 65 |
+
def inner(*args, **kwargs):
|
| 66 |
+
with warnings.catch_warnings():
|
| 67 |
+
warnings.simplefilter("ignore")
|
| 68 |
+
try:
|
| 69 |
+
return func(*args, **kwargs)
|
| 70 |
+
except Exception:
|
| 71 |
+
return None
|
| 72 |
+
|
| 73 |
+
return inner
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def resolve_paths(func):
|
| 77 |
+
"""Decorator that resolves all paths."""
|
| 78 |
+
|
| 79 |
+
def inner(*args, **kwargs):
|
| 80 |
+
parsed = func(*args, **kwargs)
|
| 81 |
+
for key in vars(parsed).keys():
|
| 82 |
+
if isinstance(getattr(parsed, key), pathlib.Path):
|
| 83 |
+
setattr(
|
| 84 |
+
parsed, key, getattr(parsed, key).expanduser().resolve()
|
| 85 |
+
)
|
| 86 |
+
return parsed
|
| 87 |
+
|
| 88 |
+
return inner
|
model.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "MMT",
|
| 3 |
+
"package_dir": "mmt",
|
| 4 |
+
"entry_point": ["representation", "music_x_transformers"],
|
| 5 |
+
"checkpoint": {
|
| 6 |
+
"location": "committed directly to Space repo at checkpoints/sod-ape/",
|
| 7 |
+
"structure": "train-args.json + checkpoints/best_model.pt, preserving the exact relative layout mmt/generate.py expects (train_args = utils.load_json(out_dir / 'train-args.json'); model.load_state_dict(torch.load(out_dir / 'checkpoints' / 'best_model.pt'))",
|
| 8 |
+
"size_mb": 80,
|
| 9 |
+
"source": "sod/ape/ from the README's Pretrained Models SharePoint link"
|
| 10 |
+
}
|
| 11 |
+
}
|
packages.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
fluidsynth
|
requirements.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
git+https://github.com/TEAMuP-dev/pyharp.git@develop
|
| 2 |
+
# model-specific deps below:
|
| 3 |
+
torch==2.8.0
|
| 4 |
+
torchaudio==2.8.0
|
| 5 |
+
x-transformers==0.25.9
|
| 6 |
+
einops
|
| 7 |
+
muspy
|
| 8 |
+
pretty_midi
|
| 9 |
+
numpy
|