OSTINATO-3B-MULTI is a fine-tuned version of LLaMA 3.2 3B, specialized in symbolic music generation, multi-instrument co-composition, and Automatic Music Transcription (AMT). Trained on the Slakh2100 dataset (approx. 50,000 multi-track music arrangements), it enables users to generate, extend, interpolate, and orchestrate musical sequences using structured text tokens that translate directly into high-fidelity MIDI files.

OSTINATO-3B-MULTI — Documentation d'utilisation

Modèle : LLaMA 3.2 3B fine-tuné · LoRA r=32 · QLoRA 4-bit
Spécialité : Génération AMT multi-instrument (DRUMS, BASS, LEAD, CHORDS, AMB)
Source : Slakh2100 — ~50 000 exemples · 6 genres · BPM variable
Format de sortie : Séquence AMT delta-time multi-canal → convertible en MIDI multi-track


1. Format de prompt

Below is an instruction that describes a music task.

### Instruction:
{INSTRUCTION}

### Response:
<MUSIC>

Le modèle génère à la suite de <MUSIC> et s'arrête sur </s>.


2. Tags disponibles

Tags obligatoires

Tag Valeurs Description
[TASK:X] GEN JAM FIM COPILOT Type de tâche (voir §4)
[GENRE:X] POP_ROCK JAZZ ELECTRONIC CLASSICAL FOLK LATIN Style musical
[BPM:X] 40→240 (multiple de 5) Tempo — ex: 70, 90, 120, 128, 140
[MOOD:X] ENERGETIC CHILL DARK UPLIFTING MELANCHOLIC GROOVY EPIC DREAMY Ambiance
[BARS:X] 1→16 Nombre de mesures cibles
[DENSITY:X] SPARSE NORMAL DENSE Densité de notes
[COMPLEXITY:X] SIMPLE NORMAL COMPLEX Richesse harmonique et polyphonie

Tags optionnels

Tag Valeurs Description
[KEY:X_Y] 0→11 + MAJOR/MINOR Tonalité cible
[KEY_PRE:X_Y] idem Tonalité avant (FIM)
[KEY_SUF:X_Y] idem Tonalité après (FIM)

Correspondance des tonalités

Chiffre Note Chiffre Note
0 Do (C) 6 Fa# / Sol♭
1 Do# / Ré♭ 7 Sol (G)
2 Ré (D) 8 Sol# / La♭
3 Ré# / Mi♭ 9 La (A)
4 Mi (E) 10 La# / Si♭
5 Fa (F) 11 Si (B)

Guide MOOD → vélocité MIDI

MOOD Vélocité min Vélocité max Usage typique
ENERGETIC 80 127 Rock, techno, festival
EPIC 85 127 Cinématique, orchestral
GROOVY 70 115 Funk, groove, danse
UPLIFTING 65 110 Pop positive
CHILL 40 85 Lo-fi, jazz calme
DREAMY 30 75 Ambient, electronica douce
MELANCHOLIC 35 80 Ballades, blues
DARK 45 95 Metal, techno sombre

3. Les cinq canaux AMT

OSTINATO-3B-MULTI génère simultanément plusieurs canaux entrelacés dans la même séquence :

Canal Code Rôle Programme GM Instruments typiques
IP_9 DRUMS Percussion Standard Kit Kick, snare, hihat, cymbale
IP_1 BASS Basse Acoustic Bass (32) Basse électrique, contrebasse
IP_0 LEAD Mélodie Grand Piano (0) Guitare solo, saxophone, synth lead
IP_2 CHORDS Harmonie String Ensemble (48) Piano, guitare rythmique, orgue
IP_3 AMB Nappes Pad Warm (91) Strings, pads de synthé

4. Les quatre tâches

GEN — Génération libre

Génère une séquence multi-instrument complète depuis zéro.

Format :

[TASK:GEN][GENRE:JAZZ][BPM:110][MOOD:CHILL][BARS:8][DENSITY:NORMAL][COMPLEXITY:NORMAL]

Avec tonalité :

[TASK:GEN][GENRE:POP_ROCK][BPM:120][MOOD:ENERGETIC][BARS:16][DENSITY:DENSE][COMPLEXITY:NORMAL][KEY:0_MAJOR]

