Spaces:
Running on Zero
Running on Zero
| """drum_dynamics β utilities for the drum-velocity "humanization" thesis. | |
| This package extracts the helper code that was previously duplicated inline | |
| across the exploratory notebooks (``poc.ipynb`` and ``ml/notebooks/eda.ipynb``): | |
| * :mod:`drum_dynamics.core.midi` β MIDI note access helpers (``MidiNote``, ``Idx``), | |
| the General MIDI percussion map, and loading helpers built on ``partitura``. | |
| * :mod:`drum_dynamics.viz.viz` β piano-roll / drum-roll visualization. | |
| * :mod:`drum_dynamics.viz.playback` β in-notebook audio rendering via FluidSynth. | |
| The goal of the wider project is to predict a "best-fitting" velocity for every | |
| note in a MIDI *drum* track β i.e. humanizing dynamics, analogous to existing | |
| tempo humanization. We focus on the Expanded Groove MIDI Dataset (E-GMD). | |
| """ | |
| import importlib | |
| from .core.midi import ( | |
| Idx, | |
| MidiNote, | |
| DRUM_MIDI_NAME, | |
| EGMD_EXTRA_MIDI_NAME, | |
| TONES_FORMAT, | |
| drum_name, | |
| midi_number_to_tone, | |
| load_note_array, | |
| ) | |
| from .core.voicemap import CANONICAL_VOICES, PITCH_TO_VOICE, voice_of, voice_index | |
| from .data.features import build_note_features | |
| from .models.baselines import GlobalMeanBaseline, LookupTableBaseline | |
| from .eval.metrics import mae, rmse, evaluate, wasserstein1d, hist_intersection | |
| from .viz.viz import piano_roll, drums_roll | |
| from .viz.playback import play_midi_file, play_midi_notes, set_soundfont, get_soundfont | |
| __all__ = [ | |
| "Idx", | |
| "MidiNote", | |
| "DRUM_MIDI_NAME", | |
| "EGMD_EXTRA_MIDI_NAME", | |
| "TONES_FORMAT", | |
| "drum_name", | |
| "midi_number_to_tone", | |
| "load_note_array", | |
| "CANONICAL_VOICES", | |
| "PITCH_TO_VOICE", | |
| "voice_of", | |
| "voice_index", | |
| "build_note_features", | |
| "GlobalMeanBaseline", | |
| "LookupTableBaseline", | |
| "mae", | |
| "rmse", | |
| "evaluate", | |
| "wasserstein1d", | |
| "hist_intersection", | |
| "NUMERIC_FEATURES", | |
| "MAX_LEN", | |
| "build_genre_vocab", | |
| "bpm_stats", | |
| "build_split_tensors", | |
| "scatter_predictions", | |
| "VelocityTransformer", | |
| "warm_start_backbone", | |
| "piano_roll", | |
| "drums_roll", | |
| "play_midi_file", | |
| "play_midi_notes", | |
| "set_soundfont", | |
| "get_soundfont", | |
| ] | |
| # Torch-dependent symbols are imported lazily: importing this package (or its | |
| # light submodules like `features`/`midi`) must NOT pull in torch. On macOS, | |
| # loading torch's OpenMP runtime before LightGBM's segfaults, so the tabular | |
| # path must stay torch-free. Accessing these names (or importing the | |
| # `.model`/`.seqdata` submodules directly) loads torch on demand. | |
| _LAZY = { | |
| "NUMERIC_FEATURES": "data.seqdata", | |
| "MAX_LEN": "data.seqdata", | |
| "build_genre_vocab": "data.seqdata", | |
| "bpm_stats": "data.seqdata", | |
| "build_split_tensors": "data.seqdata", | |
| "scatter_predictions": "data.seqdata", | |
| "VelocityTransformer": "models.model", | |
| "warm_start_backbone": "models.model", | |
| } | |
| def __getattr__(name): | |
| if name in _LAZY: | |
| module = importlib.import_module(f".{_LAZY[name]}", __name__) | |
| return getattr(module, name) | |
| raise AttributeError(f"module {__name__!r} has no attribute {name!r}") | |