diff options
Diffstat (limited to 'tools/mq_editor')
| -rw-r--r-- | tools/mq_editor/app.js | 36 | ||||
| -rw-r--r-- | tools/mq_editor/style.css | 4 |
2 files changed, 26 insertions, 14 deletions
diff --git a/tools/mq_editor/app.js b/tools/mq_editor/app.js index 20224a0..9857c64 100644 --- a/tools/mq_editor/app.js +++ b/tools/mq_editor/app.js @@ -481,6 +481,25 @@ function getSynthParams() { }; } +// Synthesize partials and return an AudioBuffer, trimmed to [t_start-margin, t_end+margin] +function getAudioBuffer(partials, margin = 0) { + const sr = audioBuffer.sampleRate; + const {integratePhase, opts} = getSynthParams(); + const pcm = synthesizeMQ(partials, sr, audioBuffer.duration, integratePhase, opts); + let startSample = 0, endSample = pcm.length; + if (margin >= 0 && partials.length > 0) { + const times = partials.flatMap(p => p.times); + const tStart = Math.min(...times); + const tEnd = Math.max(...times); + startSample = Math.max(0, Math.floor((tStart - margin) * sr)); + endSample = Math.min(pcm.length, Math.ceil((tEnd + margin) * sr)); + } + const trimmed = pcm.subarray(startSample, endSample); + const buf = audioContext.createBuffer(1, trimmed.length, sr); + buf.getChannelData(0).set(trimmed); + return buf; +} + // Play synthesized audio function playSynthesized() { if (!extractedPartials || extractedPartials.length === 0) { @@ -497,16 +516,14 @@ function playSynthesized() { const partialsToUse = extractedPartials.slice(0, keepCount).filter(p => !p.muted); setStatus(`Synthesizing ${partialsToUse.length}/${extractedPartials.length} partials (${keepPct.value}%)...`, 'info'); - const {integratePhase, opts} = getSynthParams(); - const pcm = synthesizeMQ(partialsToUse, audioBuffer.sampleRate, audioBuffer.duration, - integratePhase, opts); - if (viewer) { + const {integratePhase, opts} = getSynthParams(); + const pcm = synthesizeMQ(partialsToUse, audioBuffer.sampleRate, audioBuffer.duration, + integratePhase, opts); viewer.setSynthStftCache(new STFTCache(pcm, audioBuffer.sampleRate, fftSize, parseInt(hopSize.value))); } - const synthBuffer = audioContext.createBuffer(1, pcm.length, audioBuffer.sampleRate); - synthBuffer.getChannelData(0).set(pcm); + const synthBuffer = getAudioBuffer(partialsToUse); playAudioBuffer(synthBuffer, `Playing synthesized (${partialsToUse.length}/${extractedPartials.length} partials, ${keepPct.value}%)...`); } @@ -535,12 +552,7 @@ document.addEventListener('keydown', (e) => { const partial = extractedPartials[sel]; if (!partial) return; stopAudio(); - const {integratePhase, opts} = getSynthParams(); - const pcm = synthesizeMQ([partial], audioBuffer.sampleRate, audioBuffer.duration, - integratePhase, opts); - const buf = audioContext.createBuffer(1, pcm.length, audioBuffer.sampleRate); - buf.getChannelData(0).set(pcm); - playAudioBuffer(buf, `Playing partial #${sel}...`); + playAudioBuffer(getAudioBuffer([partial], 0.05), `Playing partial #${sel}...`); } else if (e.code === 'KeyP') { e.preventDefault(); if (viewer) viewer.togglePeaks(); diff --git a/tools/mq_editor/style.css b/tools/mq_editor/style.css index 87f033d..9563a57 100644 --- a/tools/mq_editor/style.css +++ b/tools/mq_editor/style.css @@ -29,9 +29,9 @@ button.contour-active { background: #145; border-color: #0cc; color: #aff; } #paramsPanel { display: none; position: absolute; z-index: 200; top: 100%; left: 0; margin-top: 4px; background: #222; border: 1px solid #555; border-radius: 4px; padding: 6px 0; white-space: nowrap; box-shadow: 0 4px 12px rgba(0,0,0,.5); } #paramsPanel.open { display: block; } #paramsBtn.params-open { background: #4a4a4a; border-color: #888; } -.param-group { display: flex; align-items: center; gap: 6px; padding: 5px 14px; border-bottom: 1px solid #333; } +.param-group { display: grid; grid-template-columns: auto 1fr; gap: 4px 10px; padding: 8px 14px; border-bottom: 1px solid #333; align-items: center; } .param-group:last-child { border-bottom: none; } -.group-label { font-size: 9px; color: #666; text-transform: uppercase; letter-spacing: 1px; white-space: nowrap; width: 80px; flex-shrink: 0; } +.group-label { grid-column: 1 / -1; font-size: 9px; color: #666; text-transform: uppercase; letter-spacing: 1px; } /* === Canvas & overlays === */ #canvas { border: 1px solid #555; background: #000; cursor: crosshair; display: block; flex-shrink: 0; } |