JAM — Continuation avec contexte

Le modèle reçoit une séquence multi-instrument et génère la suite naturelle.

Format :

[TASK:JAM][GENRE:ELECTRONIC][BPM:128][MOOD:DARK][BARS:8][DENSITY:NORMAL][COMPLEXITY:NORMAL][KEY:9_MINOR] /CONTEXT {AMT_SEQUENCE}
  • La clé détectée dans le contexte est injectée automatiquement dans [KEY:X_Y]
  • La sortie doit contenir ≥ 2 canaux distincts

FIM — Fill-In-the-Middle

Le modèle génère le passage central à partir d'un début et d'une fin.

Format :

[TASK:FIM][GENRE:JAZZ][BPM:100][MOOD:MELANCHOLIC][BARS:12][DENSITY:SPARSE][COMPLEXITY:SIMPLE]
[KEY_PRE:9_MINOR][KEY_SUF:2_MINOR]
/SUF {AMT_SEQUENCE_FIN}
/PRE {AMT_SEQUENCE_DEBUT}

⚠️ Ordre critique : /SUF précède toujours /PRE dans l'instruction.

La réponse inclut :

[CONFIRME:9_MINOR->2_MINOR] /TARGET {AMT_SEQUENCE_GENEREE} </s>
  • [CONFIRME:X->Y] : transition harmonique détectée et confirmée
  • /TARGET : séquence générée pour combler le trou

COPILOT — Complétion instrumentale

Le modèle reçoit certains instruments joués et génère les instruments manquants.

Format :

[TASK:COPILOT][GENRE:JAZZ][BPM:100][MOOD:CHILL][BARS:8][DENSITY:NORMAL][COMPLEXITY:NORMAL][KEY:0_MAJOR]
/CONTEXT {AMT_SEQUENCE_INSTRUMENTS_FOURNIS}
/TARGET {INSTRUMENTS_A_GENERER}

Exemples de /TARGET :

Situation /TARGET
J'ai drums+chords, je veux basse+lead BASS,LEAD
J'ai basse+lead, je veux chords+nappes CHORDS,AMB
J'ai tout sauf drums DRUMS

5. Format AMT delta-time

Chaque note est un triplet de tokens :

A_{delta} D_{duration} IP_{canal}_{pitch}_{velocity}
Champ Description
A_{delta} Délai depuis la note précédente (ticks, grille 24) · A_0 = simultané
D_{duration} Durée de la note (ticks)
IP_{ch}_{pitch}_{vel} Canal + hauteur MIDI (0-127) + vélocité (0-127)

Correspondance ticks ↔ durées musicales

Ticks Durée Exemple
24 Triples croches (1/32) D_24
48 Double-croche (1/16) D_48
96 Croche (1/8) D_96
192 Noire (1/4) D_192
384 Blanche (1/2) D_384
480 Noire + liée D_480
960 Ronde (1/1) D_960
1920 Ronde double (max) D_1920

Exemple — Groove Jazz (drums + basse + chords simultanés)

