landing / index.html
yonghyunk1m's picture
Add Zhi Zhong (Sony Group Corporation) to author list
bc86655 verified
Raw
History Blame Contribute Delete
38.9 kB
<!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 ---------- */
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)}
/* ---------- shared ---------- */
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 ---------- */
.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)}}
/* ---------- pipeline ---------- */
.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}
/* ---------- numbers ---------- */
.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)}
/* ---------- modes ---------- */
.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}
/* ---------- listen ---------- */
.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}
/* ---------- score explorer ---------- */
.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} }
/* ---------- anchor ---------- */
.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 ---------- */
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}
/* ---------- responsive ---------- */
@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>
<!-- ================= HERO ================= -->
<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 &amp; models</a>
</div>
<div class="scrollcue reveal d4">scroll&nbsp;&darr;</div>
</div>
</section>
<!-- ================= HOW ================= -->
<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&nbsp;vs.&nbsp;B comparisons.</p>
<div class="face reveal d3">
<img id="faceimg" src="assets/tunejury_logo.webp" alt="">
<span class="roll" id="facelabel">TuneJury &middot; released</span>
</div>
<div class="pipe reveal d3">
<div class="node" id="pin"><span class="roll">Prompt + audio</span></div><div class="arrow">&rarr;</div>
<div class="node frozen" id="penc"><span class="flake">&#10052;</span><span class="roll" id="penclabel">CLAP&nbsp;+&nbsp;MERT</span></div><div class="arrow">&rarr;</div>
<div class="node head">MLP head</div><div class="arrow">&rarr;</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>
<!-- ================= NUMBERS ================= -->
<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 &middot; SongEval 2,491 &middot; MusicPrefs 2,012 &middot; Music Arena 571</p>
</div>
</div>
</section>
<!-- ================= MODES ================= -->
<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&nbsp;=&nbsp;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>
<!-- ================= LISTEN ================= -->
<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">&ldquo;A dark trance track featuring accordion, blending hypnotic rhythms with melancholic melodies and a pervasive, atmospheric mood.&rdquo;</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">&ldquo;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. &hellip;&rdquo;</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">&ldquo;A fast garage track featuring an electric guitar, driven by raw energy and a loose, rhythmic feel.&rdquo;</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>
<!-- ================= SCORES ================= -->
<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 &gt; &tau; = <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 &tau;.</p>
</div>
</section>
<!-- ================= ANCHOR ================= -->
<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&times;</b>
<span>less calibration data than from-scratch retraining,<br>at the same accuracy ceiling<sup>7</sup></span>
</div>
</div>
</div>
</section>
<!-- ================= FOOTER ================= -->
<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 &ldquo;pop, classical, percussion&rdquo;. 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&rsquo; 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&nbsp;=&nbsp;10 matches from-scratch retraining at K&nbsp;=&nbsp;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> &middot;
<a href="https://arxiv.org/abs/1612.01840" target="_blank" rel="noopener">FMA</a> &middot;
<a href="https://ismir2009.ismir.net/proceedings/OS5-5.pdf" target="_blank" rel="noopener">MagnaTagATune</a> &middot;
<a href="https://archives.ismir.net/ismir2018/paper/000248.pdf" target="_blank" rel="noopener">OpenMIC</a> &middot;
<a href="https://arxiv.org/abs/2406.02255" target="_blank" rel="noopener">MidiCaps</a> &middot;
<a href="https://arxiv.org/abs/2301.11325" target="_blank" rel="noopener">MusicCaps</a> &middot;
<a href="https://arxiv.org/abs/2311.10057" target="_blank" rel="noopener">Song Describer Dataset</a> &middot;
<a href="https://arxiv.org/abs/2507.20900" target="_blank" rel="noopener">Music Arena</a> &middot;
<a href="https://arxiv.org/abs/2503.16669" target="_blank" rel="noopener">MusicPrefs</a> &middot;
<a href="https://arxiv.org/abs/2506.19085" target="_blank" rel="noopener">AIME</a> &middot;
<a href="https://arxiv.org/abs/2505.10793" target="_blank" rel="noopener">SongEval</a></p>
<p><b>Models &amp; methods:</b>
<a href="https://arxiv.org/abs/2211.06687" target="_blank" rel="noopener">LAION-CLAP</a> &middot;
<a href="https://arxiv.org/abs/2306.00107" target="_blank" rel="noopener">MERT</a> &middot;
<a href="https://arxiv.org/abs/2501.01108" target="_blank" rel="noopener">MuQ-MuLan</a> &middot;
<a href="https://arxiv.org/abs/2306.05284" target="_blank" rel="noopener">MusicGen</a> &middot;
<a href="https://arxiv.org/abs/2308.05734" target="_blank" rel="noopener">AudioLDM 2</a> &middot;
<a href="https://arxiv.org/abs/2506.00045" target="_blank" rel="noopener">ACE-Step</a> &middot;
<a href="https://arxiv.org/abs/2412.21037" target="_blank" rel="noopener">TangoFlux</a> &middot;
<a href="https://arxiv.org/abs/2505.08175" target="_blank" rel="noopener">Stable Audio Open Small</a> &middot;
<a href="https://arxiv.org/abs/2508.06098" target="_blank" rel="noopener">MeanAudio</a> &middot;
<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 &amp; 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>&sharp;</sup> &middot; Junwon Lee<sup>&flat;&flat;</sup> &middot; Haiwen Xia<sup>&natural;&natural;</sup> &middot; Yinghao Ma<sup>&sharp;&sharp;</sup> &middot; Junghyun Koo<sup>&natural;</sup> &middot; Koichi Saito<sup>&natural;</sup> &middot; Zhi Zhong<sup>&flat;&natural;</sup> &middot; Yuki Mitsufuji<sup>&natural;</sup> &middot; Chris Donahue<sup>&flat;</sup></p>
<p><sup>&flat;</sup>Carnegie Mellon University &middot; <sup>&natural;</sup>Sony AI &middot; <sup>&flat;&natural;</sup>Sony Group Corporation &middot; <sup>&sharp;</sup>Georgia Tech &middot; <sup>&flat;&flat;</sup>KAIST &middot; <sup>&natural;&natural;</sup>Peking University &middot; <sup>&sharp;&sharp;</sup>QMUL</p>
</div>
<p class="fineprint">Checkpoint released under CC-BY-NC 4.0 &middot; An Apache 2.0 variant is included for commercial use</p>
</footer>
<script>
// scroll reveal
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));
// count-up
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));
// pipeline configuration cycle
const cfgs = [
{i:'Prompt + audio', e:'CLAP&nbsp;+&nbsp;MERT', s:'s = +0.42', n:'Released checkpoint. Encoders stay frozen, and only the head is trained.',
f:{hue:0, ring:'#3552c8', label:'TuneJury &middot; released'}},
{i:'Audio only', e:'CLAP&nbsp;+&nbsp;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 &middot; 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 &middot; MuQ swap'}},
];
if(!reduced){
let ci = 0, curFace = 'TuneJury &middot; 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; // reflow
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);
}
// score explorer
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')});
});
// example dot playback
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();
})();
// one audio at a time
document.querySelectorAll('audio').forEach(a=>{
a.addEventListener('play',()=>{ document.querySelectorAll('audio').forEach(o=>{ if(o!==a) o.pause(); }); });
});
</script>
</body>
</html>