Quazim0t0 commited on
Commit
dbba743
Β·
verified Β·
1 Parent(s): afd3155

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -18
app.py CHANGED
@@ -51,6 +51,10 @@ try:
51
  except Exception:
52
  PIANO_LO, PIANO_HI, PIANO_FPS = 56, 86, 8
53
 
 
 
 
 
54
  _get_piano() # warm the piano Modular Mind at app startup (so the first play is instant)
55
 
56
 
@@ -183,13 +187,15 @@ FORCE_DARK_JS = """
183
  # ---- self-playing piano (a Modular Mind trained on the song) -----------------
184
  PIANO_CSS = """
185
  #mm-piano-wrap{max-width:920px;margin:6px auto 2px;font-family:system-ui,sans-serif}
186
- #mm-piano{display:flex;align-items:flex-end;justify-content:center;gap:2px;height:120px;
187
- background:#13131a;border:1px solid #2a2a35;border-radius:8px;padding:10px 8px;overflow-x:auto}
188
- .pk{box-sizing:border-box;border:1px solid #05050a;border-radius:0 0 3px 3px;flex:0 0 auto}
189
- .pk.white{width:20px;height:100px;background:#e9e9ee}
190
- .pk.black{width:14px;height:62px;background:#2b2b33}
191
- .pk.on.white{background:#7ad1ff;box-shadow:0 0 14px #7ad1ff}
192
- .pk.on.black{background:#3ba0d8;box-shadow:0 0 14px #3ba0d8}
 
 
193
  #mm-piano-ctrl{display:flex;gap:14px;align-items:center;justify-content:center;margin:8px auto 4px}
194
  #mm-piano-btn{cursor:pointer;background:#2a9d6a;color:#fff;border:none;border-radius:6px;
195
  padding:9px 18px;font-weight:700;font-size:14px}
@@ -225,6 +231,53 @@ PIANO_JS = r"""
225
  var specBox=document.getElementById('mm-piano-specs'), latBox=document.getElementById('mm-piano-latent');
226
  var NN=['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];
227
  function name(m){return NN[m%12]+(Math.floor(m/12)-1);}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  function buildSpecs(telem){
229
  if(built || !specBox || !telem) return; built=true;
230
  telem.spec.forEach(function(s){
@@ -311,16 +364,16 @@ PIANO_JS = r"""
311
  }catch(e){}
312
  }
313
  function releaseAll(){
314
- for(var mk in voices){ releaseNode(voices[mk]); var pe=document.getElementById('pk-'+mk); if(pe)pe.classList.remove('on'); }
315
  voices={};
316
  }
317
  function playFrame(midis){ // polyphony: strike new notes, hold sustained ones, release dropped ones
318
  var nw={}; (midis||[]).forEach(function(m){ if(m>0) nw[m]=1; });
319
  for(var mk in voices){ if(!nw[mk]){ releaseNode(voices[mk]);
320
- var pe=document.getElementById('pk-'+mk); if(pe)pe.classList.remove('on'); delete voices[mk]; } }
321
  var on=Object.keys(nw), vol=on.length>2?0.5:0.65;
322
  on.forEach(function(ms){ var m=+ms; if(!voices[m]){ var v=voice(m,vol); if(v) voices[m]=v;
323
- var el=document.getElementById('pk-'+m); if(el)el.classList.add('on'); } });
324
  if(noteEl){ noteEl.textContent= on.length ? ('β™ͺ '+on.map(function(ms){return name(+ms);}).join(' ')) : 'β™ͺ (rest)'; }
325
  }
326
  function tick(){ if(!playing) return; if(queue.length<10 && !fetching) fetchPhrase();
@@ -329,7 +382,7 @@ PIANO_JS = r"""
329
  if(!audio) audio=new (window.AudioContext||window.webkitAudioContext)();
330
  if(audio.state==='suspended'){ try{audio.resume();}catch(e){} }
331
  loadSamples(); // real piano loads in background; oscillator plays until then
332
- playing=true; btn.textContent='⏸ Pause';
333
  if(queue.length===0) fetchPhrase();
334
  if(!timer) timer=setInterval(tick, PLAY_MS);
335
  }
@@ -342,12 +395,15 @@ PIANO_JS = r"""
342
  """
343
  PIANO_HTML = """
344
  <div id="mm-piano-wrap">
345
- <div id="mm-piano"></div>
 
 
 
346
  <div id="mm-piano-ctrl">
347
  <button id="mm-piano-btn">β–Ά Let the Modular Mind play</button>
348
  <span id="mm-piano-note">β™ͺ</span>
349
  </div>
350
- <div id="mm-piano-lbl">specialists firing for each chord β€” Bass / Tenor / Soprano own a register; Sustain / Onset / Phrase are modulators that only write to the shared latent</div>
351
  <div id="mm-piano-specs"></div>
352
  <div id="mm-piano-latent" title="RecursiveLink shared latent"></div>
353
  </div>
@@ -369,7 +425,7 @@ HEAD = (
369
  )
370
 
371
  INTRO = """
372
- # πŸ„ ModuleMind - Quazim0t0's Thousand Token Wood Entry
373
  A mini **Dark-Souls-style** duel where the boss is controlled by a **Modular Mind** β€” six tiny
374
  specialist networks that communicate through a **shared latent** (RecursiveLink) and a coordinator
375
  that picks each move. The brain was **trained by self-play reinforcement learning**, not scripted.
@@ -378,9 +434,15 @@ steer the fight through the latent. **Click *Enter the Fog* and click the game o
378
  """
379
 
380
  # ---- placeholder repo link (replace REPO_URL with your real GitHub URL) ------
381
- REPO_URL = "" # TODO: replace with the real repo
382
  REPO_MD = f"""
 
 
 
 
383
 
 
 
384
  """
385
 
386
  TECH_MD = r"""
@@ -482,12 +544,14 @@ Under the boss fight, the *same architecture* (tiny specialists β†’ `RecursiveLi
482
  applied to **playing piano in chords**. It was trained by **multi-note next-frame prediction** on a
483
  *polyphonic* transcription of a song: six specialists (Bass / Tenor / Soprano registers + Sustain /
484
  Onset / Phrase modulators) emit latents, the bridge merges them, and the coordinator picks the **set
485
- of notes** to play next. It plays itself with **real recorded acoustic-piano samples**. Press **play**
486
- and watch the keys + specialists light up.
 
 
487
  <sub>Rough by design β€” one song, a tiny model, crude polyphonic transcription β€” the *method carrying over* is the point.</sub>
488
  """
489
 
490
- with gr.Blocks(theme=gr.themes.Base(), title="Quazim0t0's πŸ„ Thousand Token Wood Entry", head=HEAD) as demo:
491
  gr.Markdown(INTRO)
492
  gr.HTML(INDEX_HTML)
493
 
@@ -526,4 +590,7 @@ if __name__ == "__main__":
526
  server_name="0.0.0.0",
527
  server_port=int(os.environ.get("PORT", "7860")),
528
  allowed_paths=[AUDIO_DIR, PIANO_SAMPLES_DIR],
 
 
 
529
  )
 
51
  except Exception:
52
  PIANO_LO, PIANO_HI, PIANO_FPS = 56, 86, 8
53
 
54
+ # the performance is restyled live into A minor with the bass lifted away (see
55
+ # piano/poly_mind.py stylize_midi), so the on-screen keyboard starts at middle C
56
+ PIANO_LO = max(PIANO_LO, 60)
57
+
58
  _get_piano() # warm the piano Modular Mind at app startup (so the first play is instant)
59
 
60
 
 
187
  # ---- self-playing piano (a Modular Mind trained on the song) -----------------
188
  PIANO_CSS = """
189
  #mm-piano-wrap{max-width:920px;margin:6px auto 2px;font-family:system-ui,sans-serif}
190
+ #mm-piano-stage{position:relative;background:radial-gradient(ellipse at 50% 110%,#1b1430 0%,#0c0c14 62%,#08080e 100%);
191
+ border:1px solid #2a2a35;border-radius:10px;padding:0 8px 12px;overflow-x:auto;overflow-y:hidden}
192
+ #mm-piano-roll{display:block;width:100%;height:150px}
193
+ #mm-piano{display:flex;align-items:flex-end;justify-content:center;gap:2px;height:112px}
194
+ .pk{box-sizing:border-box;border:1px solid #05050a;border-radius:0 0 4px 4px;flex:0 0 auto;
195
+ transition:background .07s ease,box-shadow .07s ease}
196
+ .pk.white{width:20px;height:100px;background:linear-gradient(180deg,#f4f4f8 0%,#d6d6e0 88%,#b9b9c6 100%)}
197
+ .pk.black{width:14px;height:62px;background:linear-gradient(180deg,#3a3a46 0%,#1b1b23 100%)}
198
+ .pk.on{transform:translateY(1px)}
199
  #mm-piano-ctrl{display:flex;gap:14px;align-items:center;justify-content:center;margin:8px auto 4px}
200
  #mm-piano-btn{cursor:pointer;background:#2a9d6a;color:#fff;border:none;border-radius:6px;
201
  padding:9px 18px;font-weight:700;font-size:14px}
 
231
  var specBox=document.getElementById('mm-piano-specs'), latBox=document.getElementById('mm-piano-latent');
232
  var NN=['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];
233
  function name(m){return NN[m%12]+(Math.floor(m/12)-1);}
234
+ // ---- light show: glowing note trails rise off the keys while they sound ----
235
+ var roll=document.getElementById('mm-piano-roll');
236
+ var rctx=roll?roll.getContext('2d'):null, trails=[], sparks=[], keyTrail={}, rafOn=false;
237
+ function hue(m){return ((m%12)*30+200)%360;} // pitch class -> color wheel
238
+ function ensureRaf(){ if(rctx && !rafOn){ rafOn=true; requestAnimationFrame(draw); } }
239
+ function draw(){
240
+ var w=roll.clientWidth, hgt=roll.clientHeight, now=performance.now(), v=0.05;
241
+ if(roll.width!==w) roll.width=w; if(roll.height!==hgt) roll.height=hgt;
242
+ rctx.clearRect(0,0,w,hgt);
243
+ for(var i=trails.length-1;i>=0;i--){ var tr=trails[i];
244
+ var top=hgt-(now-tr.t0)*v, bot=hgt-(tr.t1?(now-tr.t1)*v:0);
245
+ if(bot<-30){ trails.splice(i,1); continue; }
246
+ top=Math.max(top,-30);
247
+ var g=rctx.createLinearGradient(0,top,0,bot);
248
+ g.addColorStop(0,'hsla('+tr.h+',85%,62%,0)');
249
+ g.addColorStop(1,'hsla('+tr.h+',85%,62%,0.9)');
250
+ rctx.shadowColor='hsl('+tr.h+',85%,60%)'; rctx.shadowBlur=10;
251
+ rctx.fillStyle=g; rctx.fillRect(tr.x,top,tr.w,Math.max(2,bot-top));
252
+ }
253
+ rctx.shadowBlur=0;
254
+ for(var j=sparks.length-1;j>=0;j--){ var s=sparks[j], a=1-(now-s.t0)/650;
255
+ if(a<=0){ sparks.splice(j,1); continue; }
256
+ s.x+=s.vx; s.y+=s.vy;
257
+ rctx.fillStyle='hsla('+s.h+',95%,72%,'+a.toFixed(2)+')';
258
+ rctx.fillRect(s.x,s.y,2.2,2.2);
259
+ }
260
+ if(!playing && !trails.length && !sparks.length){ rafOn=false; rctx.clearRect(0,0,w,hgt); return; }
261
+ requestAnimationFrame(draw);
262
+ }
263
+ function strikeFx(m,el){
264
+ if(!rctx||!el) return;
265
+ var x=el.offsetLeft-roll.offsetLeft, wd=el.offsetWidth, hh=hue(m), now=performance.now();
266
+ var tr={x:x,w:wd,h:hh,t0:now,t1:null};
267
+ trails.push(tr); keyTrail[m]=tr;
268
+ for(var i=0;i<6;i++) sparks.push({x:x+wd/2,y:roll.clientHeight-3,
269
+ vx:(Math.random()-0.5)*1.6, vy:-(0.6+Math.random()*1.4), h:hh, t0:now});
270
+ ensureRaf();
271
+ }
272
+ function endTrail(m){ if(keyTrail[m]){ keyTrail[m].t1=performance.now(); delete keyTrail[m]; } }
273
+ function lightKey(m,on){
274
+ var el=document.getElementById('pk-'+m); if(!el) return el;
275
+ if(on){ el.classList.add('on'); var hh=hue(m);
276
+ el.style.background='hsl('+hh+',82%,'+(BLACK[m%12]?'46%':'68%')+')';
277
+ el.style.boxShadow='0 0 18px hsl('+hh+',85%,60%)';
278
+ } else { el.classList.remove('on'); el.style.background=''; el.style.boxShadow=''; }
279
+ return el;
280
+ }
281
  function buildSpecs(telem){
282
  if(built || !specBox || !telem) return; built=true;
283
  telem.spec.forEach(function(s){
 
364
  }catch(e){}
365
  }
366
  function releaseAll(){
367
+ for(var mk in voices){ releaseNode(voices[mk]); lightKey(+mk,false); endTrail(+mk); }
368
  voices={};
369
  }
370
  function playFrame(midis){ // polyphony: strike new notes, hold sustained ones, release dropped ones
371
  var nw={}; (midis||[]).forEach(function(m){ if(m>0) nw[m]=1; });
372
  for(var mk in voices){ if(!nw[mk]){ releaseNode(voices[mk]);
373
+ lightKey(+mk,false); endTrail(+mk); delete voices[mk]; } }
374
  var on=Object.keys(nw), vol=on.length>2?0.5:0.65;
375
  on.forEach(function(ms){ var m=+ms; if(!voices[m]){ var v=voice(m,vol); if(v) voices[m]=v;
376
+ strikeFx(m, lightKey(m,true)); } });
377
  if(noteEl){ noteEl.textContent= on.length ? ('β™ͺ '+on.map(function(ms){return name(+ms);}).join(' ')) : 'β™ͺ (rest)'; }
378
  }
379
  function tick(){ if(!playing) return; if(queue.length<10 && !fetching) fetchPhrase();
 
382
  if(!audio) audio=new (window.AudioContext||window.webkitAudioContext)();
383
  if(audio.state==='suspended'){ try{audio.resume();}catch(e){} }
384
  loadSamples(); // real piano loads in background; oscillator plays until then
385
+ playing=true; btn.textContent='⏸ Pause'; ensureRaf();
386
  if(queue.length===0) fetchPhrase();
387
  if(!timer) timer=setInterval(tick, PLAY_MS);
388
  }
 
395
  """
396
  PIANO_HTML = """
397
  <div id="mm-piano-wrap">
398
+ <div id="mm-piano-stage">
399
+ <canvas id="mm-piano-roll"></canvas>
400
+ <div id="mm-piano"></div>
401
+ </div>
402
  <div id="mm-piano-ctrl">
403
  <button id="mm-piano-btn">β–Ά Let the Modular Mind play</button>
404
  <span id="mm-piano-note">β™ͺ</span>
405
  </div>
406
+ <div id="mm-piano-lbl">restyled live into <b>A minor</b> β€” every note is lifted out of the bass and snapped to the minor scale Β· Bass / Tenor / Soprano own a register; Sustain / Onset / Phrase are modulators that only write to the shared latent</div>
407
  <div id="mm-piano-specs"></div>
408
  <div id="mm-piano-latent" title="RecursiveLink shared latent"></div>
409
  </div>
 
425
  )
426
 
427
  INTRO = """
428
+ # πŸ„ Quazim0t0's Thousand Token Wood Entry
429
  A mini **Dark-Souls-style** duel where the boss is controlled by a **Modular Mind** β€” six tiny
430
  specialist networks that communicate through a **shared latent** (RecursiveLink) and a coordinator
431
  that picks each move. The brain was **trained by self-play reinforcement learning**, not scripted.
 
434
  """
435
 
436
  # ---- placeholder repo link (replace REPO_URL with your real GitHub URL) ------
437
+ REPO_URL = "https://github.com/your-username/ModularMind" # TODO: replace with the real repo
438
  REPO_MD = f"""
439
+ ### πŸ“¦ Get the full Modular Mind project
440
+ This Space runs a **tiny, specialist-scale** version of the architecture. The full,
441
+ production-scale **Modular Mind** β€” transformer specialists (MLA / MoE / Hyper-Connections),
442
+ the `RecursiveLink` latent bridge, context-doubling and the residual latent highway β€” lives on GitHub:
443
 
444
+ ### πŸ‘‰ [**Download / view the Modular Mind repo on GitHub**]({REPO_URL})
445
+ *(placeholder link β€” swap `{REPO_URL}` for your actual repository)*
446
  """
447
 
448
  TECH_MD = r"""
 
544
  applied to **playing piano in chords**. It was trained by **multi-note next-frame prediction** on a
545
  *polyphonic* transcription of a song: six specialists (Bass / Tenor / Soprano registers + Sustain /
546
  Onset / Phrase modulators) emit latents, the bridge merges them, and the coordinator picks the **set
547
+ of notes** to play next. It plays itself with **real recorded acoustic-piano samples**, and the
548
+ performance is **restyled live into A minor** β€” every note is lifted out of the bass register and
549
+ snapped to the minor scale before it reaches the keys. Press **play** and watch each note send a
550
+ glowing trail of light off the keyboard.
551
  <sub>Rough by design β€” one song, a tiny model, crude polyphonic transcription β€” the *method carrying over* is the point.</sub>
552
  """
553
 
554
+ with gr.Blocks(title="Quazim0t0's πŸ„ Thousand Token Wood Entry") as demo:
555
  gr.Markdown(INTRO)
556
  gr.HTML(INDEX_HTML)
557
 
 
590
  server_name="0.0.0.0",
591
  server_port=int(os.environ.get("PORT", "7860")),
592
  allowed_paths=[AUDIO_DIR, PIANO_SAMPLES_DIR],
593
+ # Gradio 6 moved these from the Blocks constructor to launch()
594
+ theme=gr.themes.Base(),
595
+ head=HEAD,
596
  )