A_0 D_24 IP_9_36_85        ← Kick (C2) — temps fort
A_0 D_480 IP_1_40_75       ← Basse (E2) — tenue longue
A_0 D_960 IP_2_60_62       ← Do (C4) chord
A_0 D_960 IP_2_64_58       ← Mi (E4) chord
A_0 D_960 IP_2_67_55       ← Sol (G4) chord
A_192 D_24 IP_9_42_70      ← Snare (F#2) — temps faible
A_192 D_480 IP_0_67_68     ← Mélodie Sol (G4)
A_288 D_24 IP_9_42_65      ← Snare

6. Exemples d'utilisation complets

Exemple 1 — GEN Jazz CHILL

instruction = (
    "[TASK:GEN][GENRE:JAZZ][BPM:110][MOOD:CHILL]"
    "[BARS:8][DENSITY:NORMAL][COMPLEXITY:NORMAL][KEY:9_MINOR]"
)

Exemple 2 — GEN Electronic DARK

instruction = (
    "[TASK:GEN][GENRE:ELECTRONIC][BPM:128][MOOD:DARK]"
    "[BARS:16][DENSITY:DENSE][COMPLEXITY:COMPLEX]"
)

Exemple 3 — GEN Pop Rock ENERGETIC

instruction = (
    "[TASK:GEN][GENRE:POP_ROCK][BPM:120][MOOD:ENERGETIC]"
    "[BARS:8][DENSITY:NORMAL][COMPLEXITY:NORMAL][KEY:0_MAJOR]"
)

Exemple 4 — JAM (continuation d'un groove)

context_amt = (
    "A_0 D_24 IP_9_36_85 A_0 D_480 IP_1_40_75 "
    "A_0 D_960 IP_2_60_62 A_0 D_960 IP_2_64_58 "
    "A_192 D_24 IP_9_42_70 A_192 D_480 IP_0_67_68 "
    "A_288 D_24 IP_9_42_65 A_288 D_240 IP_0_65_65"
)

instruction = (
    f"[TASK:JAM][GENRE:JAZZ][BPM:110][MOOD:CHILL]"
    f"[BARS:8][DENSITY:NORMAL][COMPLEXITY:NORMAL]"
    f"[KEY:9_MINOR] /CONTEXT {context_amt}"
)

Exemple 5 — FIM (transition La mineur → Ré mineur)

pre_amt = (
    "A_0 D_960 IP_2_57_60 A_0 D_960 IP_2_60_55 A_0 D_960 IP_2_64_52 "
    "A_0 D_24 IP_9_36_65 A_480 D_24 IP_9_42_62 "
    "A_0 D_480 IP_1_45_68 A_480 D_480 IP_1_45_65 "
    "A_0 D_960 IP_0_69_60"
)
suf_amt = (
    "A_0 D_960 IP_2_62_60 A_0 D_960 IP_2_65_55 A_0 D_960 IP_2_69_52 "
    "A_0 D_24 IP_9_36_65 A_480 D_24 IP_9_42_62 "
    "A_0 D_480 IP_1_50_68 A_480 D_480 IP_1_50_65 "
    "A_0 D_960 IP_0_74_60"
)

instruction = (
    f"[TASK:FIM][GENRE:JAZZ][BPM:90][MOOD:MELANCHOLIC]"
    f"[BARS:12][DENSITY:SPARSE][COMPLEXITY:SIMPLE]"
    f"[KEY_PRE:9_MINOR][KEY_SUF:2_MINOR]"
    f" /SUF {suf_amt} /PRE {pre_amt}"
)

Exemple 6 — COPILOT (générer basse + lead depuis drums + chords)

context_amt = (
    # Drums
    "A_0 D_24 IP_9_36_65 A_0 D_24 IP_9_42_60 "
    "A_480 D_24 IP_9_36_68 A_480 D_24 IP_9_42_62 "
    "A_480 D_24 IP_9_36_65 A_480 D_24 IP_9_46_58 "
    # Chords (Do maj 7 : C E G B)
    "A_0 D_960 IP_2_60_62 A_0 D_960 IP_2_64_58 "
    "A_0 D_960 IP_2_67_60 A_0 D_960 IP_2_71_55"
)

instruction = (
    f"[TASK:COPILOT][GENRE:JAZZ][BPM:100][MOOD:CHILL]"
    f"[BARS:8][DENSITY:NORMAL][COMPLEXITY:NORMAL]"
    f"[KEY:0_MAJOR]"
    f" /CONTEXT {context_amt}"
    f" /TARGET BASS,LEAD"
)

7. Paramètres de génération recommandés par usage

Usage Temperature top_p repetition_penalty Notes
Studio / précision 0.8 0.90 1.5 Académique, fidèle
Usage standard 1.1 0.92 1.8 Recommandé
Expérimental 1.3 0.95 2.0 Surprenant, parfois chaotique
Longue durée (>60s) 1.0 0.90 2.0 Évite les répétitions

8. Conversion MIDI multi-track

import re, mido
from mido import MidiFile, MidiTrack, Message, MetaMessage
from collections import defaultdict

TICKS_PER_BEAT = 96
AMT_SCALE      = TICKS_PER_BEAT / 24   # 1 tick AMT = 4 ticks MIDI
TOKEN_RE       = re.compile(r'\b(A_\d+|D_\d+|IP_\d+_\d+_\d+)\b')

# Canal AMT → canal MIDI + programme GM
CHANNEL_CONFIG = {
    9: {"midi_ch": 9, "program": 0,  "name": "Drums"},       # Kit batterie
    1: {"midi_ch": 1, "program": 32, "name": "Bass"},         # Acoustic Bass
    0: {"midi_ch": 0, "program": 0,  "name": "Lead"},         # Grand Piano
    2: {"midi_ch": 2, "program": 48, "name": "Chords"},       # Strings
    3: {"midi_ch": 3, "program": 91, "name": "Ambient"},      # Pad Warm
}

def amt_to_midi_multitrack(amt_text: str, bpm: int, output_path: str):
    tokens = TOKEN_RE.findall(amt_text)
    notes, cursor = [], 0
    i = 0
    while i + 2 < len(tokens):
        a, d, ip = tokens[i], tokens[i+1], tokens[i+2]
        if a.startswith("A_") and d.startswith("D_") and ip.startswith("IP_"):
            cursor += int(a[2:])
            dur     = int(d[2:])
            _, ch, pitch, vel = ip.split("_")
            notes.append((cursor, dur, int(ch), int(pitch), int(vel)))
            i += 3
        else:
            i += 1

    mid = MidiFile(type=1, ticks_per_beat=TICKS_PER_BEAT)

    # Track 0 : tempo
    t0 = MidiTrack()
    mid.tracks.append(t0)
    t0.append(MetaMessage("set_tempo", tempo=mido.bpm2tempo(bpm), time=0))

    # Regrouper par canal AMT
    channels_map = defaultdict(list)
    for onset, dur, amt_ch, pitch, vel in notes:
        t_on  = int(onset * AMT_SCALE)
        t_off = int((onset + dur) * AMT_SCALE)
        channels_map[amt_ch].append((t_on, t_off, pitch, vel))

    # Créer une piste MIDI par canal
    for amt_ch, ch_notes in sorted(channels_map.items()):
        cfg     = CHANNEL_CONFIG.get(amt_ch, {"midi_ch": amt_ch % 16, "program": 0, "name": "Unknown"})
        midi_ch = cfg["midi_ch"]
        track   = MidiTrack()
        mid.tracks.append(track)

        if midi_ch != 9:  # Pas de program_change pour drums
            track.append(Message("program_change", channel=midi_ch,
                                 program=cfg["program"], time=0))

        events = []
        for t_on, t_off, pitch, vel in ch_notes:
            events.append((t_on,  "note_on",  pitch, vel))
            events.append((t_off, "note_off", pitch, 0))

        events.sort(key=lambda e: (e[0], 0 if e[1] == "note_off" else 1))
        current_tick = 0
        for abs_tick, msg_type, pitch, vel in events:
            delta = abs_tick - current_tick
            track.append(Message(msg_type, channel=midi_ch,
                                 note=pitch, velocity=vel, time=delta))
            current_tick = abs_tick

    mid.save(output_path)
    return True

# Utilisation
amt_to_midi_multitrack(amt, bpm=110, output_path="sortie.mid")

9. Comparaison rapide OSTINATO-3B-MULTI vs OSTINATO-3B-CLASSICAL

(OSTINATO-3B-CLASSICAL est en cours de finalisation, pas encore publié...)

Capacité MULTI CLASSICAL
Multi-instrument ✅ 5 canaux ❌ Piano only (IP_2)
BPM variable ✅ 40-240 ⚠️ 120 uniquement
Tag GENRE ✅ 6 genres ❌
Tag MOOD ✅ 8 humeurs ❌
Tag BARS ✅ 1-16 ✅ 4/8/12/16/32
COPILOT ✅ ⚠️ Non ré-entraîné
Piano classique ⚠️ Généraliste ✅ Spécialisé
Dynamiques fin ⚠️ ✅

Règle d'usage :

  • 🎹 Piano solo classique → CLASSICAL
  • 🎸 Production complète multi-instrument → MULTI
Downloads last month
39
GGUF
Model size
4B params
Architecture
llama
Hardware compatibility
Log In to add your hardware

We're not able to determine the quantization variants.

Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for spauwels/OSTINATO-3B-MULTI-Llama3.2.final

Quantized
(544)
this model

Space using spauwels/OSTINATO-3B-MULTI-Llama3.2.final 1