Attempt to block animation when pattern highlighting disabled

This commit is contained in:
Aria
2025-11-22 22:07:10 -06:00
parent 34620ffed2
commit 8b66002dd0
4 changed files with 30 additions and 34 deletions
+15 -5
View File
@@ -162,6 +162,7 @@ export class StrudelMirror {
this.onDraw = onDraw || this.draw;
this.id = id || s4();
this.solo = solo;
this.hasPainters = false;
this.drawer = new Drawer((haps, time, _, painters) => {
const currentFrame = haps.filter((hap) => hap.isActive(time));
@@ -177,7 +178,7 @@ export class StrudelMirror {
onToggle: (started) => {
replOptions?.onToggle?.(started);
if (started) {
this.drawer.start(this.repl.scheduler);
this.shouldAnimate() && this.drawer.start(this.repl.scheduler);
if (this.solo) {
// stop other repls when this one is started
document.dispatchEvent(
@@ -207,9 +208,10 @@ export class StrudelMirror {
updateWidgets(this.editor, widgets);
updateMiniLocations(this.editor, this.miniLocations);
replOptions?.afterEval?.(options);
this.hasPainters = options.pattern.getPainters().length > 0;
// if no painters are set (.onPaint was not called), then we only need
// the present moment (for highlighting)
const drawTime = options.pattern.getPainters().length ? this.drawTime : [0, 0];
const drawTime = this.hasPainters ? this.drawTime : [0, 0];
this.drawer.setDrawTime(drawTime);
// invalidate drawer after we've set the appropriate drawTime
this.drawer.invalidate(this.repl.scheduler);
@@ -327,6 +329,12 @@ export class StrudelMirror {
}
highlightMiniLocations(this.editor, time, haps);
}
shouldAnimate() {
return (
this.repl.scheduler.started &&
(this.isPatternHighlightingEnabled || this.hasPainters || this.onDraw !== this.draw)
);
}
setFontSize(size) {
this.root.style.fontSize = size + 'px';
}
@@ -343,13 +351,15 @@ export class StrudelMirror {
return;
}
value = parseBooleans(value);
if (key === 'isPatternHighlightingEnabled') {
this.isPatternHighlightingEnabled = value;
}
const newValue = extensions[key](value, this);
this.editor.dispatch({
effects: compartments[key].reconfigure(newValue),
});
if (key === 'isPatternHighlightingEnabled') {
this.isPatternHighlightingEnabled = value;
this.drawer.stop();
this.shouldAnimate() && this.drawer.start(this.repl.scheduler);
}
if (key === 'theme') {
activateTheme(value);
}
+4 -13
View File
@@ -191,22 +191,13 @@ export function registerSynthSounds() {
getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend);
const vibratoOscillator = getVibratoOscillator(o.parameters.get('detune'), value, begin);
const fm = applyFM(o.parameters.get('frequency'), value, begin);
getParamADSR(
o.parameters.get('postgain'),
attack,
decay,
sustain,
release,
0,
0.3 * gainAdjustment,
begin,
holdend,
'linear',
);
const envGain = o.connect(gainNode(1));
getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 0.3 * gainAdjustment, begin, holdend, 'linear');
const timeoutNode = webAudioTimeout(
ac,
() => {
destroyAudioWorkletNode(o);
envGain.disconnect();
releaseVoice('supersaw', o);
onended();
fm?.stop();
@@ -217,7 +208,7 @@ export function registerSynthSounds() {
);
return {
node: o,
node: envGain,
stop: (time) => {
timeoutNode.stop(time);
},
+5 -2
View File
@@ -4,6 +4,7 @@ import {
applyFM,
applyParameterModulators,
claimVoice,
gainNode,
getADSRValues,
getFrequencyFromValue,
getParamADSR,
@@ -320,9 +321,10 @@ export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) {
);
const vibratoOscillator = getVibratoOscillator(source.parameters.get('detune'), value, t);
const fm = applyFM(source.parameters.get('frequency'), value, t);
getParamADSR(source.parameters.get('postgain'), attack, decay, sustain, release, 0, 0.3, t, holdEnd, 'linear');
const envGain = source.connect(gainNode(1));
getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 0.3, t, holdEnd, 'linear');
getPitchEnvelope(source.parameters.get('detune'), value, t, holdEnd);
const handle = { node: source };
const handle = { node: envGain };
const timeoutNode = webAudioTimeout(
ac,
() => {
@@ -330,6 +332,7 @@ export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) {
fm?.stop();
wtPosModulators?.disconnect();
wtWarpModulators?.disconnect();
envGain.disconnect();
destroyAudioWorkletNode(source);
releaseVoice(voiceKey, source);
onended();
+6 -14
View File
@@ -43,7 +43,7 @@ const getDetuner = (unison, detune) => {
function fastPow2(x) {
// Taylor approximation of 2 ^ x
const a = x * 0.6931471805599453; // ln(2)
return 1 + a * (1 + a * (0.8333333333333333 + a));
return 1 + a * (1 + a * (0.5 + (a / 6)));
}
const applySemitoneDetuneToFrequency = (frequency, detune) => {
@@ -517,10 +517,6 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
defaultValue: 0,
min: 0,
},
{
name: 'postgain',
defaultValue: 1,
},
];
}
process(_input, outputs, params) {
@@ -548,10 +544,9 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
gainR = Math.sqrt(0.5 + 0.5 * panspread);
}
for (let i = 0; i < output[0].length; i++) {
const postgain = pv(params.postgain, i);
const panspread = pv(params.panspread, i) * 0.5 + 0.5;
gainL = Math.sqrt(1 - panspread) * postgain;
gainR = Math.sqrt(panspread) * postgain;
gainL = Math.sqrt(1 - panspread);
gainR = Math.sqrt(panspread);
// Main detuning (a-rate path)
detune ??= pv(params.detune, i);
freqspread ??= pv(params.freqspread, i);
@@ -1154,7 +1149,6 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor {
{ name: 'warp', defaultValue: 0, min: 0, max: 1 },
{ name: 'warpMode', defaultValue: 0 },
{ name: 'panspread', defaultValue: 0.7, min: 0, max: 1 },
{ name: 'postgain', defaultValue: 1, min: 0 },
];
}
@@ -1187,7 +1181,7 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor {
phases[i] = Math.random() * phaseRand;
}
this.voices = options.voices;
this.voicesDenom = 1 / Math.sqrt(this.voices);
this.normalizer = 1 / Math.sqrt(this.voices);
}
_mirror(x) {
@@ -1364,8 +1358,6 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor {
const interpT = idx - fIdx;
const warpAmount = clamp(pv(params.warp, i), 0, 1);
const warpMode = pv(params.warpMode, i);
const postgain = pv(params.postgain, i);
const normalizer = postgain * this.voicesDenom;
panspread ??= this.voices > 1 ? clamp(pv(params.panspread, i), 0, 1) : 0;
gainL ??= Math.sqrt(0.5 - 0.5 * panspread);
gainR ??= Math.sqrt(0.5 + 0.5 * panspread);
@@ -1384,8 +1376,8 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor {
if (warpMode === WarpMode.FLIP && this.phases[n] < warpAmount) {
s = -s;
}
outL[i] += s * gainL * normalizer;
outR[i] += s * gainR * normalizer;
outL[i] += s * gainL * this.normalizer;
outR[i] += s * gainR * this.normalizer;
this.phases[n] = frac(this.phases[n] + dPhase);
// invert right and left gain
const tmp = gainL;