| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <title>TuneJury · An open reward model for music generation</title> |
| <meta name="description" content="TuneJury scores music the way listeners compare it. A 2.8M-parameter head over frozen music encoders, trained on 17,554 human preference pairs."> |
| <link rel="icon" type="image/webp" href="assets/tunejury_logo.webp"> |
| <style> |
| :root{ |
| --ink:#0d0d12; --paper:#fafafa; --muted:#6b6b76; --accent:#3552c8; |
| --card:#ffffff; --line:#e7e7ec; --dark-ink:#f2f2f5; --dark-muted:#9a9aa6; |
| } |
| *{margin:0;padding:0;box-sizing:border-box} |
| html{scroll-behavior:smooth} |
| body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif; |
| color:var(--ink);background:var(--paper);-webkit-font-smoothing:antialiased;line-height:1.5} |
| |
| |
| header{position:fixed;top:0;left:0;right:0;z-index:50;display:flex;align-items:center; |
| justify-content:space-between;padding:.65rem clamp(1rem,4vw,2.5rem); |
| background:rgba(250,250,250,.82);backdrop-filter:saturate(180%) blur(14px); |
| border-bottom:1px solid var(--line)} |
| .brand{display:flex;align-items:center;gap:.55rem;font-weight:700;letter-spacing:-.01em;font-size:1.02rem} |
| .brand img{width:22px;height:22px;border-radius:5px} |
| nav{display:flex;gap:.5rem} |
| .navbtn{font-size:.84rem;font-weight:600;text-decoration:none;color:var(--ink); |
| padding:.42rem .85rem;border-radius:999px;border:1px solid var(--line);background:var(--card); |
| transition:transform .15s ease, box-shadow .15s ease} |
| .navbtn:hover{transform:translateY(-1px);box-shadow:0 4px 14px rgba(0,0,0,.08)} |
| .navbtn.primary{background:var(--ink);color:var(--paper);border-color:var(--ink)} |
| |
| |
| section{padding:clamp(4.5rem,11vh,8rem) clamp(1.25rem,6vw,3rem)} |
| .wrap{max-width:1060px;margin:0 auto} |
| .kicker{font-size:.82rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--accent)} |
| h1{font-size:clamp(2.6rem,8.5vw,5.6rem);font-weight:800;letter-spacing:-.035em;line-height:1.04} |
| h2{font-size:clamp(1.9rem,5.2vw,3.2rem);font-weight:800;letter-spacing:-.03em;line-height:1.12;margin:.6rem 0 1rem} |
| .lede{font-size:clamp(1.05rem,2.4vw,1.3rem);color:var(--muted);max-width:46ch} |
| .reveal{opacity:0;transform:translateY(26px);transition:opacity .8s cubic-bezier(.2,.6,.2,1),transform .8s cubic-bezier(.2,.6,.2,1)} |
| .reveal.in{opacity:1;transform:none} |
| .d1{transition-delay:.08s}.d2{transition-delay:.16s}.d3{transition-delay:.24s}.d4{transition-delay:.32s} |
| |
| |
| .hero{min-height:92vh;display:flex;align-items:center;text-align:center; |
| background:radial-gradient(1200px 520px at 50% -8%, #e8ecfb 0%, var(--paper) 58%)} |
| .hero .wrap{display:flex;flex-direction:column;align-items:center;gap:1.1rem} |
| .hero img.logo{width:clamp(64px,9vw,92px);border-radius:20px;box-shadow:0 12px 40px rgba(53,82,200,.18)} |
| .hero .lede{margin:0 auto} |
| .hero .sub{font-size:.95rem;color:var(--muted)} |
| .cta-row{display:flex;flex-wrap:wrap;gap:.6rem;justify-content:center;margin-top:.6rem} |
| .cta{font-size:.95rem;font-weight:650;text-decoration:none;padding:.7rem 1.25rem;border-radius:999px; |
| transition:transform .15s ease, box-shadow .15s ease} |
| .cta:hover{transform:translateY(-2px);box-shadow:0 8px 22px rgba(0,0,0,.12)} |
| .cta.fill{background:var(--ink);color:var(--paper)} |
| .cta.line{border:1.5px solid var(--ink);color:var(--ink)} |
| .scrollcue{margin-top:2.2rem;color:var(--muted);font-size:.85rem;animation:bob 2.4s ease-in-out infinite} |
| @keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(7px)}} |
| |
| |
| .pipe{display:flex;align-items:center;justify-content:center;gap:.7rem;flex-wrap:wrap;margin-top:2.4rem} |
| .node{padding:.85rem 1.15rem;border-radius:14px;font-weight:650;font-size:.95rem;background:var(--card); |
| border:1.5px solid var(--line);box-shadow:0 3px 14px rgba(0,0,0,.05)} |
| .node.frozen{background:#f0f2f7;border-color:#d8dce8;color:#3c3f4a} |
| .node.head{background:var(--accent);border-color:var(--accent);color:#fff} |
| .node.score{background:var(--ink);border-color:var(--ink);color:#fff;font-variant-numeric:tabular-nums} |
| .arrow{color:#b9bcc9;font-size:1.15rem} |
| .pipenote{margin-top:1.1rem;text-align:center;color:var(--muted);font-size:.9rem} |
| .flake{font-size:.8em;opacity:.75;margin-right:.3em} |
| .face{display:flex;align-items:center;justify-content:center;gap:.65rem;margin:2.2rem 0 1.1rem} |
| .face img{width:46px;height:46px;border-radius:50%;border:3px solid var(--accent); |
| box-shadow:0 6px 18px rgba(53,82,200,.18); |
| transition:filter .6s ease,border-color .6s ease,box-shadow .6s ease} |
| .face span{display:inline-block;font-size:.92rem;font-weight:700;letter-spacing:-.01em;overflow:hidden} |
| #pin{min-width:9.2rem;text-align:center} |
| #penc{min-width:11.8rem;text-align:center} |
| #pscore{min-width:7.4rem;text-align:center} |
| .clipline{display:flex;align-items:center;justify-content:center;gap:.8rem;margin-top:1.6rem;flex-wrap:wrap} |
| .clipline audio{height:34px;max-width:280px} |
| .clipline span{font-size:.82rem;color:var(--muted)} |
| .node{overflow:hidden} |
| .roll{display:inline-block;transition:transform .42s cubic-bezier(.3,.7,.3,1),opacity .42s ease} |
| .roll.up{transform:translateY(-115%);opacity:0;transition:transform .38s ease-in,opacity .38s ease-in} |
| .roll.below{transform:translateY(115%);opacity:0;transition:none} |
| #pnote{transition:opacity .45s ease} |
| .fadeout{opacity:0 !important} |
| |
| |
| .darksec{background:var(--ink);color:var(--dark-ink)} |
| .darksec .kicker{color:#8ea2ef} |
| .darksec .lede{color:var(--dark-muted)} |
| .numgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:1.2rem;margin-top:2.6rem} |
| .num{text-align:center} |
| .num b{display:block;font-size:clamp(1.9rem,4.6vw,3.1rem);font-weight:800;letter-spacing:-.03em; |
| font-variant-numeric:tabular-nums} |
| .num span{font-size:.88rem;color:var(--dark-muted)} |
| .mixwrap{margin-top:2.6rem} |
| .mixbar{display:flex;height:10px;border-radius:6px;overflow:hidden;gap:2px} |
| .mixlegend{margin-top:.6rem;text-align:center;font-size:.82rem;color:var(--dark-muted)} |
| |
| |
| .cards{display:grid;grid-template-columns:repeat(3,1fr);gap:1.1rem;margin-top:2.4rem} |
| .card{background:var(--card);border:1px solid var(--line);border-radius:20px;padding:1.6rem 1.4rem; |
| box-shadow:0 4px 22px rgba(0,0,0,.05)} |
| .card .tag{font-size:.76rem;font-weight:700;letter-spacing:.1em;color:var(--accent);text-transform:uppercase} |
| .card h3{font-size:1.22rem;font-weight:750;letter-spacing:-.015em;margin:.45rem 0 .5rem} |
| .card p{font-size:.94rem;color:var(--muted)} |
| .mode1curve{width:100%;height:54px;margin-top:.9rem} |
| .modefig{width:100%;height:64px;margin-top:.9rem;display:block} |
| |
| |
| .abrow{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin-top:1.4rem} |
| .abcase{background:var(--card);border:1px solid var(--line);border-radius:18px;padding:1.25rem 1.3rem} |
| .abcase h4{font-size:1rem;font-weight:720;margin-bottom:.2rem} |
| .abcase .why{font-size:.85rem;color:var(--muted);margin-bottom:.55rem} |
| .abcase .prompt{font-size:.82rem;color:#3c3f4a;background:#f4f5f9;border-left:3px solid var(--accent); |
| border-radius:0 8px 8px 0;padding:.5rem .7rem;margin-bottom:.85rem;font-style:italic} |
| .abpair{display:flex;flex-direction:column;gap:.55rem} |
| .abitem{display:flex;align-items:center;gap:.7rem} |
| .abitem label{font-size:.82rem;font-weight:650;min-width:7.2rem;color:#3c3f4a} |
| .abitem audio{width:100%;height:34px} |
| .schip{font-variant-numeric:tabular-nums;font-size:.78rem;font-weight:650;color:var(--muted); |
| min-width:4.8rem;text-align:right;white-space:nowrap} |
| .schip.win{color:var(--accent)} |
| sup{font-size:.55em;font-weight:700;opacity:.7} |
| .footnotes{max-width:1060px;margin:0 auto;padding:2.2rem clamp(1.25rem,6vw,3rem) 0; |
| font-size:.74rem;color:var(--muted);line-height:1.6} |
| .footnotes li{margin-bottom:.25rem;list-style-position:inside} |
| |
| |
| .tau{display:flex;align-items:center;gap:1rem;margin:2rem 0 1.4rem;max-width:560px} |
| .tau label{font-size:.95rem;font-weight:650;white-space:nowrap;font-variant-numeric:tabular-nums} |
| .tau input{flex:1;accent-color:#8ea2ef;height:4px} |
| .drow{display:flex;align-items:center;gap:1rem;padding:.45rem 0} |
| .drow .dname{flex:0 0 8.6rem;font-size:.84rem;font-weight:600;color:var(--dark-muted);line-height:1.2} |
| .drow svg{flex:1;height:44px;display:block} |
| .drow .dpct{min-width:5.6rem;text-align:right;font-size:.9rem;font-weight:700; |
| font-variant-numeric:tabular-nums;color:#8ea2ef} |
| .dviz{position:relative;flex:1} |
| .dviz svg{width:100%;height:44px;display:block} |
| .exdot{position:absolute;top:50%;transform:translate(-50%,-50%);width:15px;height:15px;border-radius:50%; |
| background:var(--ink);border:2.5px solid #8ea2ef;cursor:pointer;padding:0; |
| transition:width .25s ease,height .25s ease,background .25s ease;z-index:2} |
| .exdot:hover{background:#2a3550} |
| .exdot.playing{width:27px;height:27px;background:#8ea2ef;animation:pulse 1.6s ease-in-out infinite} |
| @keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(142,162,239,.45)}50%{box-shadow:0 0 0 9px rgba(142,162,239,0)}} |
| @media (prefers-reduced-motion:reduce){.exdot.playing{animation:none}} |
| .dnote{margin-top:1.2rem;font-size:.8rem;color:var(--dark-muted)} |
| @media (max-width:840px){ .drow .dname{flex:0 0 6.8rem;font-size:.78rem} .drow .dpct{min-width:4.6rem} } |
| |
| |
| .split{display:grid;grid-template-columns:1.1fr .9fr;gap:2.4rem;align-items:center;margin-top:1rem} |
| .bigstat{text-align:center;background:var(--card);border:1px solid var(--line);border-radius:24px; |
| padding:2.4rem 1.5rem;box-shadow:0 8px 30px rgba(0,0,0,.06)} |
| .bigstat b{font-size:clamp(2.6rem,6vw,4rem);font-weight:800;letter-spacing:-.03em;color:var(--accent)} |
| .bigstat span{display:block;color:var(--muted);font-size:.92rem;margin-top:.35rem} |
| |
| |
| footer{padding:3.4rem clamp(1.25rem,6vw,3rem) 4rem;border-top:1px solid var(--line);text-align:center} |
| .footgrid{display:flex;flex-wrap:wrap;gap:.6rem;justify-content:center;margin:1.3rem 0 1.8rem} |
| .fineprint{font-size:.8rem;color:var(--muted)} |
| .credits{margin:0 0 1.4rem} |
| .credits .ptitle{font-size:.92rem;font-weight:650;color:#3c3f4a;margin-bottom:.45rem} |
| .credits p{font-size:.84rem;color:var(--muted);line-height:1.7} |
| |
| |
| @media (max-width:840px){ |
| .numgrid{grid-template-columns:repeat(2,1fr);gap:1.6rem 1rem} |
| .cards{grid-template-columns:1fr} |
| .abrow{grid-template-columns:1fr} |
| .split{grid-template-columns:1fr} |
| nav .navbtn.gh{display:none} |
| } |
| @media (prefers-reduced-motion:reduce){ |
| .reveal{opacity:1;transform:none;transition:none} |
| .scrollcue{animation:none} |
| html{scroll-behavior:auto} |
| } |
| </style> |
| </head> |
| <body> |
|
|
| <header> |
| <div class="brand"><img src="assets/tunejury_logo.webp" alt=""><span>TuneJury</span></div> |
| <nav> |
| <a class="navbtn" href="https://arxiv.org/abs/2606.17006" target="_blank" rel="noopener">Paper</a> |
| <a class="navbtn gh" href="https://github.com/yonghyunk1m/TuneJury" target="_blank" rel="noopener">Code</a> |
| <a class="navbtn primary" href="https://huggingface.co/spaces/TuneJury/tune-jury-demo" target="_blank" rel="noopener">Listen</a> |
| </nav> |
| </header> |
|
|
| |
| <section class="hero"> |
| <div class="wrap"> |
| <img class="logo reveal" src="assets/tunejury_logo.webp" alt="TuneJury logo"> |
| <h1 class="reveal d1">Music, scored the way<br>listeners compare it.</h1> |
| <p class="lede reveal d2">TuneJury is an open reward model for music generation. |
| It reads a prompt and an audio clip, and returns one preference score.</p> |
| <p class="reveal d2" style="font-size:.92rem;color:var(--muted);margin-top:.55rem">A follow-up to <a href="https://huggingface.co/music-arena" target="_blank" rel="noopener" style="color:var(--accent);font-weight:650;text-decoration:none">Music Arena</a>, distilling its live human preference votes into a reusable reward model.</p> |
| <div class="cta-row reveal d3"> |
| <a class="cta fill" href="https://huggingface.co/spaces/TuneJury/tune-jury" target="_blank" rel="noopener">Score your audio</a> |
| <a class="cta line" href="https://github.com/yonghyunk1m/TuneJury" target="_blank" rel="noopener">Code & models</a> |
| </div> |
| <div class="scrollcue reveal d4">scroll ↓</div> |
| </div> |
| </section> |
|
|
| |
| <section> |
| <div class="wrap"> |
| <p class="kicker reveal">How it scores</p> |
| <h2 class="reveal d1">A small head on top of<br>frozen music encoders.</h2> |
| <p class="lede reveal d2">Audio passes through CLAP and MERT. The prompt passes through CLAP text. |
| A 2.8M-parameter MLP turns the three embeddings into a single scalar, |
| trained pairwise on human A vs. B comparisons.</p> |
| <div class="face reveal d3"> |
| <img id="faceimg" src="assets/tunejury_logo.webp" alt=""> |
| <span class="roll" id="facelabel">TuneJury · released</span> |
| </div> |
| <div class="pipe reveal d3"> |
| <div class="node" id="pin"><span class="roll">Prompt + audio</span></div><div class="arrow">→</div> |
| <div class="node frozen" id="penc"><span class="flake">❄</span><span class="roll" id="penclabel">CLAP + MERT</span></div><div class="arrow">→</div> |
| <div class="node head">MLP head</div><div class="arrow">→</div> |
| <div class="node score" id="pscore"><span class="roll">s = +0.42</span></div> |
| </div> |
| <p class="pipenote reveal d4" id="pnote">Released checkpoint. Encoders stay frozen, and only the head is trained.</p> |
| <div class="clipline reveal d4"> |
| <audio controls preload="none" src="assets/config_clip.wav"></audio> |
| <span>The clip behind these scores<sup>1</sup></span> |
| </div> |
| </div> |
| </section> |
|
|
| |
| <section class="darksec"> |
| <div class="wrap"> |
| <p class="kicker reveal">By the numbers</p> |
| <h2 class="reveal d1">Trained on human preferences.<br>No pseudo-labels.</h2> |
| <p class="lede reveal d2">Four open sources of human ratings. No pseudo-label augmentation.</p> |
| <div class="numgrid"> |
| <div class="num reveal"><b data-count="17554">0</b><span>human-rated training pairs<sup>2</sup></span></div> |
| <div class="num reveal d1"><b data-count="0.7086" data-dec="4">0</b><span>held-out pairwise accuracy<sup>3</sup></span></div> |
| <div class="num reveal d2"><b data-count="2.8" data-dec="1" data-suffix="M">0</b><span>trainable parameters<sup>4</sup></span></div> |
| <div class="num reveal d3"><b data-count="219" data-suffix="K">0</b><span>released track scores<sup>5</sup></span></div> |
| </div> |
| <div class="mixwrap reveal d4"> |
| <div class="mixbar"> |
| <span style="flex:12480;background:#8ea2ef" title="AIME: 12,480"></span><span style="flex:2491;background:#6b7fd4" title="SongEval: 2,491"></span><span style="flex:2012;background:#4e5fb8" title="MusicPrefs: 2,012"></span><span style="flex:571;background:#36459c" title="Music Arena: 571"></span> |
| </div> |
| <p class="mixlegend">AIME 12,480 · SongEval 2,491 · MusicPrefs 2,012 · Music Arena 571</p> |
| </div> |
| </div> |
| </section> |
|
|
| |
| <section> |
| <div class="wrap"> |
| <p class="kicker reveal">One frozen reward</p> |
| <h2 class="reveal d1">Three ways to use it.</h2> |
| <div class="cards"> |
| <div class="card reveal d1"> |
| <p class="tag">Mode 1</p> |
| <h3>Best-of-N selection</h3> |
| <p>Generate N candidates, keep the highest-scoring one. |
| Reward rises monotonically through N = 32 on four open-weights backbones.<sup>6</sup></p> |
| <svg class="mode1curve" viewBox="0 0 100 54" preserveAspectRatio="none"><polyline points="0,26.7 20,21.8 40,17.0 60,13.6 80,10.0 100,7.2" fill="none" stroke="var(--accent)" stroke-opacity=".55" stroke-width="1.6"/><polyline points="0,25.4 20,19.0 40,16.6 60,12.6 80,8.8 100,6.5" fill="none" stroke="var(--accent)" stroke-opacity=".55" stroke-width="1.6"/><polyline points="0,48.4 20,41.0 40,33.7 60,28.1 80,25.8 100,24.6" fill="none" stroke="var(--accent)" stroke-opacity=".55" stroke-width="1.6"/><polyline points="0,47.1 20,31.2 40,21.1 60,16.4 80,12.4 100,9.6" fill="none" stroke="var(--accent)" stroke-opacity=".55" stroke-width="1.6"/></svg> |
| </div> |
| <div class="card reveal d2"> |
| <p class="tag">Mode 2</p> |
| <h3>Latent optimization</h3> |
| <p>Backpropagate the score through the sampler into the starting noise, DITTO style. |
| The backbone stays frozen.</p> |
| <svg class="modefig" viewBox="0 0 170 64" aria-hidden="true"> |
| <defs><marker id="ah2" viewBox="0 0 8 8" refX="6" refY="4" markerWidth="5" markerHeight="5" orient="auto-start-reverse"><path d="M0,0L8,4L0,8z" fill="var(--accent)" opacity=".6"/></marker></defs> |
| <path d="M14,52 C50,48 95,34 148,15" fill="none" stroke="var(--accent)" stroke-width="2" stroke-opacity=".55"/> |
| <circle cx="148" cy="15" r="3.5" fill="var(--accent)"/> |
| <path d="M143,9 C100,-4 38,2 18,40" fill="none" stroke="var(--accent)" stroke-width="1.4" stroke-dasharray="4 3" stroke-opacity=".45" marker-end="url(#ah2)"/> |
| <text x="6" y="62" font-size="9" fill="#5a647d">noise</text> |
| <text x="122" y="30" font-size="9" fill="#5a647d">score s</text> |
| </svg> |
| </div> |
| <div class="card reveal d3"> |
| <p class="tag">Mode 3</p> |
| <h3>Expert iteration</h3> |
| <p>Fine-tune a backbone on its own top-scoring outputs, |
| mapping the trade-off between reward and distributional fidelity.</p> |
| <svg class="modefig" viewBox="0 0 170 64" aria-hidden="true"> |
| <defs><marker id="ah3" viewBox="0 0 8 8" refX="6" refY="4" markerWidth="5" markerHeight="5" orient="auto-start-reverse"><path d="M0,0L8,4L0,8z" fill="var(--accent)" opacity=".6"/></marker></defs> |
| <rect x="4" y="24" width="54" height="16" rx="8" fill="var(--accent)" fill-opacity=".07" stroke="var(--accent)" stroke-opacity=".35"/> |
| <text x="31" y="35.5" font-size="9" fill="#39435e" text-anchor="middle">generate</text> |
| <rect x="112" y="4" width="54" height="16" rx="8" fill="var(--accent)" fill-opacity=".07" stroke="var(--accent)" stroke-opacity=".35"/> |
| <text x="139" y="15.5" font-size="9" fill="#39435e" text-anchor="middle">keep top</text> |
| <rect x="112" y="44" width="54" height="16" rx="8" fill="var(--accent)" fill-opacity=".07" stroke="var(--accent)" stroke-opacity=".35"/> |
| <text x="139" y="55.5" font-size="9" fill="#39435e" text-anchor="middle">retrain</text> |
| <path d="M60,27 C80,22 90,17 108,13" fill="none" stroke="var(--accent)" stroke-width="1.4" stroke-opacity=".5" marker-end="url(#ah3)"/> |
| <path d="M139,22 L139,41" fill="none" stroke="var(--accent)" stroke-width="1.4" stroke-opacity=".5" marker-end="url(#ah3)"/> |
| <path d="M108,51 C88,56 78,47 62,40" fill="none" stroke="var(--accent)" stroke-width="1.4" stroke-opacity=".5" marker-end="url(#ah3)"/> |
| </svg> |
| </div> |
| </div> |
| </div> |
| </section> |
|
|
| |
| <section style="background:#f1f2f6"> |
| <div class="wrap"> |
| <p class="kicker reveal">Hear it</p> |
| <h2 class="reveal d1">Before and after, on the same prompt.</h2> |
| <p class="lede reveal d2">Each pair uses one prompt and one backbone. Only the reward signal changed the outcome.</p> |
| <div class="abrow"> |
| <div class="abcase reveal d1"> |
| <h4>Best-of-16 selection</h4> |
| <p class="why">MusicGen-medium. One random sample vs. the top pick of 16.</p> |
| <p class="prompt">“A dark trance track featuring accordion, blending hypnotic rhythms with melancholic melodies and a pervasive, atmospheric mood.”</p> |
| <div class="abpair"> |
| <div class="abitem"><label>Single sample</label><audio controls preload="none" src="assets/mode1_p75_n1.wav"></audio><span class="schip">s = +0.05</span></div> |
| <div class="abitem"><label>Best of 16</label><audio controls preload="none" src="assets/mode1_p75_top.wav"></audio><span class="schip win">s = +1.71</span></div> |
| </div> |
| </div> |
| <div class="abcase reveal d2"> |
| <h4>Latent optimization</h4> |
| <p class="why">TangoFlux. The same noise, pushed toward higher reward.</p> |
| <p class="prompt">“A melancholic rap piece driven by a steady drummachine beat, layered with subtle synth pads and a sparse electric guitar, creating a reflective, introspective atmosphere. …”</p> |
| <div class="abpair"> |
| <div class="abitem"><label>Baseline</label><audio controls preload="none" src="assets/mode2_tangoflux_p0_baseline.wav"></audio><span class="schip">s = −1.11</span></div> |
| <div class="abitem"><label>After DITTO</label><audio controls preload="none" src="assets/mode2_tangoflux_p0_ditto.wav"></audio><span class="schip win">s = +1.13</span></div> |
| </div> |
| </div> |
| <div class="abcase reveal d3"> |
| <h4>Expert iteration</h4> |
| <p class="why">FluxAudio-S. Baseline vs. fine-tuned on its own best outputs.</p> |
| <p class="prompt">“A fast garage track featuring an electric guitar, driven by raw energy and a loose, rhythmic feel.”</p> |
| <div class="abpair"> |
| <div class="abitem"><label>Baseline</label><audio controls preload="none" src="assets/mode3_p46_baseline.wav"></audio><span class="schip">s = −2.06</span></div> |
| <div class="abitem"><label>Fine-tuned</label><audio controls preload="none" src="assets/mode3_p46_finetuned.wav"></audio><span class="schip win">s = −0.05</span></div> |
| </div> |
| </div> |
| <div class="abcase reveal d4" style="display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center"> |
| <h4>More examples, with scores</h4> |
| <p class="why">The listening demo pairs every sample with its TuneJury score.</p> |
| <a class="cta fill" href="https://huggingface.co/spaces/TuneJury/tune-jury-demo" target="_blank" rel="noopener">Open the listening demo</a> |
| </div> |
| </div> |
| </div> |
| </section> |
|
|
| |
| <section class="darksec"> |
| <div class="wrap"> |
| <p class="kicker reveal">The released scores</p> |
| <h2 class="reveal d1">219,020 clips.<br>One score each.</h2> |
| <p class="lede reveal d2">Seven open-license collections, scored with the released checkpoint. |
| Drag the threshold and see what a score filter keeps.<sup>5</sup></p> |
| <div class="tau reveal d3"> |
| <label>keep s > τ = <b id="tauval">+0.00</b></label> |
| <input type="range" id="tau" min="-4" max="3.5" step="0.05" value="0" aria-label="score threshold"> |
| </div> |
| <div id="dists" class="reveal d3"></div> |
| <p class="dnote reveal d4">Share kept = clips scoring above τ.</p> |
| </div> |
| </section> |
|
|
| |
| <section> |
| <div class="wrap"> |
| <p class="kicker reveal">Anchor calibration</p> |
| <div class="split"> |
| <div> |
| <h2 class="reveal d1">New generators keep arriving.<br>The model keeps up.</h2> |
| <p class="lede reveal d2">A reward model trained today meets systems released tomorrow. |
| Anchor calibration fits one bias per new system on a handful of preference pairs, |
| with the model itself left untouched.</p> |
| </div> |
| <div class="bigstat reveal d3"> |
| <b>25×</b> |
| <span>less calibration data than from-scratch retraining,<br>at the same accuracy ceiling<sup>7</sup></span> |
| </div> |
| </div> |
| </div> |
| </section> |
|
|
| |
| <div class="footnotes reveal"> |
| <p>Unless a variant is named, every result on this page uses the released CLAP+MERT checkpoint.</p> |
| <ol> |
| <li>A 10-second excerpt from an AIME dataset clip (CC BY 4.0), generated by Suno v3.5 from the prompt “pop, classical, percussion”. At this length scoring is deterministic: re-running the released pipeline on this file reproduces these values exactly. Score scales are model-specific: values are comparable within one configuration, not across configurations.</li> |
| <li>Post-filter pairs from Music Arena, MusicPrefs, AIME, and SongEval, after benchmark-overlap removal.</li> |
| <li>Pairwise accuracy on the 2,035-pair held-out test split of the same four-source mix, ties excluded.</li> |
| <li>2,791,169 parameters in the released scoring head. The frozen encoders add none.</li> |
| <li>One score per clip on seven open-license collections, from one scorer run per clip with an empty prompt. The MERT branch averages the full clip, while the CLAP branch encodes one 10-second window, so re-scoring a long clip can shift an individual value slightly. The Song Describer Dataset is a captioned subset of MTG-Jamendo: all 706 of its two-minute excerpts come from tracks also scored in the MTG-Jamendo row. Threshold filtering shown on this page is illustrative; the threshold is not validated on held-out data. Example dots play 10-second excerpts. MidiCaps dots play FluidSynth renders of the underlying MIDI (FluidR3 General MIDI soundfont). MusicCaps carries no dots: its license (CC BY-SA 4.0) covers the captions only, while the audio remains on YouTube under the original uploaders’ rights and cannot be redistributed.</li> |
| <li>Top-1 mean reward across MusicGen-medium, MusicGen-large, AudioLDM2-music, and ACE-Step Turbo Continuous, 100 prompts per setting.</li> |
| <li>Anchor calibration at K = 10 matches from-scratch retraining at K = 250 on the 2026-02/03 post-cutoff Music Arena slice, within the swept range of K. The recovery is slice-dependent.</li> |
| </ol> |
| <p style="margin-top:.9rem"><b>Data:</b> |
| <a href="https://repositori.upf.edu/handle/10230/42015" target="_blank" rel="noopener">MTG-Jamendo</a> · |
| <a href="https://arxiv.org/abs/1612.01840" target="_blank" rel="noopener">FMA</a> · |
| <a href="https://ismir2009.ismir.net/proceedings/OS5-5.pdf" target="_blank" rel="noopener">MagnaTagATune</a> · |
| <a href="https://archives.ismir.net/ismir2018/paper/000248.pdf" target="_blank" rel="noopener">OpenMIC</a> · |
| <a href="https://arxiv.org/abs/2406.02255" target="_blank" rel="noopener">MidiCaps</a> · |
| <a href="https://arxiv.org/abs/2301.11325" target="_blank" rel="noopener">MusicCaps</a> · |
| <a href="https://arxiv.org/abs/2311.10057" target="_blank" rel="noopener">Song Describer Dataset</a> · |
| <a href="https://arxiv.org/abs/2507.20900" target="_blank" rel="noopener">Music Arena</a> · |
| <a href="https://arxiv.org/abs/2503.16669" target="_blank" rel="noopener">MusicPrefs</a> · |
| <a href="https://arxiv.org/abs/2506.19085" target="_blank" rel="noopener">AIME</a> · |
| <a href="https://arxiv.org/abs/2505.10793" target="_blank" rel="noopener">SongEval</a></p> |
| <p><b>Models & methods:</b> |
| <a href="https://arxiv.org/abs/2211.06687" target="_blank" rel="noopener">LAION-CLAP</a> · |
| <a href="https://arxiv.org/abs/2306.00107" target="_blank" rel="noopener">MERT</a> · |
| <a href="https://arxiv.org/abs/2501.01108" target="_blank" rel="noopener">MuQ-MuLan</a> · |
| <a href="https://arxiv.org/abs/2306.05284" target="_blank" rel="noopener">MusicGen</a> · |
| <a href="https://arxiv.org/abs/2308.05734" target="_blank" rel="noopener">AudioLDM 2</a> · |
| <a href="https://arxiv.org/abs/2506.00045" target="_blank" rel="noopener">ACE-Step</a> · |
| <a href="https://arxiv.org/abs/2412.21037" target="_blank" rel="noopener">TangoFlux</a> · |
| <a href="https://arxiv.org/abs/2505.08175" target="_blank" rel="noopener">Stable Audio Open Small</a> · |
| <a href="https://arxiv.org/abs/2508.06098" target="_blank" rel="noopener">MeanAudio</a> · |
| <a href="https://arxiv.org/abs/2401.12179" target="_blank" rel="noopener">DITTO</a></p> |
| </div> |
|
|
| <footer> |
| <p class="kicker reveal">Get started</p> |
| <h2 class="reveal d1" style="margin-bottom:.4rem">Use it as your reward signal.</h2> |
| <div class="footgrid reveal d2"> |
| <a class="cta fill" href="https://huggingface.co/spaces/TuneJury/tune-jury" target="_blank" rel="noopener">Interactive scoring</a> |
| <a class="cta line" href="https://huggingface.co/spaces/TuneJury/tune-jury-demo" target="_blank" rel="noopener">Listening demo</a> |
| <a class="cta line" href="https://github.com/yonghyunk1m/TuneJury" target="_blank" rel="noopener">Code & models</a> |
| </div> |
| <div class="credits reveal d3"> |
| <p class="ptitle">TuneJury: An Open Metric for Improving Music Generation Preference Alignment · Preprint, 2026</p> |
| <p>Yonghyun Kim<sup>♯</sup> · Junwon Lee<sup>♭♭</sup> · Haiwen Xia<sup>♮♮</sup> · Yinghao Ma<sup>♯♯</sup> · Junghyun Koo<sup>♮</sup> · Koichi Saito<sup>♮</sup> · Zhi Zhong<sup>♭♮</sup> · Yuki Mitsufuji<sup>♮</sup> · Chris Donahue<sup>♭</sup></p> |
| <p><sup>♭</sup>Carnegie Mellon University · <sup>♮</sup>Sony AI · <sup>♭♮</sup>Sony Group Corporation · <sup>♯</sup>Georgia Tech · <sup>♭♭</sup>KAIST · <sup>♮♮</sup>Peking University · <sup>♯♯</sup>QMUL</p> |
| </div> |
| <p class="fineprint">Checkpoint released under CC-BY-NC 4.0 · An Apache 2.0 variant is included for commercial use</p> |
| </footer> |
|
|
| <script> |
| |
| const io = new IntersectionObserver((es)=>{ |
| es.forEach(e=>{ if(e.isIntersecting){ e.target.classList.add('in'); io.unobserve(e.target);} }); |
| },{threshold:.18}); |
| document.querySelectorAll('.reveal').forEach(el=>io.observe(el)); |
| |
| |
| const reduced = matchMedia('(prefers-reduced-motion: reduce)').matches; |
| const fmt = (v,dec)=> dec>0 ? v.toFixed(dec) : Math.round(v).toLocaleString('en-US'); |
| const cio = new IntersectionObserver((es)=>{ |
| es.forEach(e=>{ |
| if(!e.isIntersecting) return; |
| const el = e.target, target = parseFloat(el.dataset.count), |
| dec = parseInt(el.dataset.dec||'0'), suf = el.dataset.suffix||''; |
| cio.unobserve(el); |
| if(reduced){ el.textContent = fmt(target,dec)+suf; return; } |
| const t0 = performance.now(), dur = 1400; |
| const tick = (t)=>{ |
| const p = Math.min(1,(t-t0)/dur), ease = 1-Math.pow(1-p,3); |
| el.textContent = fmt(target*ease,dec)+suf; |
| if(p<1) requestAnimationFrame(tick); |
| }; |
| requestAnimationFrame(tick); |
| }); |
| },{threshold:.6}); |
| document.querySelectorAll('[data-count]').forEach(el=>cio.observe(el)); |
| |
| |
| const cfgs = [ |
| {i:'Prompt + audio', e:'CLAP + MERT', s:'s = +0.42', n:'Released checkpoint. Encoders stay frozen, and only the head is trained.', |
| f:{hue:0, ring:'#3552c8', label:'TuneJury · released'}}, |
| {i:'Audio only', e:'CLAP + MERT', s:'s = +1.02', n:'No prompt needed: the text branch receives a zero vector. Same checkpoint.', |
| f:{hue:0, ring:'#3552c8', label:'TuneJury · released'}}, |
| {i:'Audio only', e:'CLAP audio', s:'s = +0.53', n:'Apache 2.0 variant for commercial use, trained on CLAP audio alone.', |
| f:{hue:120, ring:'#2f9e63', label:'TuneJury A1'}}, |
| {i:'Prompt + audio', e:'MuQ-MuLan-large', s:'s = +0.61', n:'Encoder-swap variant. Same head template at half the input width.', |
| f:{hue:230, ring:'#8a4fc8', label:'TuneJury · MuQ swap'}}, |
| ]; |
| if(!reduced){ |
| let ci = 0, curFace = 'TuneJury · released'; |
| const pinR = document.querySelector('#pin .roll'), pel = document.getElementById('penclabel'), |
| pn = document.getElementById('pnote'); |
| const roll = (el, html)=>{ |
| el.classList.add('up'); |
| setTimeout(()=>{ |
| el.innerHTML = html; |
| el.classList.remove('up'); el.classList.add('below'); |
| void el.offsetHeight; |
| el.classList.remove('below'); |
| }, 380); |
| }; |
| setInterval(()=>{ |
| ci = (ci+1) % cfgs.length; |
| roll(pinR, cfgs[ci].i); |
| setTimeout(()=>roll(pel, cfgs[ci].e), 180); |
| setTimeout(()=>roll(document.querySelector('#pscore .roll'), cfgs[ci].s), 360); |
| const fimg = document.getElementById('faceimg'), flab = document.getElementById('facelabel'), f = cfgs[ci].f; |
| if(curFace !== f.label){ |
| curFace = f.label; |
| fimg.style.filter = `hue-rotate(${f.hue}deg)`; |
| fimg.style.borderColor = f.ring; |
| fimg.style.boxShadow = `0 6px 18px ${f.ring}33`; |
| roll(flab, f.label); |
| } |
| setTimeout(()=>{ |
| pn.classList.add('fadeout'); |
| setTimeout(()=>{ pn.textContent = cfgs[ci].n; pn.classList.remove('fadeout'); }, 450); |
| }, 360); |
| }, 5000); |
| } |
| |
| |
| const H = {"lo":-4.0,"hi":3.5,"nb":40,"data":{"Song Describer Dataset":{"n":706,"bins":[0,0,0,0,1,0,0,0,1,2,2,0,3,1,5,9,10,11,16,15,15,20,24,26,35,42,47,40,52,65,73,45,47,32,28,13,10,8,2,6]},"MTG-Jamendo":{"n":55701,"bins":[31,18,38,47,58,97,135,175,241,381,447,685,778,1036,1245,1494,1737,1951,2103,2207,2157,2144,2271,2577,3200,3798,4065,3825,3565,3303,2826,2214,1680,1220,814,530,289,171,87,61]},"MidiCaps":{"n":5000,"bins":[1,0,1,0,3,1,6,17,14,37,77,117,165,200,234,274,327,355,313,283,243,219,239,229,246,270,282,255,190,163,102,80,33,18,4,1,1,0,0,0]},"MusicCaps":{"n":5352,"bins":[6,2,8,10,16,16,28,55,74,105,136,160,185,263,304,363,342,428,388,366,293,242,233,207,186,171,183,138,151,86,89,42,30,25,8,7,3,3,0,0]},"MagnaTagATune":{"n":25860,"bins":[6,4,11,12,18,49,55,106,209,321,458,712,933,1274,1571,1897,2274,2469,2520,2327,1882,1430,1136,1019,859,725,544,399,263,157,104,62,33,13,7,1,0,0,0,0]},"FMA-Large":{"n":106401,"bins":[1596,616,797,1067,1288,1595,1926,2233,2695,3033,3202,3733,4138,4457,4917,5184,5276,5392,5172,4781,4193,3785,3465,3638,3831,4104,4120,3817,3228,2658,2109,1524,1194,733,451,248,111,50,28,16]},"OpenMIC":{"n":20000,"bins":[130,70,98,120,185,233,336,377,522,615,784,977,1090,1240,1326,1473,1516,1507,1455,1370,1102,800,632,481,430,385,273,215,138,67,34,9,6,2,1,1,0,0,0,0]}}}; |
| (function(){ |
| const wrap = document.getElementById('dists'); if(!wrap) return; |
| const W=600, Ht=44, NB=H.nb, bw=W/NB; |
| const order = ['Song Describer Dataset','MTG-Jamendo','MidiCaps','MusicCaps','MagnaTagATune','FMA-Large','OpenMIC']; |
| const EX = { |
| 'Song Describer Dataset': [{s:-0.32,f:'ex_sdd_low.mp3'},{s:1.36,f:'ex_sdd_mid.mp3'},{s:2.34,f:'ex_sdd_high.mp3'}], |
| 'MTG-Jamendo': [{s:-1.17,f:'ex_mtg_low.mp3'},{s:0.72,f:'ex_mtg_mid.mp3'},{s:1.93,f:'ex_mtg_high.mp3'}], |
| 'MidiCaps': [{s:-1.51,f:'ex_midicaps_low.mp3'},{s:-0.19,f:'ex_midicaps_mid.mp3'},{s:1.34,f:'ex_midicaps_high.mp3'}], |
| 'MagnaTagATune': [{s:-1.62,f:'ex_mtat_low.mp3'},{s:-0.58,f:'ex_mtat_mid.mp3'},{s:0.63,f:'ex_mtat_high.mp3'}], |
| 'FMA-Large': [{s:-2.54,f:'ex_fma_low.mp3'},{s:-0.62,f:'ex_fma_mid.mp3'},{s:1.35,f:'ex_fma_high.mp3'}], |
| 'OpenMIC': [{s:-2.34,f:'ex_openmic_low.mp3'},{s:-0.95,f:'ex_openmic_mid.mp3'},{s:0.33,f:'ex_openmic_high.mp3'}], |
| }; |
| const rows = []; |
| order.forEach(name=>{ |
| const d = H.data[name], mx = Math.max(...d.bins); |
| const pts = d.bins.map((v,i)=>`${(i+0.5)*bw},${Ht - (v/mx)*(Ht-4)}`).join(' '); |
| const dots = (EX[name]||[]).map(e=>{ |
| const left = (e.s - H.lo) / (H.hi - H.lo) * 100; |
| const sgn = e.s >= 0 ? '+' : ''; |
| return `<button class="exdot" data-src="assets/${e.f}" style="left:${left.toFixed(1)}%" aria-label="play example, s = ${sgn}${e.s.toFixed(2)}" title="s = ${sgn}${e.s.toFixed(2)}"></button>`; |
| }).join(''); |
| const row = document.createElement('div'); row.className='drow'; |
| row.innerHTML = `<span class="dname">${name}</span> |
| <div class="dviz"> |
| <svg viewBox="0 0 ${W} ${Ht}" preserveAspectRatio="none"> |
| <defs><clipPath id="cl-${rows.length}"><rect x="0" y="0" width="${W}" height="${Ht}"/></clipPath></defs> |
| <polygon points="0,${Ht} ${pts} ${W},${Ht}" fill="#3a3a46"/> |
| <polygon points="0,${Ht} ${pts} ${W},${Ht}" fill="#8ea2ef" clip-path="url(#cl-${rows.length})"/> |
| </svg>${dots}</div> |
| <span class="dpct">0%</span>`; |
| wrap.appendChild(row); |
| rows.push({d, rect: row.querySelector('clipPath rect'), pct: row.querySelector('.dpct')}); |
| }); |
| |
| let curDot = null, curAud = null; |
| wrap.addEventListener('click', (ev)=>{ |
| const dot = ev.target.closest('.exdot'); if(!dot) return; |
| if(curDot === dot){ curAud.pause(); return; } |
| if(curAud){ curAud.pause(); } |
| document.querySelectorAll('audio').forEach(o=>o.pause()); |
| const a = new Audio(dot.dataset.src); |
| curDot = dot; curAud = a; |
| dot.classList.add('playing'); |
| const off = ()=>{ dot.classList.remove('playing'); if(curDot===dot){curDot=null;curAud=null;} }; |
| a.addEventListener('pause', off); a.addEventListener('ended', off); |
| a.play(); |
| }); |
| const slider = document.getElementById('tau'), tv = document.getElementById('tauval'); |
| function update(){ |
| const t = parseFloat(slider.value); |
| tv.textContent = (t>=0?'+':'') + t.toFixed(2); |
| const fx = (t - H.lo) / (H.hi - H.lo); |
| rows.forEach(r=>{ |
| const x = Math.max(0, Math.min(1, fx)) * W; |
| r.rect.setAttribute('x', x); r.rect.setAttribute('width', W - x); |
| const exact = t <= H.lo ? r.d.n : r.d.bins.reduce((acc,v,i)=>{ |
| const b0 = H.lo + i*(H.hi-H.lo)/NB, b1 = b0 + (H.hi-H.lo)/NB; |
| if(t <= b0) return acc + v; |
| if(t >= b1) return acc; |
| return acc + v * (b1 - t) / (b1 - b0); |
| }, 0); |
| r.pct.textContent = (100 * exact / r.d.n).toFixed(1) + '%'; |
| }); |
| } |
| slider.addEventListener('input', update); |
| update(); |
| })(); |
| |
| |
| document.querySelectorAll('audio').forEach(a=>{ |
| a.addEventListener('play',()=>{ document.querySelectorAll('audio').forEach(o=>{ if(o!==a) o.pause(); }); }); |
| }); |
| </script> |
| </body> |
| </html> |
|
|