Maurice — Attribute-Conditioned 🎹🎛️

⚠️ This is a symbolic (MIDI) model — not an audio model

Maurice generates note events — pitch, onset, duration, velocity — and writes a .mid file. It does not generate waveforms, and it does not take audio as input. There is no vocoder, no spectrogram, no .wav anywhere in the pipeline.

To hear the output you render the MIDI yourself, with a SoundFont (FluidSynth), a sampled piano library (SFZ/Kontakt), or any synth or DAW. The quality of what you hear therefore depends heavily on the piano you render it through — the same file can sound thin through a GM font and gorgeous through a good sampled grand.

If you want text-to-audio music generation, this is not that kind of model — look at MusicGen, Stable Audio or similar. Maurice is closer in kind to a composer writing a score than to a recording of one.

An attribute-conditioned fine-tune of Maurice, the ~300M from-scratch romantic-piano cold-start model. The base model takes composer + key; this one adds nine musical attribute dials, so a brief written in natural language ("a shimmering wave that descends, dark and stormy") can be mapped to structured conditioning and realised section by section.

This is the checkpoint that actually drives an end-to-end composition pipeline — see The architecture around the model below.

  • Base: Maurice at step 37,000 (val ppl ≈ 2.96)
  • This fine-tune: step 8,000, val loss 1.168, LoRA (r64, attn+MLP) merged into the weights
  • Vocab: 17,832 = base 17,785 + 47 attribute tokens (ids 17785–17831)
  • Architecture: unchanged from base — Qwen3-style decoder, 16 layers, d=1280, 20 heads / 4 KV heads, 4096 context, ~298M params

The nine attributes

attribute values
register bass · low · mid · high · brilliant
range narrow · moderate · wide
density sparse · moderate · dense · torrential
polyphony single-line · mixed · chordal
contour ascending · descending · arch · valley · wave · static
motion still · flowing · active · agitated
dynamics hushed · soft · medium · loud · thunderous
articulation staccato · detached · legato
color dark · shadowed · neutral · warm · bright

Any attribute may be omitted — it falls back to its any token. Bins were derived from percentiles of the real corpus rather than hand-picked thresholds; hand-picked ones left several bins (e.g. dynamics: thunderous) effectively unreachable.

How it works

Training sequences interleave attribute markers with the music:

[instr, composer, key, <S>, A1, chunk1, A2, chunk2, ..., <E>]

where each Ai is 9 attribute tokens describing the following ~6-second chunk. One formulation teaches both cold-start (A1 → chunk1) and continuation (context + Ai → chunk_i), which is what makes section-by-section building possible.

Inference seed: [instr, composer, key, <S>] + [9 attribute tokens]. Attribute and prefix ids must be masked from sampling and stripped before detokenizing.

Files

file what
model.safetensors weights, fp32 (~1.2 GB), tied embeddings — this is step 8000, the final checkpoint
config.json architecture + conditioning config
attr_meta.json attribute schema, token ids, composer/key maps
model_qwen.py model definition
attr_sample.py / attr_dials.py sampling with attribute conditioning
poly_server.py HTTP server: cold-start + plan-driven compose
attributes.py / derive_bins.py attribute extraction and percentile bin derivation
train_attr.py / prep_attr.py / run_attr.sh fine-tuning pipeline
ckpt_attr_7500.pt best-val training checkpoint (step 7500) in original .pt form

Hear it

Elegy in C-sharp minor — 608 notes composed by the model, then performed. The same notes twice:

▶ as the model composed it raw output: no pedal, flat velocities, everything square on the beat
▶ after a performance pass identical pitches; only voicing, rolls, rubato and pedal differ

Play those back to back. It's the fastest way to hear what this model gives you and what it doesn't, and why we think dry-sounding symbolic output is usually unperformed rather than badly composed. Source MIDI is in output_examples/.

Prior art & lineage

Maurice stands on other people's work, and it's worth being precise about what came from where.

Aria (loubb/aria-medium-base, aria-utils) is the closest ancestor: Maurice uses Aria's AbsTokenizer unchanged and trains on the Aria-MIDI corpus. The models are complements, not competitors — Aria continues existing material; Maurice cold-starts from silence, which a continuation model structurally cannot do. Shared tokenizer means the outputs interoperate directly.

GiantMIDI-Piano (Kong, Li, Song, Hantrakul & Wang, ByteDance) supplied a wide slice of classical/romantic repertoire — ~10k works transcribed from audio — and is much of the reason the composer conditioning has range rather than a narrow canon.

