edm98 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. edm98-0.1.0/LICENSE +26 -0
  2. edm98-0.1.0/PKG-INFO +372 -0
  3. edm98-0.1.0/README.md +332 -0
  4. edm98-0.1.0/pyproject.toml +69 -0
  5. edm98-0.1.0/setup.cfg +4 -0
  6. edm98-0.1.0/src/edm98/__init__.py +5 -0
  7. edm98-0.1.0/src/edm98/cli.py +227 -0
  8. edm98-0.1.0/src/edm98/constants.py +21 -0
  9. edm98-0.1.0/src/edm98/gradio_app.py +754 -0
  10. edm98-0.1.0/src/edm98/inference/__init__.py +15 -0
  11. edm98-0.1.0/src/edm98/inference/helpers.py +60 -0
  12. edm98-0.1.0/src/edm98/inference/labels.py +28 -0
  13. edm98-0.1.0/src/edm98/inference/model.py +191 -0
  14. edm98-0.1.0/src/edm98/inference/pipeline.py +603 -0
  15. edm98-0.1.0/src/edm98/inference/postprocess.py +93 -0
  16. edm98-0.1.0/src/edm98/loaders.py +85 -0
  17. edm98-0.1.0/src/edm98/resources/LICENSE +21 -0
  18. edm98-0.1.0/src/edm98/resources/__init__.py +5 -0
  19. edm98-0.1.0/src/edm98/resources/dataset.jsonl +98 -0
  20. edm98-0.1.0/src/edm98/resources/splits/__init__.py +1 -0
  21. edm98-0.1.0/src/edm98/resources/splits/test.txt +10 -0
  22. edm98-0.1.0/src/edm98/resources/splits/train.txt +79 -0
  23. edm98-0.1.0/src/edm98/resources/splits/val.txt +11 -0
  24. edm98-0.1.0/src/edm98/schema.py +151 -0
  25. edm98-0.1.0/src/edm98.egg-info/PKG-INFO +372 -0
  26. edm98-0.1.0/src/edm98.egg-info/SOURCES.txt +32 -0
  27. edm98-0.1.0/src/edm98.egg-info/dependency_links.txt +1 -0
  28. edm98-0.1.0/src/edm98.egg-info/entry_points.txt +2 -0
  29. edm98-0.1.0/src/edm98.egg-info/requires.txt +17 -0
  30. edm98-0.1.0/src/edm98.egg-info/top_level.txt +1 -0
  31. edm98-0.1.0/tests/test_cli.py +71 -0
  32. edm98-0.1.0/tests/test_inference_optional.py +15 -0
  33. edm98-0.1.0/tests/test_schema.py +35 -0
  34. edm98-0.1.0/tests/test_smoke.py +5 -0
