Skip to content

Commit 13cc57d

Browse files
authored
Prepare v1.1.0 release (#8)
2 parents cae46b3 + 2be4d61 commit 13cc57d

13 files changed

Lines changed: 251 additions & 85 deletions

File tree

README.md

Lines changed: 167 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# SyMuPe: Affective and Controllable Symbolic Music Performance
22

3-
<img alt="PianoFlow architecture" src="assets/pianoflow.png">
4-
53
> Official release for the paper [**"SyMuPe: Affective and Controllable Symbolic Music Performance"**](https://dl.acm.org/doi/10.1145/3746027.3755871)
64
> (**ACM MM 2025 Outstanding Paper Award**)
75
>
@@ -13,8 +11,7 @@
1311
> [![ACM DL](https://img.shields.io/badge/MM_'25-Proceedings-19552e?logo=acm&logoColor=white)](https://dl.acm.org/doi/10.1145/3746027.3755871)
1412
> [![Outstanding Paper Award](https://img.shields.io/badge/MM_'25-Outstanding_Paper-E6712D.svg)](https://acmmm2025.org/awards/)
1513
> [![Website](https://img.shields.io/badge/Website-Demo-2563eb)](https://ilya16.github.io/SyMuPe)
16-
> [![Models](https://img.shields.io/badge/HuggingFace-Models-yellow?logo=huggingface)](https://huggingface.co/SyMuPe)
17-
> [![Dataset](https://img.shields.io/badge/HuggingFace-Dataset-yellow?logo=huggingface)](https://huggingface.co/datasets/SyMuPe/PERiScoPe)
14+
> [![HF](https://img.shields.io/badge/HuggingFace-Models_&_Data-yellow?logo=huggingface)](https://huggingface.co/SyMuPe)
1815
1916
## Description
2017

@@ -27,71 +24,194 @@ For more details, please refer to the [paper](https://arxiv.org/abs/2511.03425)
2724

2825
## Install
2926

30-
Install the `symupe` package using:
27+
Install `symupe` package using:
3128
```shell
32-
pip install symupe
29+
pip install -U symupe
3330
```
3431

35-
## Models in the SyMuPe Framework
32+
## Models
33+
34+
Starting with v1.1.0, SyMuPe supports a *unified inference API* for the trained symbolic music models.
35+
36+
All models are grouped into three categories:
37+
1. **Generators** (e.g. `PerformanceGenerator`)
38+
2. **Classifiers** (e.g. `MusicClassifier`)
39+
3. **Embedders** (e.g. `MusicEmbedder`)
40+
41+
The models can be loaded using the corresponding `AutoFactory` classes (`AutoGenerator`, `AutoClassifier`, or `AutoEmbedder`).
42+
43+
The trained models are available and documented on the [Hugging Face Hub](https://huggingface.co/SyMuPe).
44+
45+
### Score-to-Performance Rendering
3646

37-
Score-only models described in the paper are available on the [Hugging Face Hub](https://huggingface.co/SyMuPe).
47+
<img alt="PianoFlow architecture" src="https://raw.githubusercontent.com/ilya16/SyMuPe/main/assets/pianoflow.png">
48+
49+
Score-only performance rendering models described in the paper are listed in the [SyMuPe (ACM MM'25) Collection](https://huggingface.co/collections/SyMuPe/symupe-acm-mm25) on Hugging Face.
3850

3951
| Model Repo | Type | Objective | Description |
4052
|:---|:---------------------------|:---|:--------------------------------------------|
4153
| [**PianoFlow-base**](https://huggingface.co/SyMuPe/PianoFlow-base) | Encoder Transformer | CFM | Flagship model for high-fidelity rendering |
4254
| [**EncDec-base**](https://huggingface.co/SyMuPe/EncDec-base) | Encoder-Decoder Transformer | CLM | Slower sequence-to-sequence baseline |
4355
| [**MLM-base**](https://huggingface.co/SyMuPe/MLM-base) | Encoder Transformer | MLM | Fast single-step language modeling baseline |
4456

45-
## Quick Start
57+
#### Quick Start
4658

47-
Render an expressive performance from a quantized MIDI score in just a few lines of code.
59+
Render an expressive performance from a quantized MIDI score using an example code snippet:
4860

4961
```python
5062
import torch
51-
from symusic import Score
52-
53-
from symupe.data.tokenizers import SyMuPe
54-
from symupe.inference import AutoGenerator, perform_score, save_performances
55-
from symupe.models import AutoModel
63+
from symupe import AutoGenerator
5664

5765
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
5866

59-
# Load the model and tokenizer directly from the Hub
67+
# Select model name from the Hub
6068
model_name = "SyMuPe/PianoFlow-base"
6169
# model_name = "SyMuPe/EncDec-base"
6270
# model_name = "SyMuPe/MLM-base"
6371

64-
model = AutoModel.from_pretrained(model_name).to(device)
65-
tokenizer = SyMuPe.from_pretrained(model_name)
66-
67-
# Prepare generator for the model
68-
generator = AutoGenerator.from_model(model, tokenizer, device=device)
69-
70-
# Load score MIDI
71-
score_midi = Score("score.mid")
72+
# Build Generator by loading the model and tokenizer directly from the Hub
73+
generator = AutoGenerator.from_pretrained(model_name, device=device)
7274

7375
# Perform score MIDI (tokenization is handled inside)
74-
gen_results = perform_score(
75-
generator=generator,
76-
score=score_midi,
76+
gen_results = generator.perform_score(
77+
"score.mid",
7778
use_score_context=True,
7879
num_samples=8,
79-
seed=23
80+
seed=23,
8081
)
8182
# gen_results[i] is PerformanceRenderingResult(...) containing:
8283
# - score_midi, score_seq, gen_seq, perf_seq, perf_midi, perf_midi_sus
8384

8485
# Save performed MIDI files in a single directory
85-
save_performances(gen_results, out_dir="samples")
86+
generator.save_performances(gen_results, out_dir="samples")
87+
```
8688

89+
### MIDI Quality Classification
90+
91+
The [MIDI Quality Classifier](https://huggingface.co/SyMuPe/MIDI-Quality-Classifier) can be used to classify a MIDI file
92+
into one of the four quality classes: `score`, `high quality`, `low quality`, or `corrupted`.
93+
94+
The classifier was presented in the article [**"PianoCoRe: Combined and Refined Piano MIDI Dataset."**](https://doi.org/10.5334/tismir.333)
95+
96+
#### Quick Start
97+
98+
```python
99+
import torch
100+
from symupe import AutoClassifier
101+
102+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
103+
104+
# Build Classifier by loading the model and tokenizer directly from the Hub
105+
classifier = AutoClassifier.from_pretrained(
106+
"SyMuPe/MIDI-Quality-Classifier", device=device,
107+
)
108+
# model, tokenizer, labels = classifier.model, classifier.tokenizer, classifier.labels
109+
110+
# Classify MIDI (tokenization is handled inside)
111+
result = classifier("performance.mid")
112+
# result is MusicClassificationResult(...) containing:
113+
# - midi, seq, probabilities, prediction, label, all_logits, all_probabilities, all_predictions,
114+
# sequences and window_indices
115+
print(result.label, result.probabilities)
87116
```
88117

89-
## Dataset
118+
## Datasets and Data Processing
119+
120+
The SyMuPe project provides two MIDI datasets for analysing and modeling piano expression:
121+
1. The [**PERiScoPe**](https://huggingface.co/datasets/SyMuPe/PERiScoPe) **(Piano Expression Refined Score and Performance MIDI)** dataset, used to train the models in the [SyMuPe paper](https://arxiv.org/abs/2511.03425).
122+
2. The [**PianoCoRe**](https://github.com/ilya16/PianoCoRe) **(Combined and Refined Piano MIDI)** dataset, presented in the eponymous article published in the [TISMIR journal](https://doi.org/10.5334/tismir.333).
123+
124+
### Refined Alignment for Scores and Performances
90125

91-
The **PERiScoPe** (Piano Expression Refined Score and Performance MIDI) dataset used to train the models is available on [Hugging Face](https://huggingface.co/datasets/SyMuPe/PERiScoPe).
126+
The refined subset of PianoCoRe was constructed using the **Refined Alignment for Scores and Performances (RAScoP)** pipeline,
127+
integrated into the SyMuPe package in v1.1.0. The algorithm is described in the [article](https://doi.org/10.5334/tismir.333).
128+
129+
#### Quick Start
130+
131+
Use the following quick start code to align the score and performance MIDI:
132+
```python
133+
from symupe.data.alignments import ParangonarAligner, RAScoPConfig, RAScoP
134+
135+
score_midi_path = "score.mid"
136+
perf_midi_path = "performance.mid"
137+
138+
# Align performance to score
139+
aligner = ParangonarAligner()
140+
alignment, paths, msgs = aligner.align(score_midi_path, perf_midi_path)
141+
142+
# Initialize RAScoP
143+
config = RAScoPConfig(
144+
score_holes=True,
145+
performance_holes=True,
146+
clean_onsets=True,
147+
interpolate_notes=True,
148+
synchronize_performance=False,
149+
min_recall=0.7,
150+
num_runs=1,
151+
)
152+
rascop = RAScoP(
153+
score_midi=score_midi_path,
154+
perf_midi=perf_midi_path,
155+
alignment=alignment,
156+
config=config,
157+
verbose=1,
158+
)
159+
160+
# Refine raw alignment
161+
alignment, match_ratios, stage_times = rascop()
162+
perf_midi, score_midi = rascop.perf_midi, rascop.score_midi # refined MIDI
163+
print(match_ratios)
164+
```
165+
166+
Additional usage examples are available in the [PianoCoRe repository](https://github.com/ilya16/PianoCoRe).
167+
168+
The RAScoP pipeline expects both the score and the performance MIDI files to be single-track.
169+
During initialization, all tracks are merged and duplicate notes are removed by default.
170+
For any other preprocessing, use `symupe.data.midi.preprocess_midi`:
171+
```python
172+
from symusic import Score
173+
from symupe.data.midi import preprocess_midi
174+
175+
midi = Score("score.mid")
176+
midi = preprocess_midi(
177+
midi,
178+
to_single_track=True,
179+
clean_duplicates=True,
180+
cut_overlapped_notes=True,
181+
clean_short_notes=True,
182+
min_tick_shift=10,
183+
min_tick_duration=5,
184+
target_ticks_per_quarter=480,
185+
)
186+
midi.dump_midi("score_processed.mid")
187+
```
188+
189+
### MusicXML to MIDI conversion
190+
191+
SyMuPe provides utilities for working with MusicXML files. The code extends [partitura](https://github.com/CPJKU/partitura)
192+
by supporting the processing of duplicate and overlapping notes, expansion of grace notes, and deduplication of ornament notes,
193+
as described in the [PianoCoRe article](https://doi.org/10.5334/tismir.333).
194+
195+
Use `symupe.data.partitura.partitura_score_to_midi`, to convert score files to MIDI similar to the PERiScoPe/PianoCoRe datasets:
196+
```python
197+
import partitura as pt
198+
from symupe.data.partitura import partitura_score_to_midi
199+
200+
score = pt.load_score("score.musicxml")
201+
midi = partitura_score_to_midi(
202+
score,
203+
expand_grace_notes=True,
204+
process_ornaments=True,
205+
clean_duplicates=True,
206+
cut_overlapped_notes=True,
207+
downsample_ticks_per_quarter=48,
208+
ticks_per_quarter=480,
209+
)
210+
```
92211

93212
## Citation
94213

214+
If you use the package, models or the PERiScoPe dataset in your research, please cite:
95215
```bibtex
96216
@inproceedings{borovik2025symupe,
97217
title = {{SyMuPe: Affective and Controllable Symbolic Music Performance}},
@@ -103,8 +223,22 @@ The **PERiScoPe** (Piano Expression Refined Score and Performance MIDI) dataset
103223
}
104224
```
105225

226+
If you use the PianoCoRe dataset or the RAScoP pipeline for data processing, please cite:
227+
```bibtex
228+
@article{borovik2026pianocore,
229+
title = {{PianoCoRe: Combined and Refined Piano MIDI Dataset}},
230+
author = {Borovik, Ilya},
231+
year = {2026},
232+
journal = {Transactions of the International Society for Music Information Retrieval},
233+
volume = {9},
234+
number = {1},
235+
pages = {144--163},
236+
doi = {10.5334/tismir.333}
237+
}
238+
```
239+
106240
## License
107241

108242
- The **source code** in this repository is licensed under the [Apache License 2.0](LICENSE).
109-
- The **pre-trained model weights** and the **PERiScoPe dataset** are licensed under
110-
[Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International](LICENSE-DATA).
243+
- The **trained model weights** and the **datasets** are licensed under
244+
[CC BY-NC-SA 4.0](LICENSE-DATA) license.

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "symupe"
7-
version = "1.0.0"
7+
version = "1.1.0"
88
description = "SyMuPe: Symbolic Music Performance modeling framework"
99
readme = { file = "README.md", content-type = "text/markdown" }
1010
requires-python = ">=3.10"
@@ -23,7 +23,7 @@ keywords = [
2323
"expressive performance"
2424
]
2525
classifiers = [
26-
"Development Status :: 4 - Beta",
26+
"Development Status :: 5 - Production/Stable",
2727
"Intended Audience :: Developers",
2828
"Intended Audience :: Science/Research",
2929
"License :: OSI Approved :: Apache Software License",
@@ -45,6 +45,7 @@ dependencies = [
4545
"symusic>=0.5.8",
4646
"partitura>=1.8.0",
4747
"parangonar>=3.1.0",
48+
"pandas>=2.2.2",
4849
"omegaconf>=2.3.0",
4950
"loguru>=0.7.3",
5051
"tqdm>=4.66.0",

requirements.txt

Lines changed: 0 additions & 14 deletions
This file was deleted.

symupe/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
MAJOR = 1
2-
MINOR = 0
2+
MINOR = 1
33
PATCH = 0
44

55
VERSION = (MAJOR, MINOR, PATCH)

0 commit comments

Comments
 (0)