diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 7c9188d49..b7234a4ba 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -171,29 +171,43 @@ void DivPlatformN163::acquire(short* bufL, short* bufR, size_t start, size_t len } } -void DivPlatformN163::updateWave(int wave, int pos, int len) { +void DivPlatformN163::updateWave(int ch, int wave, int pos, int len) { len&=0xfc; // 4 nibble boundary - DivWavetable* wt=parent->getWave(wave); - for (int i=0; i=((0x78-(chanMax<<3))<<1)) { // avoid conflict with channel register area - break; - } - unsigned char mask=(addr&1)?0xf0:0x0f; - if (wt->max<1 || wt->len<1) { - rWriteMask(addr>>1,0,mask); - } else { - int data=wt->data[i*wt->len/len]*15/wt->max; - if (data<0) data=0; - if (data>15) data=15; + if (wave<0) { + // load from wave synth + for (int i=0; i=((0x78-(chanMax<<3))<<1)) { // avoid conflict with channel register area + break; + } + unsigned char mask=(addr&1)?0xf0:0x0f; + int data=chan[ch].ws.output[i]; rWriteMask(addr>>1,(addr&1)?(data<<4):(data&0xf),mask); } + } else { + // load from custom + DivWavetable* wt=parent->getWave(wave); + for (int i=0; i=((0x78-(chanMax<<3))<<1)) { // avoid conflict with channel register area + break; + } + unsigned char mask=(addr&1)?0xf0:0x0f; + if (wt->max<1 || wt->len<1) { + rWriteMask(addr>>1,0,mask); + } else { + int data=wt->data[i*wt->len/len]*15/wt->max; + if (data<0) data=0; + if (data>15) data=15; + rWriteMask(addr>>1,(addr&1)?(data<<4):(data&0xf),mask); + } + } } } void DivPlatformN163::updateWaveCh(int ch) { if (ch<=chanMax) { - updateWave(chan[ch].wave,chan[ch].wavePos,chan[ch].waveLen); + updateWave(ch,-1,chan[ch].wavePos,chan[ch].waveLen); if (chan[ch].active && !isMuted[ch]) { chan[ch].volumeChanged=true; } @@ -241,6 +255,7 @@ void DivPlatformN163::tick() { if (chan[i].std.wave.had) { if (chan[i].wave!=chan[i].std.wave.val) { chan[i].wave=chan[i].std.wave.val; + chan[i].ws.changeWave1(chan[i].wave); if (chan[i].waveMode&0x2) { chan[i].waveUpdated=true; } @@ -249,6 +264,7 @@ void DivPlatformN163::tick() { if (chan[i].std.ex1.had) { if (chan[i].waveLen!=(chan[i].std.ex1.val&0xfc)) { chan[i].waveLen=chan[i].std.ex1.val&0xfc; + chan[i].ws.setWidth(chan[i].waveLen); if (chan[i].waveMode&0x2) { chan[i].waveUpdated=true; } @@ -275,7 +291,7 @@ void DivPlatformN163::tick() { if (chan[i].loadWave!=chan[i].std.ex3.val) { chan[i].loadWave=chan[i].std.ex3.val; if (chan[i].loadMode&0x2) { - updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc); + updateWave(i,chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc); } } } @@ -296,7 +312,7 @@ void DivPlatformN163::tick() { if ((chan[i].loadMode&0x1)!=(chan[i].std.fms.val&0x1)) { // load now chan[i].loadMode=(chan[i].loadMode&~0x1)|(chan[i].std.fms.val&0x1); if (chan[i].loadMode&0x1) { // rising edge - updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc); + updateWave(i,chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc); } } } @@ -315,6 +331,11 @@ void DivPlatformN163::tick() { } chan[i].waveChanged=false; } + if (chan[i].active) { + if (chan[i].ws.tick()) { + chan[i].waveUpdated=true; + } + } if (chan[i].waveUpdated) { updateWaveCh(i); if (chan[i].active) { @@ -353,11 +374,12 @@ int DivPlatformN163::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan[c.chan].ins); if (chan[c.chan].insChanged) { chan[c.chan].wave=ins->n163.wave; + chan[c.chan].ws.changeWave1(chan[c.chan].wave); chan[c.chan].wavePos=ins->n163.wavePos; chan[c.chan].waveLen=ins->n163.waveLen; chan[c.chan].waveMode=ins->n163.waveMode; chan[c.chan].waveChanged=true; - if (chan[c.chan].waveMode&0x3) { + if (chan[c.chan].waveMode&0x3 || ins->ws.enabled) { chan[c.chan].waveUpdated=true; } chan[c.chan].insChanged=false; @@ -374,6 +396,7 @@ int DivPlatformN163::dispatch(DivCommand c) { chan[c.chan].volumeChanged=true; } chan[c.chan].std.init(ins); + chan[c.chan].ws.init(ins,chan[c.chan].waveLen,15,chan[c.chan].insChanged); break; } case DIV_CMD_NOTE_OFF: @@ -472,7 +495,7 @@ int DivPlatformN163::dispatch(DivCommand c) { case DIV_CMD_N163_WAVE_LOAD: chan[c.chan].loadWave=c.value; if (chan[c.chan].loadMode&0x2) { // load when every waveform changes - updateWave(chan[c.chan].loadWave,chan[c.chan].loadPos,chan[c.chan].loadLen); + updateWave(c.chan,chan[c.chan].loadWave,chan[c.chan].loadPos,chan[c.chan].loadLen); } break; case DIV_CMD_N163_WAVE_LOADPOS: @@ -484,13 +507,13 @@ int DivPlatformN163::dispatch(DivCommand c) { case DIV_CMD_N163_WAVE_LOADMODE: chan[c.chan].loadMode=c.value&0x3; if (chan[c.chan].loadMode&0x1) { // load now - updateWave(chan[c.chan].loadWave,chan[c.chan].loadPos,chan[c.chan].loadLen); + updateWave(c.chan,chan[c.chan].loadWave,chan[c.chan].loadPos,chan[c.chan].loadLen); } break; case DIV_CMD_N163_GLOBAL_WAVE_LOAD: loadWave=c.value; if (loadMode&0x2) { // load when every waveform changes - updateWave(loadWave,loadPos,loadLen); + updateWave(c.chan,loadWave,loadPos,loadLen); } break; case DIV_CMD_N163_GLOBAL_WAVE_LOADPOS: @@ -502,7 +525,7 @@ int DivPlatformN163::dispatch(DivCommand c) { case DIV_CMD_N163_GLOBAL_WAVE_LOADMODE: loadMode=c.value&0x3; if (loadMode&0x3) { // load now - updateWave(loadWave,loadPos,loadLen); + updateWave(c.chan,loadWave,loadPos,loadLen); } break; case DIV_CMD_N163_CHANNEL_LIMIT: @@ -562,6 +585,7 @@ void DivPlatformN163::notifyWaveChange(int wave) { for (int i=0; i<8; i++) { if (chan[i].wave==wave) { if (chan[i].waveMode&0x2) { + chan[i].ws.changeWave1(wave); chan[i].waveUpdated=true; } } @@ -601,6 +625,8 @@ void DivPlatformN163::reset() { while (!writes.empty()) writes.pop(); for (int i=0; i<8; i++) { chan[i]=DivPlatformN163::Channel(); + chan[i].ws.setEngine(parent); + chan[i].ws.init(NULL,32,15,false); } n163.reset(); diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index 70f842adf..2f68d6c9d 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -23,6 +23,7 @@ #include "../dispatch.h" #include #include "../macroInt.h" +#include "../waveSynth.h" #include "sound/n163/n163.hpp" class DivPlatformN163: public DivDispatch { @@ -35,6 +36,7 @@ class DivPlatformN163: public DivDispatch { bool active, insChanged, freqChanged, volumeChanged, waveChanged, waveUpdated, keyOn, keyOff, inPorta; signed char vol, outVol, resVol; DivMacroInt std; + DivWaveSynth ws; Channel(): freq(0), baseFreq(0), @@ -79,7 +81,7 @@ class DivPlatformN163: public DivDispatch { n163_core n163; unsigned char regPool[128]; - void updateWave(int wave, int pos, int len); + void updateWave(int ch, int wave, int pos, int len); void updateWaveCh(int ch); friend void putDispatchChan(void*,int,int); diff --git a/src/engine/waveSynth.cpp b/src/engine/waveSynth.cpp index e38ee228e..ce93105d4 100644 --- a/src/engine/waveSynth.cpp +++ b/src/engine/waveSynth.cpp @@ -18,6 +18,7 @@ bool DivWaveSynth::tick() { bool updated=first; first=false; if (!state.enabled) return updated; + if (width<1) return false; if (--divCounter<=0) { // run effect @@ -84,8 +85,15 @@ bool DivWaveSynth::tick() { return updated; } +void DivWaveSynth::setWidth(int val) { + width=val; + if (width<0) width=0; + if (width>256) width=256; +} + void DivWaveSynth::changeWave1(int num) { DivWavetable* w1=e->getWave(num); + if (width<1) return; for (int i=0; imax<1 || w1->len<1) { wave1[i]=0; @@ -103,6 +111,7 @@ void DivWaveSynth::changeWave1(int num) { void DivWaveSynth::changeWave2(int num) { DivWavetable* w2=e->getWave(num); + if (width<1) return; for (int i=0; imax<1 || w2->len<1) { wave2[i]=0; diff --git a/src/engine/waveSynth.h b/src/engine/waveSynth.h index ccd8b23de..ecd6f8a86 100644 --- a/src/engine/waveSynth.h +++ b/src/engine/waveSynth.h @@ -47,6 +47,11 @@ class DivWaveSynth { * @return whether the wave has changed. */ bool tick(); + /** + * set the wave width. + * @param value the width. + */ + void setWidth(int val); /** * change the first wave. * @param num wavetable number. diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 1b292638c..bc5345aa5 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -385,8 +385,8 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_OSC_BORDER,"",ImVec4(0.4f,0.6f,0.95f,1.0f)), D(GUI_COLOR_OSC_WAVE,"",ImVec4(0.95f,0.95f,1.0f,1.0f)), D(GUI_COLOR_OSC_WAVE_PEAK,"",ImVec4(0.95f,0.95f,1.0f,1.0f)), - D(GUI_COLOR_OSC_REF,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), - D(GUI_COLOR_OSC_GUIDE,"",ImVec4(0.3,0.3f,0.3f,1.0f)), + D(GUI_COLOR_OSC_REF,"",ImVec4(0.3,0.65f,1.0f,0.15f)), + D(GUI_COLOR_OSC_GUIDE,"",ImVec4(0.3,0.65f,1.0f,0.13f)), D(GUI_COLOR_VOLMETER_LOW,"",ImVec4(0.2f,0.6f,0.2f,1.0f)), D(GUI_COLOR_VOLMETER_HIGH,"",ImVec4(1.0f,0.9f,0.2f,1.0f)), diff --git a/src/gui/osc.cpp b/src/gui/osc.cpp index e43dee1e0..c7089a991 100644 --- a/src/gui/osc.cpp +++ b/src/gui/osc.cpp @@ -69,9 +69,6 @@ void FurnaceGUI::readOsc() { e->oscReadPos=readPos; } -// TODO: -// - draw reference level -// - draw guidelines void FurnaceGUI::drawOsc() { if (nextWindow==GUI_WINDOW_OSCILLOSCOPE) { oscOpen=true; @@ -115,6 +112,7 @@ void FurnaceGUI::drawOsc() { ImU32 color=ImGui::GetColorU32(isClipping?uiColors[GUI_COLOR_OSC_WAVE_PEAK]:uiColors[GUI_COLOR_OSC_WAVE]); ImU32 borderColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_BORDER]); ImU32 refColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_REF]); + ImU32 guideColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_GUIDE]); ImGui::ItemSize(size,style.FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("wsDisplay"))) { // https://github.com/ocornut/imgui/issues/3710 @@ -162,11 +160,60 @@ void FurnaceGUI::drawOsc() { dl->AddLine( ImLerp(rect.Min,rect.Max,ImVec2(0.0f,0.5f)), - ImLerp(rect.Min,rect.Max,ImVec2(0.0f,0.5f)), + ImLerp(rect.Min,rect.Max,ImVec2(1.0f,0.5f)), refColor, dpiScale ); + dl->AddLine( + ImLerp(rect.Min,rect.Max,ImVec2(0.48f,0.125f)), + ImLerp(rect.Min,rect.Max,ImVec2(0.52f,0.125f)), + guideColor, + dpiScale + ); + + dl->AddLine( + ImLerp(rect.Min,rect.Max,ImVec2(0.47f,0.25f)), + ImLerp(rect.Min,rect.Max,ImVec2(0.53f,0.25f)), + guideColor, + dpiScale + ); + + dl->AddLine( + ImLerp(rect.Min,rect.Max,ImVec2(0.45f,0.375f)), + ImLerp(rect.Min,rect.Max,ImVec2(0.55f,0.375f)), + guideColor, + dpiScale + ); + + dl->AddLine( + ImLerp(rect.Min,rect.Max,ImVec2(0.45f,0.625f)), + ImLerp(rect.Min,rect.Max,ImVec2(0.55f,0.625f)), + guideColor, + dpiScale + ); + + dl->AddLine( + ImLerp(rect.Min,rect.Max,ImVec2(0.47f,0.75f)), + ImLerp(rect.Min,rect.Max,ImVec2(0.53f,0.75f)), + guideColor, + dpiScale + ); + + dl->AddLine( + ImLerp(rect.Min,rect.Max,ImVec2(0.48f,0.875f)), + ImLerp(rect.Min,rect.Max,ImVec2(0.52f,0.875f)), + guideColor, + dpiScale + ); + + dl->AddLine( + ImLerp(rect.Min,rect.Max,ImVec2(0.5f,0.08f)), + ImLerp(rect.Min,rect.Max,ImVec2(0.5f,0.92f)), + guideColor, + dpiScale + ); + for (size_t i=0; i<512; i++) { float x=(float)i/512.0f; float y=oscValues[i]*oscZoom;