edm98-0.1.0/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Creative Commons Attribution 4.0 International Public License
2
+
3
+ By exercising the Licensed Rights (defined below), You accept and agree
4
+ to be bound by the terms and conditions of this Creative Commons
5
+ Attribution 4.0 International Public License ("Public License").
6
+ To the extent this Public License may be interpreted as a contract,
7
+ You are granted the Licensed Rights in consideration of Your acceptance
8
+ of these terms and conditions, and the Licensor grants You such rights
9
+ in consideration of benefits the Licensor receives from making
10
+ the Licensed Material available under these terms and conditions.
11
+
12
+ You are free to:
13
+ - Share — copy and redistribute the material in any medium or format
14
+ - Adapt — remix, transform, and build upon the material for any purpose, even commercially.
15
+
16
+ Under the following terms:
17
+ - Attribution — You must give appropriate credit, provide a link to the license,
18
+ and indicate if changes were made. You may do so in any reasonable manner,
19
+ but not in any way that suggests the licensor endorses you or your use.
20
+
21
+ No additional restrictions — You may not apply legal terms or
22
+ technological measures that legally restrict others from doing
23
+ anything the license permits.
24
+
25
+ Full license text:
26
+ https://creativecommons.org/licenses/by/4.0/legalcode
edm98-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,372 @@
1
+ Metadata-Version: 2.4
2
+ Name: edm98
3
+ Version: 0.1.0
4
+ Summary: EDM-98 dataset package with optional EDMFormer inference tooling
5
+ Author: Sahal Sajeer Kalandan
6
+ License: CC-BY-4.0
7
+ Project-URL: Homepage, https://github.com/25ohms/EDM-98
8
+ Project-URL: Repository, https://github.com/25ohms/EDM-98
9
+ Project-URL: Issues, https://github.com/25ohms/EDM-98/issues
10
+ Project-URL: Paper, https://arxiv.org/abs/2603.08759
11
+ Keywords: music,dataset,edm,structure-analysis,audio
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ License-File: src/edm98/resources/LICENSE
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=8.0; extra == "dev"
27
+ Requires-Dist: ruff>=0.11.0; extra == "dev"
28
+ Requires-Dist: PyYAML>=6.0; extra == "dev"
29
+ Provides-Extra: inference
30
+ Requires-Dist: PyYAML>=6.0; extra == "inference"
31
+ Requires-Dist: torch>=2.4.0; extra == "inference"
32
+ Requires-Dist: librosa>=0.11.0; extra == "inference"
33
+ Requires-Dist: omegaconf>=2.3.0; extra == "inference"
34
+ Requires-Dist: safetensors>=0.5.3; extra == "inference"
35
+ Requires-Dist: x-transformers>=2.4.14; extra == "inference"
36
+ Requires-Dist: scipy>=1.15.0; extra == "inference"
37
+ Provides-Extra: ui
38
+ Requires-Dist: gradio>=5.0; extra == "ui"
39
+ Dynamic: license-file
40
+
41
+ # EDM-98
42
+
43
+ `EDM-98` packages the EDM-98 dataset and an optional EDMFormer-based inference stack for local experimentation, app development, and downstream tooling.
44
+
45
+ ## What Is Included
46
+
47
+ - the canonical EDM-98 label artifact packaged with the module
48
+ - canonical split files packaged with the module
49
+ - a lightweight Python package for dataset loading and validation
50
+ - an optional inference pipeline for EDMFormer
51
+ - a CLI for validation, prediction, cache warming, and demo launch
52
+ - a Gradio app with a waveform timeline and color-coded section predictions
53
+
54
+ ## Dataset
55
+
56
+ EDM-98 was created from a curated 98-song set with Rekordbox cue-point labeling. The original dataset artifact was created as JSON and later converted to JSONL to match the label-file format expected by the SongFormer architecture.
57
+
58
+ The dataset and split files are loaded from packaged resources inside `edm98`, under `src/edm98/resources/`. That packaged copy is the canonical source used by the Python API and PyPI distribution.
59
+
60
+ The primary labels exposed by the EDMFormer setup are:
61
+
62
+ - `intro`
63
+ - `buildup`
64
+ - `drop`
65
+ - `breakdown`
66
+ - `outro`
67
+ - `silence`
68
+
69
+ Each packaged dataset record currently includes:
70
+
71
+ - `id`: the Deezer track identifier used as the canonical record ID
72
+ - `labels`: a strictly increasing list of `[time, label]` pairs terminated by `end`
73
+ - `file_path`: the original filename used during labeling when available
74
+
75
+ For local preprocessing and training, the canonical audio contract is that each downloaded song is stored as `<deezer_id>.<ext>`, for example `1060564312.mp3`. `file_path` is preserved as provenance metadata, not as the primary lookup key.
76
+
77
+ The package does not redistribute the audio itself. The Deezer IDs are included so users can map the metadata back to externally downloaded audio.
78
+
79
+ ## Accessing The Dataset
80
+
81
+ Load the canonical packaged dataset:
82
+
83
+ ```python
84
+ from edm98.loaders import load_dataset_records, load_all_splits, load_records_by_split
85
+
86
+ records = load_dataset_records()
87
+ splits = load_all_splits()
88
+ train_records = load_records_by_split("train")
89
+ ```
90
+
91
+ Example record shape:
92
+
93
+ ```python
94
+ {
95
+ "id": "1060564312",
96
+ "labels": [
97
+ (0.054, "intro"),
98
+ (35.942, "buildup"),
99
+ (58.38, "silence"),
100
+ (62.866, "drop"),
101
+ ...
102
+ (247.0, "end"),
103
+ ],
104
+ "file_path": "01 - Oak - Airwalk.mp3",
105
+ }
106
+ ```
107
+
108
+ If you have downloaded the corresponding audio externally, you can join the metadata back to a local music directory by Deezer ID. For example:
109
+
110
+ ```python
111
+ from pathlib import Path
112
+
113
+ from edm98.loaders import load_dataset_records
114
+
115
+ audio_dir = Path("/path/to/downloaded/audio")
116
+ records = load_dataset_records()
117
+ extensions = (".mp3", ".wav", ".flac", ".m4a")
118
+
119
+ for record in records:
120
+ for ext in extensions:
121
+ candidate = audio_dir / f"{record['id']}{ext}"
122
+ if candidate.exists():
123
+ print(record["id"], candidate, record["labels"][:3])
124
+ break
125
+ ```
126
+
127
+ This assumes you have already acquired the audio separately. `edm98` provides the labels, IDs, and split definitions; it does not fetch or ship the songs.
128
+
129
+ ## Training Preparation
130
+
131
+ `edm98` is primarily a dataset package, but the packaged labels and split files can also be used as the canonical dataset-side inputs for EDMFormer-style training.
132
+
133
+ The repository includes a simple notebook at `notebooks/edm98_training_prep.ipynb` that shows:
134
+
135
+ - how to load the packaged metadata and split IDs
136
+ - how to map dataset records back to externally downloaded audio
137
+ - how to structure the four embedding directories EDMFormer expects
138
+ - how to construct the minimal train/eval dataset configuration
139
+
140
+ The audio itself is still external. A typical flow is:
141
+
142
+ 1. Install `edm98` and load the packaged records.
143
+ 2. Download the songs separately using the provided Deezer IDs and store them as `<deezer_id>.<ext>`.
144
+ 3. Generate the MuQ and MusicFM embeddings required by EDMFormer.
145
+ 4. Point your training configuration at the packaged JSONL labels and split files.
146
+
147
+ Minimal example:
148
+
149
+ ```python
150
+ from pathlib import Path
151
+
152
+ from edm98.loaders import load_records_by_split
153
+
154
+ audio_dir = Path("/path/to/downloaded/audio")
155
+ train_records = load_records_by_split("train")
156
+ extensions = (".mp3", ".wav", ".flac", ".m4a")
157
+
158
+ resolved = []
159
+ for record in train_records:
160
+ for ext in extensions:
161
+ candidate = audio_dir / f"{record['id']}{ext}"
162
+ if candidate.exists():
163
+ resolved.append(
164
+ {
165
+ "id": record["id"],
166
+ "audio_path": candidate,
167
+ "labels": record["labels"],
168
+ }
169
+ )
170
+ break
171
+
172
+ resolved[:2]
173
+ ```
174
+
175
+ That resolved list is the starting point for a preprocessing step that generates the EDMFormer-compatible MuQ and MusicFM embedding directories used during training.
176
+
177
+ ## Installation
178
+
179
+ ### Dataset-only
180
+
181
+ ```bash
182
+ pip install edm98
183
+ ```
184
+
185
+ ### Inference
186
+
187
+ ```bash
188
+ git clone https://github.com/25ohms/EDM-98.git
189
+ cd EDM-98
190
+ ./scripts/install_inference_deps.sh
191
+ pip install -e ".[ui]"
192
+ export MUSICFMPATH="$PWD/third_party/musicfm"
193
+ ```
194
+
195
+ `third_party/musicfm` is provisioned locally by the install script because upstream MusicFM is not published as an installable Python package. The same script also installs MuQ from its upstream source repository. Set `MUSICFMPATH` to that checkout when using the optional local inference workflow.
196
+
197
+ ## Checkpoints And Cache
198
+
199
+ Expected local inference assets:
200
+
201
+ - `data/checkpoints/model.pt`
202
+ - `data/checkpoints/pretrained_msd.pt`
203
+ - `data/checkpoints/msd_stats.json`
204
+ - `configs/edmformer.yaml`
205
+
206
+ MuQ and MusicFM also depend on Hugging Face-backed upstream assets. Those are cached automatically under `.cache/huggingface/` on first use and reused on later runs.
207
+
208
+ Optional cache commands:
209
+
210
+ ```bash
211
+ python -m edm98.cli warm-cache
212
+ python -m edm98.cli predict --offline path/to/song.mp3
213
+ python -m edm98.cli predict --no-cache path/to/song.mp3
214
+ ```
215
+
216
+ ## CLI
217
+
218
+ Validate the dataset:
219
+
220
+ ```bash
221
+ python -m edm98.cli validate-dataset
222
+ ```
223
+
224
+ Run inference on one file:
225
+
226
+ ```bash
227
+ python -m edm98.cli predict --device cuda --low-memory path/to/song.mp3
228
+ ```
229
+
230
+ Launch the Gradio demo:
231
+
232
+ ```bash
233
+ python -m edm98.cli demo --device cuda --server-name 0.0.0.0 --server-port 7860
234
+ ```
235
+
236
+ ## Gradio Demo
237
+
238
+ The Gradio app uses the same inference backend as the CLI and preloads the inference pipeline when the app starts. That pipeline stays alive until the process exits, so the app does not rebuild the full EDMFormer, MuQ, and MusicFM stack for every request.
239
+
240
+ The demo is intentionally persistent. Start it once, keep the process running, and reuse the loaded pipeline until you close the app.
241
+
242
+ The demo currently provides:
243
+
244
+ - a file upload flow
245
+ - a full-width color-coded waveform timeline
246
+ - labeled section regions
247
+ - a moving playback cursor
248
+ - a tabular view of predicted sections with minute-second timestamps
249
+
250
+ To launch the demo:
251
+
252
+ ```bash
253
+ ./scripts/install_inference_deps.sh
254
+ pip install -e ".[ui]"
255
+ export MUSICFMPATH="$PWD/third_party/musicfm"
256
+ python -m edm98.cli demo --device cuda --server-name 0.0.0.0 --server-port 7860
257
+ ```
258
+
259
+ If you are running on a remote machine, expose or forward the chosen port and open the forwarded local URL in your browser.
260
+
261
+ ### Demo Options
262
+
263
+ Useful demo flags:
264
+
265
+ - `--device auto`: pick the best available backend automatically
266
+ - `--device cuda`: run on an NVIDIA GPU
267
+ - `--device mps`: run on Apple Silicon via Metal
268
+ - `--device cpu`: force CPU inference
269
+ - `--server-name 0.0.0.0`: bind on all interfaces so you can forward or expose the port
270
+ - `--server-port 7860`: choose a different port if needed
271
+ - `--offline`: require Hugging Face-backed assets to already exist in the local cache
272
+ - `--no-cache`: use a temporary cache directory for this run
273
+ - `--hf-cache-dir <path>`: override the default Hugging Face cache location
274
+
275
+ `--low-memory` is useful for one-off CLI prediction runs, but it is not the intended mode for the Gradio demo. The demo is designed to keep its models resident until shutdown.
276
+
277
+ ## Platform Notes
278
+
279
+ The CLI currently supports `--device auto`, `--device cpu`, `--device cuda`, and `--device mps`.
280
+
281
+ ### Linux
282
+
283
+ Linux is the most straightforward setup for GPU-backed demo usage.
284
+
285
+ - NVIDIA GPU: use `--device cuda`
286
+ - CPU-only: use `--device cpu`
287
+ - Typical demo launch:
288
+
289
+ ```bash
290
+ ./scripts/install_inference_deps.sh
291
+ pip install -e ".[ui]"
292
+ export MUSICFMPATH="$PWD/third_party/musicfm"
293
+ python -m edm98.cli demo --device cuda --server-name 0.0.0.0 --server-port 7860
294
+ ```
295
+
296
+ ### macOS
297
+
298
+ On Apple Silicon, use Metal via `--device mps`.
299
+
300
+ - Apple Silicon demo launch:
301
+
302
+ ```bash
303
+ ./scripts/install_inference_deps.sh
304
+ pip install -e ".[ui]"
305
+ export MUSICFMPATH="$PWD/third_party/musicfm"
306
+ python -m edm98.cli demo --device mps --server-name 127.0.0.1 --server-port 7860
307
+ ```
308
+
309
+ - If MPS is unavailable or unstable in your local environment, fall back to `--device cpu`
310
+
311
+ ### Windows
312
+
313
+ The supported install helper in this repository is `scripts/install_inference_deps.sh`, which is a Bash script. Because of that, the smoothest Windows path is currently a Bash-compatible environment such as WSL2 or Git Bash, with WSL2 being the more predictable choice for ML dependencies.
314
+
315
+ - Windows + WSL2 + NVIDIA GPU: use `--device cuda`
316
+ - Windows + WSL2 CPU-only: use `--device cpu`
317
+ - If you want a browser on Windows to access a demo running inside WSL2, open the forwarded localhost URL from Windows after launch
318
+
319
+ If you are running a fully native Windows Python environment instead of WSL2, the same CLI flags apply, but you will need to reproduce the install-script steps manually.
320
+
321
+ ## Python API
322
+
323
+ For one-off inference:
324
+
325
+ ```python
326
+ from edm98.inference import predict_file
327
+
328
+ prediction = predict_file("song.mp3", device="cuda", low_memory=True)
329
+ ```
330
+
331
+ For app integration or repeated use, create the pipeline once and reuse it:
332
+
333
+ ```python
334
+ from edm98.inference import create_pipeline
335
+
336
+ pipeline = create_pipeline(
337
+ device="cuda",
338
+ persistent_models=True,
339
+ )
340
+
341
+ prediction = pipeline.predict_file("song.mp3")
342
+ ```
343
+
344
+ This is the same pattern used by the Gradio app.
345
+
346
+ ## Developer Notes
347
+
348
+ - `predict` is suitable for single-use command-line workflows.
349
+ - `InferencePipeline` is the stable object to reuse inside other applications.
350
+ - `create_pipeline(...)` is provided as a small convenience wrapper for app startup code.
351
+ - the current repo-local cache behavior is the default and should remain transparent to most users
352
+
353
+ ## Validation
354
+
355
+ Dataset validation:
356
+
357
+ ```bash
358
+ python -m edm98.cli validate-dataset
359
+ ```
360
+
361
+ Test suite:
362
+
363
+ ```bash
364
+ pytest -q
365
+ ```
366
+
367
+ ## Licensing
368
+
369
+ This repository uses separate licenses by component:
370
+
371
+ - repository code and model-related materials: CC BY 4.0
372
+ - packaged dataset metadata and split files: MIT