thecollabagepatch commited on
Commit
1e3b782
·
1 Parent(s): 21a61ae

equal power crossfade in web app demo

Browse files
Files changed (2) hide show
  1. documentation.html +0 -5
  2. magentaRT_rt_tester.html +52 -15
documentation.html CHANGED
@@ -407,11 +407,6 @@ files.download('/content/checkpoint_1862001.tgz')</pre>
407
  <p><a href="/docs">auto-generated API docs (for all the http requests)</a></p>
408
  </div>
409
 
410
- <!-- <div class="section">
411
- <h2>contributors</h2>
412
- <p>Kevin Griffing and Andrew Luck</p>
413
- </div> -->
414
-
415
  <script>
416
  function copyCode(button) {
417
  const pre = button.parentElement;
 
407
  <p><a href="/docs">auto-generated API docs (for all the http requests)</a></p>
408
  </div>
409
 
 
 
 
 
 
410
  <script>
411
  function copyCode(button) {
412
  const pre = button.parentElement;
magentaRT_rt_tester.html CHANGED
@@ -106,8 +106,6 @@
106
  <label class="small"><input id="chkAutoUpdate" type="checkbox" checked /> Auto-update on slider change (150ms debounce)</label>
107
  <label class="small"><input id="chkLogAudio" type="checkbox" /> Log chunk sizes</label>
108
  <label class="small"><input id="chkRealtime" type="checkbox" checked /> Ask server to pace real-time</label>
109
- <!-- <label class="small"><input id="chkBootstrap" type="checkbox" checked /> Bootstrap fast (ASAP → flip to realtime)</label>
110
- <label class="small">Pre-roll chunks: <input id="numPreroll" type="number" min="0" max="12" step="1" value="3" style="width:60px"></label> -->
111
  </div>
112
  </div>
113
  </div>
@@ -241,8 +239,6 @@
241
  const rngGuid = $("rngGuid"), numGuid = $("numGuid");
242
  const rngTopk = $("rngTopk"), numTopk = $("numTopk");
243
  const rngVol = $("rngVol"), numVol = $("numVol");
244
- // const txtStyles = $("txtStyles");
245
- // const txtStyleWeights = $("txtStyleWeights");
246
  const chkUseMixStyle = $("chkUseMixStyle");
247
  const statusEl = $("status");
248
  const queueEl = $("queue");
@@ -268,8 +264,19 @@ const START_CUSHION = 0.12; // already used
268
 
269
  const fade = XFADE_MS / 1000;
270
 
 
 
 
 
 
 
 
 
 
 
 
271
  function scheduleAudioBuffer(abuf) {
272
- // Overlap-add crossfade scheduling (same as your scheduleWavBytes but taking a decoded buffer)
273
  const src = ctx.createBufferSource();
274
  const g = ctx.createGain();
275
  src.buffer = abuf;
@@ -279,13 +286,47 @@ function scheduleAudioBuffer(abuf) {
279
  const startAt = nextTime;
280
  const dur = abuf.duration;
281
 
282
- // Overlap by 'fade' so theres no dip
283
  nextTime = startAt + Math.max(0, dur - fade);
284
 
285
- g.gain.setValueAtTime(0.0, startAt);
286
- g.gain.linearRampToValueAtTime(1.0, startAt + fade);
287
- g.gain.setValueAtTime(1.0, startAt + Math.max(0, dur - fade));
288
- g.gain.linearRampToValueAtTime(0.0, startAt + dur);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
 
290
  src.start(startAt);
291
  scheduled.push({ src, when: startAt, dur });
@@ -301,10 +342,6 @@ function beginPlaybackFromPending() {
301
  const abuf = pending.shift();
302
  scheduleAudioBuffer(abuf);
303
  }
304
- // Flip server pacing to realtime after we’ve started, if bootstrapping was enabled
305
- // if ($("chkBootstrap").checked) {
306
- // try { ws?.send(JSON.stringify({ type: "update", pace: "realtime" })); } catch {}
307
- // }
308
  }
309
 
310
  // Audio chain
@@ -820,4 +857,4 @@ async function scheduleWavBytes(arrayBuffer) {
820
  })();
821
  </script>
822
  </body>
823
- </html>
 
106
  <label class="small"><input id="chkAutoUpdate" type="checkbox" checked /> Auto-update on slider change (150ms debounce)</label>
107
  <label class="small"><input id="chkLogAudio" type="checkbox" /> Log chunk sizes</label>
108
  <label class="small"><input id="chkRealtime" type="checkbox" checked /> Ask server to pace real-time</label>
 
 
109
  </div>
110
  </div>
111
  </div>
 
239
  const rngGuid = $("rngGuid"), numGuid = $("numGuid");
240
  const rngTopk = $("rngTopk"), numTopk = $("numTopk");
241
  const rngVol = $("rngVol"), numVol = $("numVol");
 
 
242
  const chkUseMixStyle = $("chkUseMixStyle");
243
  const statusEl = $("status");
244
  const queueEl = $("queue");
 
264
 
265
  const fade = XFADE_MS / 1000;
266
 
267
+ // Equal-power crossfading functions
268
+ function equalPowerFadeOut(t) {
269
+ // cos²(t * π/2) where t goes from 0 to 1
270
+ return Math.cos(t * Math.PI / 2) ** 2;
271
+ }
272
+
273
+ function equalPowerFadeIn(t) {
274
+ // sin²(t * π/2) where t goes from 0 to 1
275
+ return Math.sin(t * Math.PI / 2) ** 2;
276
+ }
277
+
278
  function scheduleAudioBuffer(abuf) {
279
+ // Equal-power crossfade scheduling
280
  const src = ctx.createBufferSource();
281
  const g = ctx.createGain();
282
  src.buffer = abuf;
 
286
  const startAt = nextTime;
287
  const dur = abuf.duration;
288
 
289
+ // Overlap by 'fade' so there's no dip
290
  nextTime = startAt + Math.max(0, dur - fade);
291
 
292
+ // Equal-power crossfading using custom curves
293
+ const numPoints = 64; // More points for smoother curves
294
+ const times = [];
295
+ const values = [];
296
+
297
+ // Fade in from 0 to 1 over fade duration
298
+ for (let i = 0; i <= numPoints; i++) {
299
+ const t = i / numPoints;
300
+ const time = startAt + t * fade;
301
+ const value = equalPowerFadeIn(t);
302
+ times.push(time);
303
+ values.push(value);
304
+ }
305
+
306
+ // Hold at 1.0 during the main portion
307
+ const holdStart = startAt + fade;
308
+ const holdEnd = startAt + Math.max(0, dur - fade);
309
+ if (holdEnd > holdStart) {
310
+ times.push(holdStart);
311
+ values.push(1.0);
312
+ times.push(holdEnd);
313
+ values.push(1.0);
314
+ }
315
+
316
+ // Fade out from 1 to 0 over fade duration
317
+ for (let i = 0; i <= numPoints; i++) {
318
+ const t = i / numPoints;
319
+ const time = startAt + Math.max(0, dur - fade) + t * fade;
320
+ const value = equalPowerFadeOut(t);
321
+ times.push(time);
322
+ values.push(value);
323
+ }
324
+
325
+ // Apply the envelope
326
+ g.gain.setValueAtTime(values[0], times[0]);
327
+ for (let i = 1; i < times.length; i++) {
328
+ g.gain.linearRampToValueAtTime(values[i], times[i]);
329
+ }
330
 
331
  src.start(startAt);
332
  scheduled.push({ src, when: startAt, dur });
 
342
  const abuf = pending.shift();
343
  scheduleAudioBuffer(abuf);
344
  }
 
 
 
 
345
  }
346
 
347
  // Audio chain
 
857
  })();
858
  </script>
859
  </body>
860
+ </html>