summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/mq_editor/index.html46
1 files changed, 45 insertions, 1 deletions
diff --git a/tools/mq_editor/index.html b/tools/mq_editor/index.html
index 61ff1ac..b37eaaf 100644
--- a/tools/mq_editor/index.html
+++ b/tools/mq_editor/index.html
@@ -349,6 +349,18 @@
<label><input type="checkbox" id="disableJitter"> Disable jitter</label>
<label><input type="checkbox" id="disableSpread"> Disable spread</label>
<label title="Test mode: force resonator synthesis for all partials (ignores per-partial mode setting)"><input type="checkbox" id="forceResonator"> Resonator (all)</label>
+ <div style="margin-top:6px;">
+ <label style="display:flex;align-items:center;gap:6px;" title="LP filter coefficient k1 in (0,1]. 1.0 = bypass.">
+ LP k1
+ <input type="range" id="lpK1" min="0.001" max="1.0" step="0.001" value="1.0" style="flex:1;min-width:0;">
+ <span id="lpK1Val" style="width:44px;text-align:right;">bypass</span>
+ </label>
+ <label style="display:flex;align-items:center;gap:6px;" title="HP filter coefficient k2 in (0,1]. 1.0 = bypass.">
+ HP k2
+ <input type="range" id="hpK2" min="0.001" max="1.0" step="0.001" value="1.0" style="flex:1;min-width:0;">
+ <span id="hpK2Val" style="width:44px;text-align:right;">bypass</span>
+ </label>
+ </div>
</div>
</div>
</div>
@@ -363,6 +375,34 @@
<script src="viewer.js"></script>
<script src="editor.js"></script>
<script>
+ // LP: y[n] = k*x[n] + (1-k)*y[n-1] => -3dB at cos(w) = (2-2k-k²)/(2(1-k))
+ function k1ToHz(k, sr) {
+ if (k >= 1.0) return sr / 2;
+ const cosW = (2 - 2*k - k*k) / (2*(1 - k));
+ return Math.acos(Math.max(-1, Math.min(1, cosW))) * sr / (2 * Math.PI);
+ }
+ // HP: y[n] = k*(y[n-1]+x[n]-x[n-1]) => -3dB from peak at cos(w) = 2k/(1+k²)
+ function k2ToHz(k, sr) {
+ if (k >= 1.0) return 0;
+ const cosW = 2*k / (1 + k*k);
+ return Math.acos(Math.max(-1, Math.min(1, cosW))) * sr / (2 * Math.PI);
+ }
+ function fmtHz(f) {
+ return f >= 1000 ? (f/1000).toFixed(1) + 'k' : Math.round(f) + 'Hz';
+ }
+ function getSR() { return (typeof audioBuffer !== 'undefined' && audioBuffer) ? audioBuffer.sampleRate : 44100; }
+
+ // LP/HP slider live display
+ document.getElementById('lpK1').addEventListener('input', function() {
+ const k = parseFloat(this.value);
+ const f = k1ToHz(k, getSR());
+ document.getElementById('lpK1Val').textContent = k >= 1.0 ? 'bypass' : fmtHz(f);
+ });
+ document.getElementById('hpK2').addEventListener('input', function() {
+ const k = parseFloat(this.value);
+ const f = k2ToHz(k, getSR());
+ document.getElementById('hpK2Val').textContent = k >= 1.0 ? 'bypass' : fmtHz(f);
+ });
let audioBuffer = null;
let viewer = null;
let audioContext = null;
@@ -632,8 +672,12 @@
const disableJitter = document.getElementById('disableJitter').checked;
const disableSpread = document.getElementById('disableSpread').checked;
const forceResonator = document.getElementById('forceResonator').checked;
+ const lpK1Raw = parseFloat(document.getElementById('lpK1').value);
+ const hpK2Raw = parseFloat(document.getElementById('hpK2').value);
+ const k1 = lpK1Raw < 1.0 ? lpK1Raw : null;
+ const k2 = hpK2Raw < 1.0 ? hpK2Raw : null;
const pcm = synthesizeMQ(partialsToUse, audioBuffer.sampleRate, audioBuffer.duration,
- integratePhase, {disableJitter, disableSpread, forceResonator});
+ integratePhase, {disableJitter, disableSpread, forceResonator, k1, k2});
if (viewer) {
viewer.setSynthStftCache(new STFTCache(pcm, audioBuffer.sampleRate, fftSize, parseInt(hopSize.value)));