BoxOfColors commited on
Commit
782f393
·
1 Parent(s): 1cf1eb7
Files changed (1) hide show
  1. app.py +31 -25
app.py CHANGED
@@ -1328,31 +1328,45 @@ def _build_waveform_html(audio_path: str, segments: list, slot_id: str,
1328
  const buf = new Uint8Array(bin.length);
1329
  for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
1330
 
1331
- const AudioCtx = window.AudioContext || window.webkitAudioContext;
1332
- if (!AudioCtx) {{ console.warn('[waveform {slot_id}] No AudioContext available'); }}
1333
- else {{
1334
- // Use OfflineAudioContext so decoding works even without user gesture
1335
- const tmpCtx = new AudioCtx({{latencyHint:'playback', sampleRate:44100}});
1336
- tmpCtx.decodeAudioData(buf.buffer.slice(0), function(audioBuffer) {{
 
 
 
 
1337
  const channelData = audioBuffer.getChannelData(0);
1338
  const duration = audioBuffer.duration;
1339
- tmpCtx.close();
 
1340
 
1341
- // Now wait for the canvas to have layout width before drawing
1342
  function tryDraw() {{
1343
  const canvas = document.getElementById('wf_canvas_{slot_id}');
1344
- if (!canvas) {{ setTimeout(tryDraw, 100); return; }}
1345
- // Force a width by walking up to a sized ancestor if needed
1346
  let W = canvas.getBoundingClientRect().width;
1347
- if (W <= 0) W = canvas.parentElement ? canvas.parentElement.getBoundingClientRect().width : 0;
1348
- if (W <= 0) {{ setTimeout(tryDraw, 100); return; }}
 
 
 
1349
  drawWaveform(channelData, duration);
1350
  attachVideoSync();
1351
  }}
1352
  tryDraw();
1353
- }}, function(err) {{
 
 
 
1354
  console.error('[waveform {slot_id}] decodeAudioData error:', err);
1355
  }});
 
 
 
 
 
1356
  }}
1357
  }})();
1358
  </script>
@@ -1437,19 +1451,11 @@ def _update_slot_visibility(n):
1437
  # ================================================================== #
1438
 
1439
  _SLOT_CSS = """
1440
- /* Make all video components (input and output) use the same responsive
1441
- aspect-ratio container so they match at any window size. */
1442
- .gradio-video,
1443
- .gradio-video > div {
1444
- aspect-ratio: 16 / 9;
1445
- width: 100%;
1446
- height: auto !important;
1447
- min-height: unset !important;
1448
- max-height: unset !important;
1449
- }
1450
  .gradio-video video {
1451
- width: 100%;
1452
- height: 100%;
 
1453
  object-fit: contain;
1454
  }
1455
  """
 
1328
  const buf = new Uint8Array(bin.length);
1329
  for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
1330
 
1331
+ // OfflineAudioContext for decoding works without user gesture, no playback
1332
+ const OfflineCtx = window.OfflineAudioContext || window.webkitOfflineAudioContext;
1333
+ const AudioCtx = window.AudioContext || window.webkitAudioContext;
1334
+ if (!OfflineCtx && !AudioCtx) {{
1335
+ console.warn('[waveform {slot_id}] No AudioContext available');
1336
+ }} else {{
1337
+ // Decode using a throwaway AudioContext (OfflineAudioContext.decodeAudioData
1338
+ // has the same user-gesture restriction in some browsers, so use regular one)
1339
+ const tmpCtx = new (AudioCtx || OfflineCtx)({{sampleRate: 44100}});
1340
+ const doRender = function(audioBuffer) {{
1341
  const channelData = audioBuffer.getChannelData(0);
1342
  const duration = audioBuffer.duration;
1343
+ try {{ tmpCtx.close(); }} catch(e) {{}}
1344
+ console.log('[waveform {slot_id}] decoded OK, duration=' + duration + 's, samples=' + channelData.length);
1345
 
 
1346
  function tryDraw() {{
1347
  const canvas = document.getElementById('wf_canvas_{slot_id}');
1348
+ if (!canvas) {{ console.log('[waveform {slot_id}] canvas not in DOM yet'); setTimeout(tryDraw, 100); return; }}
 
1349
  let W = canvas.getBoundingClientRect().width;
1350
+ if (W <= 0 && canvas.parentElement) W = canvas.parentElement.getBoundingClientRect().width;
1351
+ if (W <= 0 && canvas.parentElement && canvas.parentElement.parentElement)
1352
+ W = canvas.parentElement.parentElement.getBoundingClientRect().width;
1353
+ console.log('[waveform {slot_id}] tryDraw W=' + W);
1354
+ if (W <= 0) {{ setTimeout(tryDraw, 150); return; }}
1355
  drawWaveform(channelData, duration);
1356
  attachVideoSync();
1357
  }}
1358
  tryDraw();
1359
+ }};
1360
+
1361
+ // decodeAudioData with promise fallback
1362
+ const decodePromise = tmpCtx.decodeAudioData(buf.buffer.slice(0), doRender, function(err) {{
1363
  console.error('[waveform {slot_id}] decodeAudioData error:', err);
1364
  }});
1365
+ if (decodePromise && typeof decodePromise.then === 'function') {{
1366
+ decodePromise.then(doRender).catch(function(err) {{
1367
+ console.error('[waveform {slot_id}] decodeAudioData promise error:', err);
1368
+ }});
1369
+ }}
1370
  }}
1371
  }})();
1372
  </script>
 
1451
  # ================================================================== #
1452
 
1453
  _SLOT_CSS = """
1454
+ /* Responsive video: fills column width, height auto from aspect ratio */
 
 
 
 
 
 
 
 
 
1455
  .gradio-video video {
1456
+ width: 100% !important;
1457
+ height: auto !important;
1458
+ max-height: 60vh !important;
1459
  object-fit: contain;
1460
  }
1461
  """