2022-04-12 05:18:29 +00:00
|
|
|
/**
|
|
|
|
* Furnace Tracker - multi-system chiptune tracker
|
|
|
|
* Copyright (C) 2021-2022 tildearrow and contributors
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
2022-04-07 20:46:48 +00:00
|
|
|
#include "waveSynth.h"
|
2022-04-07 23:27:17 +00:00
|
|
|
#include "engine.h"
|
2022-04-08 07:11:33 +00:00
|
|
|
#include "instrument.h"
|
|
|
|
|
|
|
|
bool DivWaveSynth::activeChanged() {
|
|
|
|
if (activeChangedB) {
|
|
|
|
activeChangedB=false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2022-04-07 20:46:48 +00:00
|
|
|
|
|
|
|
bool DivWaveSynth::tick() {
|
2022-04-07 23:27:17 +00:00
|
|
|
bool updated=first;
|
|
|
|
first=false;
|
2022-04-08 07:11:33 +00:00
|
|
|
if (!state.enabled) return updated;
|
2022-04-12 05:17:34 +00:00
|
|
|
if (width<1) return false;
|
2022-04-07 23:27:17 +00:00
|
|
|
|
2022-04-08 07:11:33 +00:00
|
|
|
if (--divCounter<=0) {
|
|
|
|
// run effect
|
|
|
|
switch (state.effect) {
|
|
|
|
case DIV_WS_INVERT:
|
|
|
|
for (int i=0; i<=state.speed; i++) {
|
|
|
|
output[pos]=height-output[pos];
|
|
|
|
if (++pos>=width) pos=0;
|
|
|
|
}
|
|
|
|
updated=true;
|
|
|
|
break;
|
2022-04-08 21:03:54 +00:00
|
|
|
case DIV_WS_ADD:
|
|
|
|
for (int i=0; i<=state.speed; i++) {
|
|
|
|
output[pos]+=MIN(height,state.param1);
|
|
|
|
if (output[pos]>=height) output[pos]-=height;
|
|
|
|
if (++pos>=width) pos=0;
|
|
|
|
}
|
|
|
|
updated=true;
|
|
|
|
break;
|
|
|
|
case DIV_WS_SUBTRACT:
|
|
|
|
for (int i=0; i<=state.speed; i++) {
|
|
|
|
output[pos]+=MIN(height,state.param1);
|
|
|
|
if (output[pos]<0) output[pos]+=height;
|
|
|
|
if (++pos>=width) pos=0;
|
|
|
|
}
|
|
|
|
updated=true;
|
|
|
|
break;
|
|
|
|
case DIV_WS_AVERAGE:
|
|
|
|
for (int i=0; i<=state.speed; i++) {
|
|
|
|
int pos1=(pos+1>=width)?0:(pos+1);
|
|
|
|
output[pos]=(output[pos]*state.param1+output[pos1]*(256-state.param1))>>8;
|
|
|
|
if (output[pos]<0) output[pos]=0;
|
|
|
|
if (output[pos]>height) output[pos]=height;
|
|
|
|
if (++pos>=width) pos=0;
|
|
|
|
}
|
|
|
|
updated=true;
|
|
|
|
break;
|
|
|
|
case DIV_WS_PHASE:
|
|
|
|
for (int i=0; i<=state.speed; i++) {
|
|
|
|
output[pos]=wave1[(pos+stage)%width];
|
|
|
|
if (++pos>=width) {
|
|
|
|
pos=0;
|
|
|
|
if (++stage>=width) stage=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updated=true;
|
|
|
|
break;
|
|
|
|
case DIV_WS_WIPE:
|
|
|
|
break;
|
|
|
|
case DIV_WS_FADE:
|
|
|
|
break;
|
|
|
|
case DIV_WS_PING_PONG:
|
|
|
|
break;
|
|
|
|
case DIV_WS_OVERLAY:
|
|
|
|
break;
|
|
|
|
case DIV_WS_NEGATIVE_OVERLAY:
|
|
|
|
break;
|
|
|
|
case DIV_WS_PHASE_DUAL:
|
|
|
|
break;
|
2022-04-08 07:11:33 +00:00
|
|
|
}
|
|
|
|
divCounter=state.rateDivider;
|
|
|
|
}
|
2022-04-07 23:27:17 +00:00
|
|
|
|
|
|
|
return updated;
|
|
|
|
}
|
|
|
|
|
2022-04-12 05:17:34 +00:00
|
|
|
void DivWaveSynth::setWidth(int val) {
|
|
|
|
width=val;
|
|
|
|
if (width<0) width=0;
|
|
|
|
if (width>256) width=256;
|
|
|
|
}
|
|
|
|
|
2022-04-08 07:11:33 +00:00
|
|
|
void DivWaveSynth::changeWave1(int num) {
|
|
|
|
DivWavetable* w1=e->getWave(num);
|
2022-04-12 05:17:34 +00:00
|
|
|
if (width<1) return;
|
2022-04-07 23:27:17 +00:00
|
|
|
for (int i=0; i<width; i++) {
|
|
|
|
if (w1->max<1 || w1->len<1) {
|
|
|
|
wave1[i]=0;
|
2022-04-08 07:11:33 +00:00
|
|
|
output[i]=0;
|
2022-04-07 23:27:17 +00:00
|
|
|
} else {
|
|
|
|
int data=w1->data[i*w1->len/width]*height/w1->max;
|
|
|
|
if (data<0) data=0;
|
2022-04-08 07:11:33 +00:00
|
|
|
if (data>height) data=height;
|
2022-04-07 23:27:17 +00:00
|
|
|
wave1[i]=data;
|
2022-04-08 07:11:33 +00:00
|
|
|
output[i]=data;
|
2022-04-07 23:27:17 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-08 07:11:33 +00:00
|
|
|
first=true;
|
|
|
|
}
|
2022-04-07 23:27:17 +00:00
|
|
|
|
2022-04-08 07:11:33 +00:00
|
|
|
void DivWaveSynth::changeWave2(int num) {
|
|
|
|
DivWavetable* w2=e->getWave(num);
|
2022-04-12 05:17:34 +00:00
|
|
|
if (width<1) return;
|
2022-04-07 23:27:17 +00:00
|
|
|
for (int i=0; i<width; i++) {
|
|
|
|
if (w2->max<1 || w2->len<1) {
|
|
|
|
wave2[i]=0;
|
|
|
|
} else {
|
|
|
|
int data=w2->data[i*w2->len/width]*height/w2->max;
|
|
|
|
if (data<0) data=0;
|
2022-04-08 07:11:33 +00:00
|
|
|
if (data>height) data=height;
|
2022-04-07 23:27:17 +00:00
|
|
|
wave2[i]=data;
|
|
|
|
}
|
|
|
|
}
|
2022-04-08 07:11:33 +00:00
|
|
|
first=true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DivWaveSynth::setEngine(DivEngine* engine) {
|
|
|
|
e=engine;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) {
|
|
|
|
width=w;
|
|
|
|
height=h;
|
|
|
|
if (width<0) width=0;
|
|
|
|
if (width>256) width=256;
|
|
|
|
if (e==NULL) return;
|
|
|
|
if (which==NULL) {
|
|
|
|
if (state.enabled) activeChangedB=true;
|
|
|
|
state=DivInstrumentWaveSynth();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!which->ws.enabled) {
|
|
|
|
if (state.enabled) activeChangedB=true;
|
|
|
|
state=DivInstrumentWaveSynth();
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (!state.enabled) activeChangedB=true;
|
|
|
|
}
|
|
|
|
state=which->ws;
|
|
|
|
if (insChanged || !state.global) {
|
|
|
|
pos=0;
|
|
|
|
stage=0;
|
|
|
|
divCounter=1+state.rateDivider;
|
|
|
|
first=true;
|
|
|
|
|
|
|
|
changeWave1(state.wave1);
|
|
|
|
changeWave2(state.wave2);
|
|
|
|
}
|
2022-04-08 21:03:54 +00:00
|
|
|
}
|