From 5bd076d13ece687789f4a5e40b754fde8eb8e848 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 8 Apr 2022 02:11:33 -0500 Subject: [PATCH] initial bring-up of the wave synth issue #16 --- src/engine/fileOps.cpp | 1 + src/engine/instrument.h | 2 +- src/engine/platform/gb.cpp | 51 +++++++++-------- src/engine/platform/gb.h | 2 + src/engine/platform/pce.cpp | 35 ++++++------ src/engine/platform/pce.h | 2 + src/engine/waveSynth.cpp | 107 ++++++++++++++++++++++++++---------- src/engine/waveSynth.h | 32 ++++++++++- src/gui/insEdit.cpp | 2 + 9 files changed, 162 insertions(+), 72 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index e14cd8b3b..7988992ba 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -579,6 +579,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } else { wave->data[j]=reader.readI(); } + wave->data[j]&=wave->max; } // #FDS4Bit if (ds.system[0]==DIV_SYSTEM_NES_FDS && ds.version<0x1a) { diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 9327c64c6..c56319119 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -516,7 +516,7 @@ struct DivInstrumentWaveSynth { oneShot(false), enabled(false), global(false), - speed(1), + speed(0), param1(0), param2(0), param3(0), diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index d1d580c84..263e8e2ba 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -91,20 +91,11 @@ void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len) } void DivPlatformGB::updateWave() { - DivWavetable* wt=parent->getWave(chan[2].wave); rWrite(0x1a,0); for (int i=0; i<16; i++) { - if (wt->max<1 || wt->len<1) { - rWrite(0x30+i,0); - } else { - int nibble1=15-((wt->data[(i*2)*wt->len/32]*15)/wt->max); - int nibble2=15-((wt->data[(1+i*2)*wt->len/32]*15)/wt->max); - if (nibble1<0) nibble1=0; - if (nibble1>15) nibble1=15; - if (nibble2<0) nibble2=0; - if (nibble2>15) nibble2=15; - rWrite(0x30+i,(nibble1<<4)|nibble2); - } + int nibble1=15-ws.output[i<<1]; + int nibble2=15-ws.output[1+(i<<1)]; + rWrite(0x30+i,(nibble1<<4)|nibble2); } } @@ -194,10 +185,16 @@ void DivPlatformGB::tick() { } } } - if (chan[i].std.hadWave) { - if (chan[i].wave!=chan[i].std.wave) { + if (i==2 && chan[i].std.hadWave) { + if (chan[i].wave!=chan[i].std.wave || ws.activeChanged()) { chan[i].wave=chan[i].std.wave; - if (i==2) { + ws.changeWave1(chan[i].wave); + if (!chan[i].keyOff) chan[i].keyOn=true; + } + } + if (i==2) { + if (chan[i].active) { + if (ws.tick()) { updateWave(); if (!chan[i].keyOff) chan[i].keyOn=true; } @@ -222,10 +219,6 @@ void DivPlatformGB::tick() { } if (chan[i].keyOn) { if (i==2) { // wave - if (chan[i].wave<0) { - chan[i].wave=0; - updateWave(); - } rWrite(16+i*5,0x80); rWrite(16+i*5+2,gbVolMap[chan[i].vol]); } else { @@ -261,7 +254,8 @@ void DivPlatformGB::muteChannel(int ch, bool mute) { int DivPlatformGB::dispatch(DivCommand c) { switch (c.cmd) { - case DIV_CMD_NOTE_ON: + case DIV_CMD_NOTE_ON: { + DivInstrument* ins=parent->getIns(chan[c.chan].ins); if (c.value!=DIV_NOTE_NULL) { if (c.chan==3) { // noise chan[c.chan].baseFreq=c.value; @@ -273,8 +267,17 @@ int DivPlatformGB::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + chan[c.chan].std.init(ins); + if (c.chan==2) { + if (chan[c.chan].wave<0) { + chan[c.chan].wave=0; + ws.changeWave1(chan[c.chan].wave); + } + ws.init(ins,32,15,chan[c.chan].insChanged); + } + chan[c.chan].insChanged=false; break; + } case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; chan[c.chan].keyOff=true; @@ -287,6 +290,7 @@ int DivPlatformGB::dispatch(DivCommand c) { case DIV_CMD_INSTRUMENT: if (chan[c.chan].ins!=c.value || c.value2==1) { chan[c.chan].ins=c.value; + chan[c.chan].insChanged=true; if (c.chan!=2) { DivInstrument* ins=parent->getIns(chan[c.chan].ins); chan[c.chan].vol=ins->gb.envVol; @@ -312,7 +316,7 @@ int DivPlatformGB::dispatch(DivCommand c) { case DIV_CMD_WAVE: if (c.chan!=2) break; chan[c.chan].wave=c.value; - updateWave(); + ws.changeWave1(chan[c.chan].wave); chan[c.chan].keyOn=true; break; case DIV_CMD_NOTE_PORTA: { @@ -415,6 +419,8 @@ void DivPlatformGB::reset() { for (int i=0; i<4; i++) { chan[i]=DivPlatformGB::Channel(); } + ws.setEngine(parent); + ws.init(NULL,32,15,false); if (dumpWrites) { addWrite(0xffffffff,0); } @@ -445,6 +451,7 @@ void DivPlatformGB::notifyInsChange(int ins) { void DivPlatformGB::notifyWaveChange(int wave) { if (chan[2].wave==wave) { + ws.changeWave1(wave); updateWave(); if (!chan[2].keyOff) chan[2].keyOn=true; } diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index 04e36ad3c..5a345e45d 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -22,6 +22,7 @@ #include "../dispatch.h" #include "../macroInt.h" +#include "../waveSynth.h" #include "sound/gb/gb.h" class DivPlatformGB: public DivDispatch { @@ -53,6 +54,7 @@ class DivPlatformGB: public DivDispatch { Channel chan[4]; bool isMuted[4]; unsigned char lastPan; + DivWaveSynth ws; GB_gameboy_t* gb; unsigned char regPool[128]; diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index bf7d0d8db..aa78aa625 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -131,18 +131,10 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) } void DivPlatformPCE::updateWave(int ch) { - DivWavetable* wt=parent->getWave(chan[ch].wave); chWrite(ch,0x04,0x5f); chWrite(ch,0x04,0x1f); for (int i=0; i<32; i++) { - if (wt->max<1 || wt->len<1) { - chWrite(ch,0x06,0); - } else { - int data=wt->data[i*wt->len/32]*31/wt->max; - if (data<0) data=0; - if (data>31) data=31; - chWrite(ch,0x06,data); - } + chWrite(ch,0x06,chan[ch].ws.output[i]); } if (chan[ch].active) { chWrite(ch,0x04,0x80|chan[ch].outVol); @@ -198,12 +190,17 @@ void DivPlatformPCE::tick() { } } if (chan[i].std.hadWave && !chan[i].pcm) { - if (chan[i].wave!=chan[i].std.wave) { + if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) { chan[i].wave=chan[i].std.wave; - updateWave(i); + chan[i].ws.changeWave1(chan[i].wave); if (!chan[i].keyOff) chan[i].keyOn=true; } } + if (chan[i].active) { + if (chan[i].ws.tick()) { + updateWave(i); + } + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true); @@ -224,10 +221,6 @@ void DivPlatformPCE::tick() { chWrite(i,0x02,chan[i].freq&0xff); chWrite(i,0x03,chan[i].freq>>8); if (chan[i].keyOn) { - if (chan[i].wave<0) { - chan[i].wave=0; - updateWave(i); - } //rWrite(16+i*5,0x80); //chWrite(i,0x04,0x80|chan[i].vol); } @@ -310,6 +303,12 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].keyOn=true; chWrite(c.chan,0x04,0x80|chan[c.chan].vol); chan[c.chan].std.init(ins); + if (chan[c.chan].wave<0) { + chan[c.chan].wave=0; + chan[c.chan].ws.changeWave1(chan[c.chan].wave); + } + chan[c.chan].ws.init(ins,32,31,chan[c.chan].insChanged); + chan[c.chan].insChanged=false; break; } case DIV_CMD_NOTE_OFF: @@ -327,6 +326,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { case DIV_CMD_INSTRUMENT: if (chan[c.chan].ins!=c.value || c.value2==1) { chan[c.chan].ins=c.value; + chan[c.chan].insChanged=true; } break; case DIV_CMD_VOLUME: @@ -350,7 +350,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; case DIV_CMD_WAVE: chan[c.chan].wave=c.value; - updateWave(c.chan); + chan[c.chan].ws.changeWave1(chan[c.chan].wave); chan[c.chan].keyOn=true; break; case DIV_CMD_PCE_LFO_MODE: @@ -462,6 +462,8 @@ void DivPlatformPCE::reset() { memset(regPool,0,128); for (int i=0; i<6; i++) { chan[i]=DivPlatformPCE::Channel(); + chan[i].ws.setEngine(parent); + chan[i].ws.init(NULL,32,31,false); } if (dumpWrites) { addWrite(0xffffffff,0); @@ -499,6 +501,7 @@ bool DivPlatformPCE::keyOffAffectsArp(int ch) { void DivPlatformPCE::notifyWaveChange(int wave) { for (int i=0; i<6; i++) { if (chan[i].wave==wave) { + chan[i].ws.changeWave1(wave); updateWave(i); } } diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 2a5bd4fba..2e8614ba8 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -23,6 +23,7 @@ #include "../dispatch.h" #include #include "../macroInt.h" +#include "../waveSynth.h" #include "sound/pce_psg.h" class DivPlatformPCE: public DivDispatch { @@ -35,6 +36,7 @@ class DivPlatformPCE: public DivDispatch { bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, furnaceDac; signed char vol, outVol, wave; DivMacroInt std; + DivWaveSynth ws; Channel(): freq(0), baseFreq(0), diff --git a/src/engine/waveSynth.cpp b/src/engine/waveSynth.cpp index b82539aaf..d658be178 100644 --- a/src/engine/waveSynth.cpp +++ b/src/engine/waveSynth.cpp @@ -1,52 +1,99 @@ #include "waveSynth.h" #include "engine.h" +#include "instrument.h" + +bool DivWaveSynth::activeChanged() { + if (activeChangedB) { + activeChangedB=false; + return true; + } + return false; +} bool DivWaveSynth::tick() { bool updated=first; first=false; + if (!state.enabled) return updated; + 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; + } + divCounter=state.rateDivider; + } return updated; } +void DivWaveSynth::changeWave1(int num) { + DivWavetable* w1=e->getWave(num); + for (int i=0; imax<1 || w1->len<1) { + wave1[i]=0; + output[i]=0; + } else { + int data=w1->data[i*w1->len/width]*height/w1->max; + if (data<0) data=0; + if (data>height) data=height; + wave1[i]=data; + output[i]=data; + } + } + first=true; +} + +void DivWaveSynth::changeWave2(int num) { + DivWavetable* w2=e->getWave(num); + for (int i=0; imax<1 || w2->len<1) { + wave2[i]=0; + } else { + int data=w2->data[i*w2->len/width]*height/w2->max; + if (data<0) data=0; + if (data>height) data=height; + wave2[i]=data; + } + } + first=true; +} + void DivWaveSynth::setEngine(DivEngine* engine) { e=engine; } void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) { - if (e==NULL) return; - if (which==NULL) { - state=DivInstrumentWaveSynth(); - } - state=which->ws; width=w; height=h; - pos=0; - stage=0; - divCounter=0; - first=true; - - DivWavetable* w1=e->getWave(state.wave1); - DivWavetable* w2=e->getWave(state.wave2); - for (int i=0; imax<1 || w1->len<1) { - wave1[i]=0; - } else { - int data=w1->data[i*w1->len/width]*height/w1->max; - if (data<0) data=0; - if (data>31) data=31; - wave1[i]=data; - } + 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; - for (int i=0; imax<1 || w2->len<1) { - wave2[i]=0; - } else { - int data=w2->data[i*w2->len/width]*height/w2->max; - if (data<0) data=0; - if (data>31) data=31; - wave2[i]=data; - } + changeWave1(state.wave1); + changeWave2(state.wave2); } } \ No newline at end of file diff --git a/src/engine/waveSynth.h b/src/engine/waveSynth.h index 92a5c9a26..70fb27389 100644 --- a/src/engine/waveSynth.h +++ b/src/engine/waveSynth.h @@ -29,16 +29,41 @@ class DivWaveSynth { DivEngine* e; DivInstrumentWaveSynth state; int pos, stage, divCounter, width, height; - bool first; + bool first, activeChangedB; unsigned char wave1[256]; unsigned char wave2[256]; - int output[256]; public: + /** + * the output. + */ + int output[256]; + /** + * check whether the "active" status has changed. + * @return truth. + */ + bool activeChanged(); /** * tick this DivWaveSynth. * @return whether the wave has changed. */ bool tick(); + /** + * change the first wave. + * @param num wavetable number. + */ + void changeWave1(int num); + /** + * change the second wave. + * @param num wavetable number. + */ + void changeWave2(int num); + /** + * initialize this DivWaveSynth. + * @param which the instrument. + * @param width the system's wave width. + * @param height the system's wave height. + * @param insChanged whether the instrument has changed. + */ void init(DivInstrument* which, int width, int height, bool insChanged=false); void setEngine(DivEngine* engine); DivWaveSynth(): @@ -48,7 +73,8 @@ class DivWaveSynth { divCounter(0), width(32), height(31), - first(false) { + first(false), + activeChangedB(false) { memset(wave1,0,sizeof(int)*256); memset(wave2,0,sizeof(int)*256); memset(output,0,sizeof(int)*256); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 71426dfe9..14ca65b40 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2418,6 +2418,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::InputScalar("Amount",ImGuiDataType_U8,&ins->ws.param1,&_ONE,&_SEVEN); + ImGui::Checkbox("Global",&ins->ws.global); + ImGui::EndTabItem(); } }