MAESTRO (Hawthorne et al., Google Magenta) contributed ~200 hours of aligned virtuoso performance. Being performed rather than quantized, it is disproportionately responsible for whatever expressive micro-timing the model has absorbed.

Broader lineage: Music Transformer (Huang et al.), the Anticipatory Music Transformer (Thickstun et al.), and score-level systems like SymphonyNet and NotaGen. For the performance layer discussed below: VirtuosoNet (Jeong et al.), the Vienna Basis Mixer (Cancino-Chacón, Grachten, Widmer), the KTH performance rules (Friberg, Sundberg, Bresin), and ASAP for score↔performance alignment.

The architecture around the model

Weights alone give you notes, not music. This checkpoint was built to sit inside a pipeline:

brief
  │
  ▼  PLAN        germ motif, section arc, per-section attribute targets, where the climax lands
  ▼  MAURICE     composes EVERY note, plan-driven — states a theme, develops it
  │              (fragment / invert / transpose / augment), returns it transformed
  ▼  GATE        verifies ADHERENCE to the plan — arithmetic only, never taste
  ▼  PERFORMER   an interpreter plays it: voicing, rolls, rubato, dynamics, pedal
  │              — pitches strictly preserved, everything else decided
  ▼  RENDER      MIDI → sampled piano

Three findings worth stating plainly, because they'll save you time:

1. Composition and performance are separate layers, and performance carries an enormous share of perceived quality. Testable both ways: take a piece that sounds good, quantize onsets to a grid and flatten velocities — same pitches — and it collapses into mush; take a raw "dry" model output and genuinely perform it — same pitches — and it comes alive. A dry generation is usually not a composition failure but an unperformed one. Judge symbolic output only after something has played it.

2. Rolled chords and rubato are acoustics, not decoration. Staggering a chord's attacks by 20–70 ms spreads beating partials out in time and measurably lowers sensory roughness. Expressive micro-timing and "sounds less muddy" are the same phenomenon — which is why quantizing a dense passage makes it rougher, not merely stiffer.

3. Structure must be imposed from outside. With a 4096-token context (~2–3 min) and no notion of overall arc, the model needs an explicit plan — capture a theme, develop it under named transformations, return it — to become something with a beginning, middle and end. For material longer than the context, carry the captured theme into the next span so later sections keep developing the same germ.

Limitations

  • It can reproduce training data. The most important caveat, and measurable: screening generations against the training corpus with exact 12-interval melodic matching, most come back clean, but a minority quote one training file heavily — in a measured Liszt sample, 40 exact windows (~31% of the piece) traced to a single Aria-MIDI file. Incompletely deduplicated sources (Aria-MIDI documents this) and over-represented works both contribute. Screen anything you intend to publish or perform; do not assume novelty.
  • Attribute conditioning is real but soft — and density is effectively non-functional. Measured across explicit density requests and repeated resampling, output lands in a narrow band regardless of the dial, and "sparse" is as likely to come out dense as the reverse. Register, color and dynamics steer more reliably. Get contrast from tempo, key, register and character, not from the density dial.
  • ~2–3 minutes is its natural form. Coherent within the context window; stretched much further, one unvarying texture reads as sameness rather than voice. Prefer a multi-movement suite with real tempo/key contrast between movements.
  • Uneven composers — bold, well-represented ones (Liszt, Chopin, Debussy, Scriabin, Ravel) condition best; subtler ones drift toward a generic-romantic center.
  • Solo piano only; symbolic MIDI output (render with your own SoundFont/synth).

Data & license provenance

Trained on transcribed/curated solo-piano MIDI — Aria-MIDI, GiantMIDI-Piano and MAESTRO — plus period-romantic pieces of unknown authorship (the unknown token), with ×12 transposition augmentation. Uses Aria's AbsTokenizer.

License: CC BY-NC-SA 4.0 — a non-commercial research release, matching the most restrictive of the training sources (MAESTRO is CC BY-NC-SA 4.0; Aria-MIDI and GiantMIDI carry research/non-commercial terms). See LICENSE.

Citation

@misc{maurice_attr2026,
  title  = {Maurice (attribute-conditioned): controllable romantic-piano cold-start},
  year   = {2026},
  note   = {Attribute fine-tune of the 298M Qwen3-style Maurice decoder; 9 musical dials, 47 added tokens}
}
Downloads last month
49
Safetensors
Model size
0.3B params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for roygbiv33/Maurice-Attr

Finetuned
(1)
this model