WaveSynth: add change detection

don't update wave if it is intact
issue #2298
This commit is contained in:
tildearrow 2025-02-21 17:25:05 -05:00
parent 8c67ea8eb9
commit cfb962236a

View file

@ -47,6 +47,9 @@ bool DivWaveSynth::activeChanged() {
return false; return false;
} }
#define WS_BEGIN int _oldOut=output[pos];
#define WS_END if (output[pos]!=_oldOut) updated=true;
bool DivWaveSynth::tick(bool skipSubDiv) { bool DivWaveSynth::tick(bool skipSubDiv) {
bool updated=first; bool updated=first;
first=false; first=false;
@ -63,84 +66,103 @@ bool DivWaveSynth::tick(bool skipSubDiv) {
switch (state.effect) { switch (state.effect) {
case DIV_WS_INVERT: case DIV_WS_INVERT:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]=height-output[pos]; output[pos]=height-output[pos];
WS_END;
if (++pos>=width) pos=0; if (++pos>=width) pos=0;
} }
updated=true;
break; break;
case DIV_WS_ADD: case DIV_WS_ADD:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]+=MIN(height,state.param1); output[pos]+=MIN(height,state.param1);
if (output[pos]>=height) output[pos]-=height; if (output[pos]>=height) output[pos]-=height;
WS_END;
if (++pos>=width) pos=0; if (++pos>=width) pos=0;
} }
updated=true;
break; break;
case DIV_WS_SUBTRACT: case DIV_WS_SUBTRACT:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]-=MIN(height,state.param1); output[pos]-=MIN(height,state.param1);
if (output[pos]<0) output[pos]+=height; if (output[pos]<0) output[pos]+=height;
WS_END;
if (++pos>=width) pos=0; if (++pos>=width) pos=0;
} }
updated=true;
break; break;
case DIV_WS_AVERAGE: case DIV_WS_AVERAGE:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
int pos1=(pos+1>=width)?0:(pos+1); int pos1=(pos+1>=width)?0:(pos+1);
WS_BEGIN;
output[pos]=(128+output[pos]*(256-state.param1)+output[pos1]*state.param1)>>8; output[pos]=(128+output[pos]*(256-state.param1)+output[pos1]*state.param1)>>8;
if (output[pos]<0) output[pos]=0; if (output[pos]<0) output[pos]=0;
if (output[pos]>height) output[pos]=height; if (output[pos]>height) output[pos]=height;
WS_END;
if (++pos>=width) pos=0; if (++pos>=width) pos=0;
} }
updated=true;
break; break;
case DIV_WS_PHASE: case DIV_WS_PHASE:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]=wave1[(pos+stage)%width]; output[pos]=wave1[(pos+stage)%width];
WS_END;
if (++pos>=width) { if (++pos>=width) {
pos=0; pos=0;
if (++stage>=width) stage=0; if (++stage>=width) stage=0;
} }
} }
updated=true;
break; break;
case DIV_WS_CHORUS: case DIV_WS_CHORUS:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]=(wave1[pos]+wave1[(pos+stage)%width])>>1; output[pos]=(wave1[pos]+wave1[(pos+stage)%width])>>1;
WS_END;
if (++pos>=width) { if (++pos>=width) {
pos=0; pos=0;
stage+=state.param1; stage+=state.param1;
while (stage>=width) stage-=width; while (stage>=width) stage-=width;
} }
} }
updated=true;
break; break;
case DIV_WS_WIPE: case DIV_WS_WIPE:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]=(stage&1)?wave1[pos]:wave2[pos]; output[pos]=(stage&1)?wave1[pos]:wave2[pos];
if (output[pos]<0) output[pos]=0; if (output[pos]<0) output[pos]=0;
if (output[pos]>height) output[pos]=height; if (output[pos]>height) output[pos]=height;
WS_END;
if (++pos>=width) { if (++pos>=width) {
pos=0; pos=0;
stage=!stage; stage=!stage;
} }
} }
updated=true;
break; break;
case DIV_WS_FADE: case DIV_WS_FADE:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]=wave1[pos]+(((wave2[pos]-wave1[pos])*stage)>>9); output[pos]=wave1[pos]+(((wave2[pos]-wave1[pos])*stage)>>9);
WS_END;
if (++pos>=width) { if (++pos>=width) {
pos=0; pos=0;
stage+=1+state.param1; stage+=1+state.param1;
if (stage>512) stage=512; if (stage>512) stage=512;
} }
} }
updated=true;
break; break;
case DIV_WS_PING_PONG: case DIV_WS_PING_PONG:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]=wave1[pos]+(((wave2[pos]-wave1[pos])*stage)>>8); output[pos]=wave1[pos]+(((wave2[pos]-wave1[pos])*stage)>>8);
WS_END;
if (++pos>=width) { if (++pos>=width) {
pos=0; pos=0;
if (stageDir) { if (stageDir) {
@ -158,61 +180,70 @@ bool DivWaveSynth::tick(bool skipSubDiv) {
} }
} }
} }
updated=true;
break; break;
case DIV_WS_OVERLAY: case DIV_WS_OVERLAY:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]+=wave2[pos]; output[pos]+=wave2[pos];
if (output[pos]>=height) output[pos]-=height; if (output[pos]>=height) output[pos]-=height;
WS_END;
if (++pos>=width) pos=0; if (++pos>=width) pos=0;
} }
updated=true;
break; break;
case DIV_WS_NEGATIVE_OVERLAY: case DIV_WS_NEGATIVE_OVERLAY:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]-=wave2[pos]; output[pos]-=wave2[pos];
if (output[pos]<0) output[pos]+=height; if (output[pos]<0) output[pos]+=height;
WS_END;
if (++pos>=width) pos=0; if (++pos>=width) pos=0;
} }
updated=true;
break; break;
case DIV_WS_SLIDE: case DIV_WS_SLIDE:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
int newPos=(pos+stage)%(width*2); int newPos=(pos+stage)%(width*2);
WS_BEGIN;
if (newPos>=width) { if (newPos>=width) {
output[pos]=wave2[newPos-width]; output[pos]=wave2[newPos-width];
} else { } else {
output[pos]=wave1[newPos]; output[pos]=wave1[newPos];
} }
WS_END;
if (++pos>=width) { if (++pos>=width) {
pos=0; pos=0;
if (++stage>=width*2) stage=0; if (++stage>=width*2) stage=0;
} }
} }
updated=true;
break; break;
case DIV_WS_MIX: case DIV_WS_MIX:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
WS_BEGIN;
output[pos]=(wave1[pos]+wave2[(pos+stage)%width])>>1; output[pos]=(wave1[pos]+wave2[(pos+stage)%width])>>1;
WS_END;
if (++pos>=width) { if (++pos>=width) {
pos=0; pos=0;
stage+=state.param1; stage+=state.param1;
while (stage>=width) stage-=width; while (stage>=width) stage-=width;
} }
} }
updated=true;
break; break;
case DIV_WS_PHASE_MOD: case DIV_WS_PHASE_MOD:
for (int i=0; i<=state.speed; i++) { for (int i=0; i<=state.speed; i++) {
int mod=(wave2[pos]*(state.param2-stage)*width)/(64*(height+1)); int mod=(wave2[pos]*(state.param2-stage)*width)/(64*(height+1));
WS_BEGIN;
output[pos]=wave1[(pos+mod)%width]; output[pos]=wave1[(pos+mod)%width];
WS_END;
if (++pos>=width) { if (++pos>=width) {
pos=0; pos=0;
stage+=state.param1; stage+=state.param1;
if (stage>state.param2) stage=state.param2; if (stage>state.param2) stage=state.param2;
} }
} }
updated=true;
break; break;
} }
divCounter=state.rateDivider; divCounter=state.rateDivider;