diff --git a/.gitignore b/.gitignore index df492a378..d243d7bc4 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ test/songs/ test/delta/ test/result/ .vs/ +CMakeSettings.json diff --git a/TODO.md b/TODO.md index c5e26bd9b..7df17b348 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,5 @@ # to-do for ES5506 -- make sound produces actually -- filter, envelope macro, commands - envelope shape - reversed playing flag in instrument/macro/commands - transwave synthesizer (like ensoniq synths - 12 bit command and macro) @@ -10,9 +8,6 @@ - panning macro - QSound? -- pitch macro - - relative mode - - test - piano/input pad - note input via piano - input pad diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index a671e1186..3a66784d4 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -466,4 +466,8 @@ class DivDispatch { #define COLOR_NTSC (315000000.0/88.0) #define COLOR_PAL (283.75*15625.0+25.0) +#define CLAMP_VAR(x,xMin,xMax) \ + if ((x)<(xMin)) (x)=(xMin); \ + if ((x)>(xMax)) (x)=(xMax); + #endif diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 17183840c..5bed93232 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -675,10 +675,79 @@ void DivEngine::createNew(const int* description) { BUSY_END; } -void DivEngine::changeSystem(int index, DivSystem which) { +void DivEngine::swapChannels(int src, int dest) { + logV("swapping channel %d with %d",src,dest); + if (src==dest) { + logV("not swapping channels because it's the same channel!",src,dest); + return; + } + + for (int i=0; i<256; i++) { + song.orders.ord[dest][i]^=song.orders.ord[src][i]; + song.orders.ord[src][i]^=song.orders.ord[dest][i]; + song.orders.ord[dest][i]^=song.orders.ord[src][i]; + + DivPattern* prev=song.pat[src].data[i]; + song.pat[src].data[i]=song.pat[dest].data[i]; + song.pat[dest].data[i]=prev; + } + + song.pat[src].effectCols^=song.pat[dest].effectCols; + song.pat[dest].effectCols^=song.pat[src].effectCols; + song.pat[src].effectCols^=song.pat[dest].effectCols; +} + +void DivEngine::stompChannel(int ch) { + logV("stomping channel %d",ch); + for (int i=0; i<256; i++) { + song.orders.ord[ch][i]=0; + } + song.pat[ch].wipePatterns(); + song.pat[ch].effectCols=1; +} + +void DivEngine::swapChannelsP(int src, int dest) { + if (src<0 || src>=chans) return; + if (dest<0 || dest>=chans) return; + BUSY_BEGIN; + saveLock.lock(); + swapChannels(src,dest); + saveLock.unlock(); + BUSY_END; +} + +void DivEngine::changeSystem(int index, DivSystem which, bool preserveOrder) { + int chanCount=chans; quitDispatch(); BUSY_BEGIN; saveLock.lock(); + + if (!preserveOrder) { + int firstChan=0; + int chanMovement=getChannelCount(which)-getChannelCount(song.system[index]); + while (dispatchOfChan[firstChan]!=index) firstChan++; + int lastChan=firstChan+getChannelCount(song.system[index]); + if (chanMovement!=0) { + if (chanMovement>0) { + // add channels + for (int i=chanCount+chanMovement-1; i>=lastChan+chanMovement; i--) { + swapChannels(i,i-chanMovement); + } + for (int i=lastChan; ichanInsType[j][0]!=DIV_INS_NULL) { isInsTypePossible[sysDefs[song.system[i]]->chanInsType[j][0]]=true; - logV("Marking"); } if (sysDefs[song.system[i]]->chanInsType[j][1]!=DIV_INS_NULL) { diff --git a/src/engine/engine.h b/src/engine/engine.h index b63693882..b0687baa2 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -397,6 +397,8 @@ class DivEngine { void registerSystems(); void exchangeIns(int one, int two); + void swapChannels(int src, int dest); + void stompChannel(int ch); public: DivSong song; @@ -764,14 +766,17 @@ class DivEngine { // public render samples void renderSamplesP(); + // public swap channels + void swapChannelsP(int src, int dest); + // change system - void changeSystem(int index, DivSystem which); + void changeSystem(int index, DivSystem which, bool preserveOrder=true); // add system bool addSystem(DivSystem which); // remove system - bool removeSystem(int index); + bool removeSystem(int index, bool preserveOrder=true); // write to register on system void poke(int sys, unsigned int addr, unsigned short val); diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index ba07269ab..34d216983 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -198,6 +198,12 @@ void DivPlatformAmiga::tick(bool sysTick) { chan[i].ws.tick(); } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].std.phaseReset.had) { @@ -207,7 +213,7 @@ void DivPlatformAmiga::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA); - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2); if (chan[i].freq>4095) chan[i].freq=4095; if (chan[i].freq<0) chan[i].freq=0; if (chan[i].keyOn) { @@ -266,7 +272,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (chan[c.chan].useWave) { chan[c.chan].ws.init(ins,chan[c.chan].audLen<<1,255,chan[c.chan].insChanged); } @@ -277,7 +283,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) { chan[c.chan].sample=-1; chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -364,7 +370,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) { } case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/amiga.h b/src/engine/platform/amiga.h index a4c1a7a44..0777100d7 100644 --- a/src/engine/platform/amiga.h +++ b/src/engine/platform/amiga.h @@ -27,7 +27,7 @@ class DivPlatformAmiga: public DivDispatch { struct Channel { - int freq, baseFreq, pitch; + int freq, baseFreq, pitch, pitch2; unsigned int audLoc; unsigned short audLen; unsigned int audPos; @@ -41,10 +41,15 @@ class DivPlatformAmiga: public DivDispatch { signed char vol, outVol; DivMacroInt std; DivWaveSynth ws; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), audLoc(0), audLen(0), audPos(0), diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 6be50b6e4..f993a400d 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -275,6 +275,12 @@ void DivPlatformArcade::tick(bool sysTick) { } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } @@ -420,7 +426,7 @@ void DivPlatformArcade::tick(bool sysTick) { for (int i=0; i<8; i++) { if (chan[i].freqChanged) { - chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].std.pitch.val; + chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].pitch2; if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1; immWrite(i+0x28,hScale(chan[i].freq>>6)); @@ -452,7 +458,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { chan[c.chan].state=ins->fm; } - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index e051e8aba..68f6baad3 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -36,18 +36,23 @@ class DivPlatformArcade: public DivDispatch { DivInstrumentFM state; DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, note; + int freq, baseFreq, pitch, pitch2, note; int ins; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset; int vol, outVol; unsigned char chVolL, chVolR; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), active(false), diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index fc2a36ab6..12ea0f64a 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -216,6 +216,12 @@ void DivPlatformAY8910::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].std.phaseReset.had) { @@ -239,7 +245,7 @@ void DivPlatformAY8910::tick(bool sysTick) { if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2); if (chan[i].freq>4095) chan[i].freq=4095; if (chan[i].keyOn) { //rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); @@ -302,7 +308,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); } else if (intellivision && (chan[c.chan].psgMode&4)) { @@ -315,7 +321,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { case DIV_CMD_NOTE_OFF: chan[c.chan].keyOff=true; chan[c.chan].active=false; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -457,7 +463,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AY)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index ce06fc9fc..2bc4a03d3 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -32,7 +32,7 @@ class DivPlatformAY8910: public DivDispatch { inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; } struct Channel { unsigned char freqH, freqL; - int freq, baseFreq, note, pitch; + int freq, baseFreq, note, pitch, pitch2; int ins; unsigned char psgMode, autoEnvNum, autoEnvDen; signed char konCycles; @@ -40,7 +40,11 @@ class DivPlatformAY8910: public DivDispatch { int vol, outVol; unsigned char pan; DivMacroInt std; - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {} + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } + Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), pitch2(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {} }; Channel chan[3]; bool isMuted[3]; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 03e99961d..e0cbd9803 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -227,6 +227,12 @@ void DivPlatformAY8930::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].std.phaseReset.had) { @@ -261,7 +267,7 @@ void DivPlatformAY8930::tick(bool sysTick) { immWrite(0x1a,ayNoiseOr); } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2); if (chan[i].freq>65535) chan[i].freq=65535; if (chan[i].keyOn) { if (chan[i].insChanged) { @@ -326,7 +332,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); } else { @@ -337,7 +343,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { case DIV_CMD_NOTE_OFF: chan[c.chan].keyOff=true; chan[c.chan].active=false; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -482,7 +488,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 61a186f4c..ced107fcf 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -28,7 +28,7 @@ class DivPlatformAY8930: public DivDispatch { protected: struct Channel { unsigned char freqH, freqL; - int freq, baseFreq, note, pitch; + int freq, baseFreq, note, pitch, pitch2; int ins; unsigned char psgMode, autoEnvNum, autoEnvDen, duty; signed char konCycles; @@ -36,7 +36,11 @@ class DivPlatformAY8930: public DivDispatch { int vol, outVol; unsigned char pan; DivMacroInt std; - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), duty(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(31), pan(3) {} + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } + Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), pitch2(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), duty(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(31), pan(3) {} }; Channel chan[3]; bool isMuted[3]; diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 6783bc336..3224bfee9 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -111,6 +111,12 @@ void DivPlatformBubSysWSG::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].active) { @@ -120,7 +126,7 @@ void DivPlatformBubSysWSG::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SCC); - chan[i].freq=0x1000-parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val; + chan[i].freq=0x1000-parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].pitch2; if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>4095) chan[i].freq=4095; k005289->load(i,chan[i].freq); @@ -151,7 +157,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) { chan[c.chan].active=true; chan[c.chan].keyOn=true; rWrite(2+c.chan,(chan[c.chan].wave<<5)|chan[c.chan].vol); - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (chan[c.chan].wave<0) { chan[c.chan].wave=0; chan[c.chan].ws.changeWave1(chan[c.chan].wave); @@ -163,7 +169,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) { case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -228,7 +234,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SCC)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/bubsyswsg.h b/src/engine/platform/bubsyswsg.h index 0fbb2ac5d..a28b4ac1d 100644 --- a/src/engine/platform/bubsyswsg.h +++ b/src/engine/platform/bubsyswsg.h @@ -28,16 +28,21 @@ class DivPlatformBubSysWSG: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; signed char vol, outVol, wave; signed char waveROM[32] = {0}; // 4 bit PROM per channel on bubble system DivMacroInt std; DivWaveSynth ws; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), active(false), diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 3515f0465..7e9cf4d18 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -183,6 +183,12 @@ void DivPlatformC64::tick(bool sysTick) { rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active)); } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].std.ex1.had) { @@ -205,7 +211,7 @@ void DivPlatformC64::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8,chan[i].pitch2); if (chan[i].freq>0xffff) chan[i].freq=0xffff; if (chan[i].keyOn) { rWrite(i*7+5,(chan[i].attack<<4)|(chan[i].decay)); @@ -264,14 +270,14 @@ int DivPlatformC64::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].insChanged=false; } - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); break; } case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; - //chan[c.chan].std.init(NULL); + //chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: chan[c.chan].active=false; @@ -352,7 +358,7 @@ int DivPlatformC64::dispatch(DivCommand c) { case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta || !chan[c.chan].inPorta) { - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_C64)); + chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_C64)); chan[c.chan].keyOn=true; } } diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index bc3cbf98f..a4968fee5 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -26,17 +26,22 @@ class DivPlatformC64: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, prevFreq, testWhen, note, ins; + int freq, baseFreq, pitch, pitch2, prevFreq, testWhen, note, ins; unsigned char sweep, wave, attack, decay, sustain, release; short duty; bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, filter; bool resetMask, resetFilter, resetDuty, ring, sync, test; signed char vol, outVol; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), prevFreq(65535), testWhen(0), note(0), diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 5659bd49c..a0f98613c 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -270,6 +270,12 @@ void DivPlatformES5506::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAL(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } // phase reset macro @@ -300,9 +306,9 @@ void DivPlatformES5506::tick(bool sysTick) { } break; case 2: { // delta - signed int next_k1=MAX(0,MIN(65535,chan[i].filter.k1+chan[i].std.ex1.val)); - if (chan[i].filter.k1!=next_k1) { - chan[i].filter.k1=next_k1; + signed int next_k1=CLAMP_VAL(chan[i].k1Offs+chan[i].std.ex1.val,-65535,65535); + if (chan[i].k1Offs!=next_k1) { + chan[i].k1Offs=next_k1; chan[i].filterChanged.k1=1; } break; @@ -326,9 +332,9 @@ void DivPlatformES5506::tick(bool sysTick) { } break; case 2: { // delta - signed int next_k2=MAX(0,MIN(65535,chan[i].filter.k2+chan[i].std.ex2.val)); - if (chan[i].filter.k2!=next_k2) { - chan[i].filter.k2=next_k2; + signed int next_k2=CLAMP_VAL(chan[i].k2Offs+chan[i].std.ex2.val,-65535,65535); + if (chan[i].k2Offs!=next_k2) { + chan[i].k2Offs=next_k2; chan[i].filterChanged.k2=1; } break; @@ -399,15 +405,15 @@ void DivPlatformES5506::tick(bool sysTick) { pageWriteMask(0x00|i,0x5f,0x00,(chan[i].filter.mode<<8),0x0300); } if (chan[i].filterChanged.k2) { - if (chan[i].std.ex2.mode==0) { // Relative - pageWrite(0x00|i,0x07,MAX(0,MIN(65535,chan[i].filter.k2+chan[i].k2Offs))); + if (chan[i].std.ex2.mode!=1) { // Relative + pageWrite(0x00|i,0x07,CLAMP_VAL(chan[i].filter.k2+chan[i].k2Offs,0,65535)); } else { pageWrite(0x00|i,0x07,chan[i].filter.k2); } } if (chan[i].filterChanged.k1) { - if (chan[i].std.ex1.mode==0) { // Relative - pageWrite(0x00|i,0x09,MAX(0,MIN(65535,chan[i].filter.k1+chan[i].k1Offs))); + if (chan[i].std.ex1.mode!=1) { // Relative + pageWrite(0x00|i,0x09,CLAMP_VAL(chan[i].filter.k1+chan[i].k1Offs,0,65535)); } else { pageWrite(0x00|i,0x09,chan[i].filter.k1); } @@ -456,13 +462,13 @@ void DivPlatformES5506::tick(bool sysTick) { pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0)); // initialize filter pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(chan[i].filter.mode<<8),0xc300); - if ((chan[i].std.ex2.mode==0) && (chan[i].std.ex2.had)) { - pageWrite(0x00|i,0x07,MAX(0,MIN(65535,chan[i].filter.k2+chan[i].k2Offs))); + if ((chan[i].std.ex2.mode!=1) && (chan[i].std.ex2.had)) { + pageWrite(0x00|i,0x07,CLAMP_VAL(chan[i].filter.k2+chan[i].k2Offs,0,65535)); } else { pageWrite(0x00|i,0x07,chan[i].filter.k2); } - if ((chan[i].std.ex1.mode==0) && (chan[i].std.ex1.had)) { - pageWrite(0x00|i,0x09,MAX(0,MIN(65535,chan[i].filter.k1+chan[i].k1Offs))); + if ((chan[i].std.ex1.mode!=1) && (chan[i].std.ex1.had)) { + pageWrite(0x00|i,0x09,CLAMP_VAL(chan[i].filter.k1+chan[i].k1Offs,0,65535)); } else { pageWrite(0x00|i,0x09,chan[i].filter.k1); } @@ -506,38 +512,35 @@ int DivPlatformES5506::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins); - if (chan[c.chan].insChanged) { - chan[c.chan].sample=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].ind:ins->amiga.initSample; - double off=1.0; - if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { - chan[c.chan].pcm.index=chan[c.chan].sample; - DivSample* s=parent->getSample(chan[c.chan].sample); - if (s->centerRate<1) { - off=1.0; - } else { - off=ins->amiga.useNoteMap?((double)ins->amiga.noteMap[c.value].freq/((double)s->centerRate*pow(2.0,((double)c.value-48.0)/12.0))):((double)s->centerRate/8363.0); - } - const unsigned int start=s->offES5506<<10; - const unsigned int length=s->samples-1; - const unsigned int end=start+(length<<11); - chan[c.chan].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; - chan[c.chan].pcm.freqOffs=off; - chan[c.chan].pcm.reversed=ins->amiga.reversed; - chan[c.chan].pcm.bank=(s->offES5506>>22)&3; - chan[c.chan].pcm.start=start; - chan[c.chan].pcm.end=end; - chan[c.chan].pcm.length=length; - chan[c.chan].pcm.loopStart=(start+(s->loopStart<<11))&0xfffff800; - chan[c.chan].pcm.loopEnd=(start+((s->loopEnd-1)<<11))&0xffffff80; - chan[c.chan].filter=ins->es5506.filter; - chan[c.chan].envelope=ins->es5506.envelope; + chan[c.chan].sample=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].ind:ins->amiga.initSample; + double off=1.0; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + chan[c.chan].pcm.index=chan[c.chan].sample; + DivSample* s=parent->getSample(chan[c.chan].sample); + if (s->centerRate<1) { + off=1.0; } else { - chan[c.chan].sample=-1; - chan[c.chan].pcm.index=-1; - chan[c.chan].filter=DivInstrumentES5506::Filter(); - chan[c.chan].envelope=DivInstrumentES5506::Envelope(); + off=(ins->amiga.useNoteMap?((double)ins->amiga.noteMap[c.value].freq/((double)s->centerRate*pow(2.0,((double)c.value-48.0)/12.0))):1.0)*((double)s->centerRate/8363.0); } - chan[c.chan].insChanged=false; + const unsigned int start=s->offES5506<<10; + const unsigned int length=s->samples-1; + const unsigned int end=start+(length<<11); + chan[c.chan].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; + chan[c.chan].pcm.freqOffs=off; + chan[c.chan].pcm.reversed=ins->amiga.reversed; + chan[c.chan].pcm.bank=(s->offES5506>>22)&3; + chan[c.chan].pcm.start=start; + chan[c.chan].pcm.end=end; + chan[c.chan].pcm.length=length; + chan[c.chan].pcm.loopStart=(start+(s->loopStart<<11))&0xfffff800; + chan[c.chan].pcm.loopEnd=(start+((s->loopEnd-1)<<11))&0xffffff80; + chan[c.chan].filter=ins->es5506.filter; + chan[c.chan].envelope=ins->es5506.envelope; + } else { + chan[c.chan].sample=-1; + chan[c.chan].pcm.index=-1; + chan[c.chan].filter=DivInstrumentES5506::Filter(); + chan[c.chan].envelope=DivInstrumentES5506::Envelope(); } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_ES5506(c.chan,c.value); @@ -556,7 +559,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); break; } case DIV_CMD_NOTE_OFF: @@ -565,7 +568,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].sample=-1; chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -694,7 +697,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { } case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins)); } chan[c.chan].inPorta=c.value; break; @@ -763,6 +766,7 @@ void DivPlatformES5506::reset() { pageWriteMask(0x00,0x60,0x0b,chanMax); pageWriteMask(0x00,0x60,0x0b,0x1f); + // set serial output to I2S-ish, 16 bit pageWriteMask(0x20,0x60,0x0a,0x01); pageWriteMask(0x20,0x60,0x0b,0x11); pageWriteMask(0x20,0x60,0x0c,0x20); diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index fc49525f7..47a7e2935 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -54,7 +54,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { loopEnd(0), loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {} } pcm; - int freq, baseFreq, pitch, note, ins, sample, wave; + int freq, baseFreq, pitch, pitch2, note, ins, sample, wave; bool active, insChanged, freqChanged, volChanged, keyOn, keyOff, inPorta, useWave, isReverseLoop; struct FilterChanged { // Filter changed flags @@ -96,10 +96,21 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { DivInstrumentES5506::Filter filter; DivInstrumentES5506::Envelope envelope; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + if (std.ex1.mode==2) { + k1Offs=0; + } + if (std.ex1.mode==2) { + k2Offs=0; + } + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), sample(-1), @@ -111,6 +122,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { keyOn(false), keyOff(false), inPorta(false), + useWave(false), + isReverseLoop(false), k1Offs(0), k2Offs(0), vol(0xff), diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index 845e72475..f1e2bfdec 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -146,6 +146,12 @@ void DivPlatformFDS::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].active) { @@ -177,7 +183,7 @@ void DivPlatformFDS::tick(bool sysTick) { } } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2); if (chan[i].freq>4095) chan[i].freq=4095; if (chan[i].freq<0) chan[i].freq=0; if (chan[i].keyOn) { @@ -241,7 +247,7 @@ int DivPlatformFDS::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (chan[c.chan].wave<0) { chan[c.chan].wave=0; ws.changeWave1(chan[c.chan].wave); @@ -254,7 +260,7 @@ int DivPlatformFDS::dispatch(DivCommand c) { case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -358,7 +364,7 @@ int DivPlatformFDS::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FDS)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FDS)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/fds.h b/src/engine/platform/fds.h index bf9492722..ed0c77d72 100644 --- a/src/engine/platform/fds.h +++ b/src/engine/platform/fds.h @@ -26,16 +26,21 @@ class DivPlatformFDS: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, prevFreq, note, modFreq, ins; + int freq, baseFreq, pitch, pitch2, prevFreq, note, modFreq, ins; unsigned char duty, sweep, modDepth, modPos; bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, modOn; signed char vol, outVol, wave; signed char modTable[32]; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), prevFreq(65535), note(0), modFreq(0), diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index ded7b493c..0cfdb960c 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -198,6 +198,12 @@ void DivPlatformGB::tick(bool sysTick) { rWrite(0x25,procMute()); } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].std.phaseReset.had) { @@ -227,7 +233,7 @@ void DivPlatformGB::tick(bool sysTick) { if (ntPos>255) ntPos=255; chan[i].freq=noiseTable[ntPos]; } else { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2); if (chan[i].freq>2047) chan[i].freq=2047; if (chan[i].freq<0) chan[i].freq=0; } @@ -281,7 +287,7 @@ int DivPlatformGB::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (c.chan==2) { if (chan[c.chan].wave<0) { chan[c.chan].wave=0; @@ -295,7 +301,7 @@ int DivPlatformGB::dispatch(DivCommand c) { case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -379,7 +385,7 @@ int DivPlatformGB::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_GB)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_GB)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index c79603ab1..2cdbc7858 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -27,15 +27,20 @@ class DivPlatformGB: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; unsigned char duty, sweep; bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta; signed char vol, outVol, wave; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), duty(0), diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index e4642b32a..ad4d28683 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -282,6 +282,12 @@ void DivPlatformGenesis::tick(bool sysTick) { } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } @@ -412,7 +418,7 @@ void DivPlatformGenesis::tick(bool sysTick) { for (int i=0; i<6; i++) { if (i==2 && extMode) continue; if (chan[i].freqChanged) { - int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].std.pitch.val); + int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2); int block=(chan[i].baseFreq&0xf800)>>11; if (fNum<0) fNum=0; if (fNum>2047) { @@ -436,7 +442,7 @@ void DivPlatformGenesis::tick(bool sysTick) { off=(double)s->centerRate/8363.0; } } - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4)+chan[i].std.pitch.val; + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4)+chan[i].pitch2; dacRate=chan[i].freq*off; if (dacRate<1) dacRate=1; if (dumpWrites) addWrite(0xffff0001,dacRate); @@ -526,7 +532,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { chan[c.chan].state=ins->fm; } - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 31f11d188..0482ea0a0 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -36,17 +36,22 @@ class DivPlatformGenesis: public DivDispatch { DivInstrumentFM state; DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, portaPauseFreq, note; + int freq, baseFreq, pitch, pitch2, portaPauseFreq, note; int ins; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset; int vol, outVol; unsigned char pan; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), + pitch2(0), portaPauseFreq(0), note(0), ins(-1), diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index d77857a66..e5d964e5d 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -307,7 +307,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) { unsigned char writeMask=2; if (extMode) for (int i=0; i<4; i++) { if (opChan[i].freqChanged) { - int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,false,4,opChan[i].std.pitch.val); + int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,false,4,opChan[i].pitch2); int block=(opChan[i].baseFreq&0xf800)>>11; if (fNum<0) fNum=0; if (fNum>2047) { diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index e3604a34c..c246ee3f3 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -25,7 +25,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { struct OpChannel { DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, portaPauseFreq, ins; + int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause; int vol; @@ -36,6 +36,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { freq(0), baseFreq(0), pitch(0), + pitch2(0), portaPauseFreq(0), ins(-1), active(false), diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index f70198b6e..9a1f4d3d2 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -186,6 +186,12 @@ void DivPlatformLynx::tick(bool sysTick) { } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } @@ -195,7 +201,7 @@ void DivPlatformLynx::tick(bool sysTick) { WRITE_OTHER(i, ((chan[i].lfsr&0xf00)>>4)); chan[i].lfsr=-1; } - chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val); + chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2); if (chan[i].std.duty.had) { chan[i].duty=chan[i].std.duty.val; WRITE_FEEDBACK(i, chan[i].duty.feedback); @@ -224,12 +230,12 @@ int DivPlatformLynx::dispatch(DivCommand c) { } chan[c.chan].active=true; WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127))); - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); + chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; WRITE_VOLUME(c.chan, 0); - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_LYNX_LFSR_LOAD: chan[c.chan].freqChanged=true; @@ -241,7 +247,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { break; case DIV_CMD_INSTRUMENT: chan[c.chan].ins=c.value; - //chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); + //chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); break; case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { @@ -297,7 +303,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/lynx.h b/src/engine/platform/lynx.h index f1f974ed0..5200fbd9c 100644 --- a/src/engine/platform/lynx.h +++ b/src/engine/platform/lynx.h @@ -44,16 +44,21 @@ class DivPlatformLynx: public DivDispatch { DivMacroInt std; MikeyFreqDiv fd; MikeyDuty duty; - int baseFreq, pitch, note, actualNote, lfsr, ins; + int baseFreq, pitch, pitch2, note, actualNote, lfsr, ins; unsigned char pan; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; signed char vol, outVol; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): std(), fd(0), duty(0), baseFreq(0), pitch(0), + pitch2(0), note(0), actualNote(0), lfsr(-1), diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 4e70b388a..c4818cb37 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -125,6 +125,12 @@ void DivPlatformMMC5::tick(bool sysTick) { rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].std.phaseReset.had) { @@ -134,7 +140,7 @@ void DivPlatformMMC5::tick(bool sysTick) { } } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val)-1; + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2)-1; if (chan[i].freq>2047) chan[i].freq=2047; if (chan[i].freq<0) chan[i].freq=0; if (chan[i].keyOn) { @@ -228,7 +234,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); + chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); rWrite(0x5000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6)); break; case DIV_CMD_NOTE_OFF: @@ -238,7 +244,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { } chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -306,7 +312,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index 879ebee18..bf7eeaad5 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -25,15 +25,20 @@ class DivPlatformMMC5: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, prevFreq, note, ins; + int freq, baseFreq, pitch, pitch2, prevFreq, note, ins; unsigned char duty, sweep; bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac; signed char vol, outVol, wave; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), prevFreq(65535), note(0), ins(-1), diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 34515305e..5d3c9c201 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -262,6 +262,12 @@ void DivPlatformN163::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].std.ex1.had) { @@ -347,7 +353,7 @@ void DivPlatformN163::tick(bool sysTick) { chan[i].waveUpdated=false; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq((((chan[i].baseFreq*chan[i].waveLen)*(chanMax+1))/16),chan[i].pitch,false,0,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq((((chan[i].baseFreq*chan[i].waveLen)*(chanMax+1))/16),chan[i].pitch,false,0,chan[i].pitch2); if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>0x3ffff) chan[i].freq=0x3ffff; if (chan[i].keyOn) { @@ -398,7 +404,7 @@ int DivPlatformN163::dispatch(DivCommand c) { if (!isMuted[c.chan]) { chan[c.chan].volumeChanged=true; } - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); chan[c.chan].ws.init(ins,chan[c.chan].waveLen,15,chan[c.chan].insChanged); break; } @@ -406,7 +412,7 @@ int DivPlatformN163::dispatch(DivCommand c) { chan[c.chan].active=false; chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; - //chan[c.chan].std.init(NULL); + //chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: chan[c.chan].active=false; @@ -546,7 +552,7 @@ int DivPlatformN163::dispatch(DivCommand c) { case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) { - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_N163)); + chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_N163)); chan[c.chan].keyOn=true; } } diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index 38ebeace3..d01030848 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -28,7 +28,7 @@ class DivPlatformN163: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note; + int freq, baseFreq, pitch, pitch2, note; short ins, wave, wavePos, waveLen; unsigned char waveMode; short loadWave, loadPos, loadLen; @@ -37,10 +37,15 @@ class DivPlatformN163: public DivDispatch { signed char vol, outVol, resVol; DivMacroInt std; DivWaveSynth ws; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), wave(-1), diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index ddface2f0..7da1a0908 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -197,6 +197,12 @@ void DivPlatformNES::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].sweepChanged) { @@ -218,7 +224,7 @@ void DivPlatformNES::tick(bool sysTick) { if (ntPos>252) ntPos=252; chan[i].freq=(parent->song.properNoiseLayout)?(15-(chan[i].baseFreq&15)):(noiseTable[ntPos]); } else { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val)-1; + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2)-1; if (chan[i].freq>2047) chan[i].freq=2047; if (chan[i].freq<0) chan[i].freq=0; } @@ -326,7 +332,7 @@ int DivPlatformNES::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); + chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); if (c.chan==2) { rWrite(0x4000+c.chan*4,0xff); } else { @@ -340,7 +346,7 @@ int DivPlatformNES::dispatch(DivCommand c) { } chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -429,7 +435,7 @@ int DivPlatformNES::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 7650d39e9..d88b447f4 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -25,15 +25,20 @@ class DivPlatformNES: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, prevFreq, note, ins; + int freq, baseFreq, pitch, pitch2, prevFreq, note, ins; unsigned char duty, sweep; bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac; signed char vol, outVol, wave; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), prevFreq(65535), note(0), ins(-1), diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 1e727fa66..c127ce774 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -274,6 +274,12 @@ void DivPlatformOPL::tick(bool sysTick) { } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } @@ -417,9 +423,9 @@ void DivPlatformOPL::tick(bool sysTick) { bool updateDrums=false; for (int i=0; icalcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].pitch2); if (chan[i].freq>131071) chan[i].freq=131071; - int freqt=toFreq(chan[i].freq)+chan[i].std.pitch.val; + int freqt=toFreq(chan[i].freq)+chan[i].pitch2; chan[i].freqH=freqt>>8; chan[i].freqL=freqt&0xff; immWrite(chanMap[i]+ADDR_FREQ,chan[i].freqL); @@ -541,7 +547,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { chan[c.chan].state=ins->fm; } - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } @@ -549,7 +555,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2; chan[c.chan].fourOp=(ops==4); if (chan[c.chan].fourOp) { - chan[c.chan+1].std.init(NULL); + chan[c.chan+1].macroInit(NULL); } update4OpMask=true; for (int i=0; icalcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].pitch2); if (chan[i].freq>262143) chan[i].freq=262143; - int freqt=toFreq(chan[i].freq)+chan[i].std.pitch.val; + int freqt=toFreq(chan[i].freq)+chan[i].pitch2; chan[i].freqL=freqt&0xff; if (i>=6 && properDrums) { immWrite(0x10+drumSlot[i],freqt&0xff); @@ -370,7 +376,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { chan[c.chan].state=ins->fm; } - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } diff --git a/src/engine/platform/opll.h b/src/engine/platform/opll.h index 79f905c66..96cb1a914 100644 --- a/src/engine/platform/opll.h +++ b/src/engine/platform/opll.h @@ -33,16 +33,21 @@ class DivPlatformOPLL: public DivDispatch { DivInstrumentFM state; DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta; int vol, outVol; unsigned char pan; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), active(false), diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 08cb77390..6e249aa36 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -208,6 +208,12 @@ void DivPlatformPCE::tick(bool sysTick) { chWrite(i,0x05,isMuted[i]?0:chan[i].pan); } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].active) { @@ -217,7 +223,7 @@ void DivPlatformPCE::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE); - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2); if (chan[i].furnaceDac) { double off=1.0; if (chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { @@ -279,7 +285,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].note=c.value; } chan[c.chan].active=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); //chan[c.chan].keyOn=true; chan[c.chan].furnaceDac=true; } else { @@ -316,7 +322,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].active=true; chan[c.chan].keyOn=true; chWrite(c.chan,0x04,0x80|chan[c.chan].vol); - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (chan[c.chan].wave<0) { chan[c.chan].wave=0; chan[c.chan].ws.changeWave1(chan[c.chan].wave); @@ -331,7 +337,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].pcm=false; chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -429,7 +435,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_PCE)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index deb85fbb9..b1b140383 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -28,7 +28,7 @@ class DivPlatformPCE: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note; + int freq, baseFreq, pitch, pitch2, note; int dacPeriod, dacRate; unsigned int dacPos; int dacSample, ins; @@ -37,10 +37,15 @@ class DivPlatformPCE: public DivDispatch { signed char vol, outVol, wave; DivMacroInt std; DivWaveSynth ws; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), dacPeriod(0), dacRate(0), diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 1a4b2ee06..5da1923cf 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -190,10 +190,16 @@ void DivPlatformPCSpeaker::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val)-1; + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2)-1; if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>65535) chan[i].freq=65535; if (chan[i].keyOn) { @@ -220,12 +226,12 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER)); + chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER)); break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -285,7 +291,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/pcspkr.h b/src/engine/platform/pcspkr.h index f8813f3ff..d2c01454e 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -25,15 +25,20 @@ class DivPlatformPCSpeaker: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; unsigned char duty, sweep; bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac; signed char vol, outVol, wave; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), duty(0), diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index eb954a6e1..5a7efe1f9 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -116,7 +116,7 @@ void DivPlatformPET::tick(bool sysTick) { chan.freqChanged=true; } if (chan.freqChanged || chan.keyOn || chan.keyOff) { - chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true,0,chan.std.pitch.val); + chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true,0,chan.pitch2); if (chan.freq>257) chan.freq=257; if (chan.freq<2) chan.freq=2; rWrite(8,chan.freq-2); @@ -146,13 +146,13 @@ int DivPlatformPET::dispatch(DivCommand c) { } chan.active=true; chan.keyOn=true; - chan.std.init(ins); + chan.macroInit(ins); break; } case DIV_CMD_NOTE_OFF: chan.active=false; chan.keyOff=true; - chan.std.init(NULL); + chan.macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -213,7 +213,7 @@ int DivPlatformPET::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan.active && c.value2) { - if (parent->song.resetMacroOnPorta) chan.std.init(parent->getIns(chan.ins,DIV_INS_PET)); + if (parent->song.resetMacroOnPorta) chan.macroInit(parent->getIns(chan.ins,DIV_INS_PET)); } chan.inPorta=c.value; break; diff --git a/src/engine/platform/pet.h b/src/engine/platform/pet.h index b4b75316e..c26ef5392 100644 --- a/src/engine/platform/pet.h +++ b/src/engine/platform/pet.h @@ -25,17 +25,22 @@ class DivPlatformPET: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; int vol, outVol, wave; unsigned char sreg; int cnt; short out; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), active(false), diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 179e1317d..a38bde376 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -327,11 +327,17 @@ void DivPlatformQSound::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA); - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2); if (chan[i].freq>0xffff) chan[i].freq=0xffff; if (chan[i].keyOn) { rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank); @@ -386,14 +392,14 @@ int DivPlatformQSound::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); break; } case DIV_CMD_NOTE_OFF: chan[c.chan].sample=-1; chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -487,7 +493,7 @@ int DivPlatformQSound::dispatch(DivCommand c) { } case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index aa07a3b47..1eb9b2751 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -27,7 +27,7 @@ class DivPlatformQSound: public DivDispatch { struct Channel { - int freq, baseFreq, pitch; + int freq, baseFreq, pitch, pitch2; unsigned short audLen; unsigned int audPos; int sample, wave, ins; @@ -36,10 +36,15 @@ class DivPlatformQSound: public DivDispatch { bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave; int vol, outVol; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), audLen(0), audPos(0), sample(-1), diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index 2d4986b58..4d79d45bd 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -187,6 +187,12 @@ void DivPlatformSAA1099::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].std.ex1.had) { @@ -194,7 +200,7 @@ void DivPlatformSAA1099::tick(bool sysTick) { rWrite(0x18+(i/3),saaEnv[i/3]); } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2); if (chan[i].freq>65535) chan[i].freq=65535; if (chan[i].freq>=32768) { chan[i].freqH=7; @@ -257,7 +263,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (isMuted[c.chan]) { rWrite(c.chan,0); } else { @@ -268,7 +274,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) { case DIV_CMD_NOTE_OFF: chan[c.chan].keyOff=true; chan[c.chan].active=false; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -356,7 +362,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index 309092936..24108da79 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -35,14 +35,18 @@ class DivPlatformSAA1099: public DivDispatch { protected: struct Channel { unsigned char freqH, freqL; - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; unsigned char psgMode; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; int vol, outVol; unsigned char pan; DivMacroInt std; - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), note(0), ins(-1), psgMode(1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(255) {} + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } + Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), psgMode(1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(255) {} }; Channel chan[6]; bool isMuted[6]; diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index e4fe02439..ea3a72d0c 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -116,6 +116,12 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } /*if (chan[i].keyOn || chan[i].keyOff) { @@ -132,7 +138,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { DivSample* s=parent->getSample(chan[i].pcm.sample); off=(double)s->centerRate/8363.0; } - chan[i].pcm.freq=MIN(255,(15625+(off*parent->song.tuning*pow(2.0,double(chan[i].freq+256)/(64.0*12.0)))*255)/31250)+chan[i].std.pitch.val; + chan[i].pcm.freq=MIN(255,(15625+(off*parent->song.tuning*pow(2.0,double(chan[i].freq+256)/(64.0*12.0)))*255)/31250)+chan[i].pitch2; if (dumpWrites) { addWrite(0x10007+(i<<3),chan[i].pcm.freq); } @@ -158,7 +164,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { if (dumpWrites) { addWrite(0x10086+(c.chan<<3),3); } - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; } chan[c.chan].pcm.pos=0; @@ -168,7 +174,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].freqChanged=true; } chan[c.chan].furnacePCM=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (dumpWrites) { // Sega PCM writes DivSample* s=parent->getSample(chan[c.chan].pcm.sample); addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); @@ -185,7 +191,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { } } } else { - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; } @@ -227,7 +233,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: chan[c.chan].keyOff=true; diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 3a68a34b3..7ef09892a 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -29,7 +29,7 @@ class DivPlatformSegaPCM: public DivDispatch { struct Channel { DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM; int vol, outVol; @@ -42,7 +42,11 @@ class DivPlatformSegaPCM: public DivDispatch { unsigned char freq; PCMChannel(): sample(-1), pos(0), len(0), freq(0) {} } pcm; - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {} + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } + Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {} }; Channel chan[16]; struct QueuedWrite { diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index faf5ba7d6..d0a19d1db 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -101,12 +101,18 @@ void DivPlatformSMS::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } } for (int i=0; i<3; i++) { if (chan[i].freqChanged) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2); if (chan[i].freq>1023) chan[i].freq=1023; if (chan[i].freq<8) chan[i].freq=1; //if (chan[i].actualNote>0x5d) chan[i].freq=0x01; @@ -121,7 +127,7 @@ void DivPlatformSMS::tick(bool sysTick) { } } if (chan[3].freqChanged || updateSNMode) { - chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].std.pitch.val); + chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].pitch2); if (chan[3].freq>1023) chan[3].freq=1023; if (chan[3].actualNote>0x5d) chan[3].freq=0x01; if (snNoiseMode&2) { // take period from channel 3 @@ -177,12 +183,12 @@ int DivPlatformSMS::dispatch(DivCommand c) { } chan[c.chan].active=true; rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); + chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; rWrite(0x9f|c.chan<<5); - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -190,7 +196,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { break; case DIV_CMD_INSTRUMENT: chan[c.chan].ins=c.value; - //chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); + //chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); break; case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { @@ -246,7 +252,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index 66fdda857..a79945bdd 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -26,14 +26,19 @@ class DivPlatformSMS: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note, actualNote, ins; + int freq, baseFreq, pitch, pitch2, note, actualNote, ins; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; signed char vol, outVol; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), actualNote(0), ins(-1), diff --git a/src/engine/platform/sound/es550x/es5505.cpp b/src/engine/platform/sound/es550x/es5505.cpp index d2d4731cf..0b460f773 100644 --- a/src/engine/platform/sound/es550x/es5505.cpp +++ b/src/engine/platform/sound/es550x/es5505.cpp @@ -456,7 +456,7 @@ void es5505_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) switch (address) { case 13: // ACT (Number of voices) - m_active = clamp(bitfield(data, 0, 5), 7, 31); + m_active = std::max(7, bitfield(data, 0, 5)); break; case 14: // IRQV (Interrupting voice vector) // Read only diff --git a/src/engine/platform/sound/es550x/es5506.cpp b/src/engine/platform/sound/es550x/es5506.cpp index 133611eee..85245f408 100644 --- a/src/engine/platform/sound/es550x/es5506.cpp +++ b/src/engine/platform/sound/es550x/es5506.cpp @@ -166,7 +166,7 @@ void es5506_core::tick() void es5506_core::tick_perf() { // output - if (((!m_mode.lrclk_en) && (!m_mode.bclk_en) && (!m_mode.bclk_en)) && (m_w_st < m_w_end)) + if (((!m_mode.lrclk_en) && (!m_mode.bclk_en) && (!m_mode.wclk_en)) && (m_w_st < m_w_end)) { const int output_bits = 20 - (m_w_end - m_w_st); if (output_bits < 20) @@ -307,7 +307,7 @@ s32 es5506_core::voice_t::volume_calc(u16 volume, s32 in) { u8 exponent = bitfield(volume, 12, 4); u8 mantissa = bitfield(volume, 4, 8); - return (in * s32(0x100 | mantissa)) >> (19 - exponent); + return (in * s32(0x100 | mantissa)) >> (20 - exponent); } void es5506_core::reset() @@ -771,7 +771,7 @@ void es5506_core::regs_w(u8 page, u8 address, u32 data, bool cpu_access) v.m_k1ramp.ramp = bitfield(data, 8, 8); break; case 11: // ACT (Number of voices) - m_active = std::min(4, bitfield(data, 0, 5)); + m_active = std::max(4, bitfield(data, 0, 5)); break; case 12: // MODE (Global Mode) m_mode.lrclk_en = bitfield(data, 0); diff --git a/src/engine/platform/sound/es550x/es550x.hpp b/src/engine/platform/sound/es550x/es550x.hpp index 4c7a8fa77..d1dae9e3d 100644 --- a/src/engine/platform/sound/es550x/es550x.hpp +++ b/src/engine/platform/sound/es550x/es550x.hpp @@ -42,7 +42,7 @@ namespace es550x // std::clamp is only for C++17 or later; I use my own code template T clamp(T in, T min, T max) { - return (in < max) ? max : ((in > min) ? min : in); + return std::min(std::max(in, min), max); } template diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 1f47a1629..6efa0a482 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -151,6 +151,12 @@ void DivPlatformSoundUnit::tick(bool sysTick) { chWrite(i,0x03,chan[i].pan); } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].std.ex1.had) { @@ -168,7 +174,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU); - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2); chWrite(i,0x00,chan[i].freq&0xff); chWrite(i,0x01,chan[i].freq>>8); if (chan[i].freq>65535) chan[i].freq=65535; @@ -198,14 +204,14 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { chan[c.chan].active=true; chan[c.chan].keyOn=true; chWrite(c.chan,0x02,chan[c.chan].vol); - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); chan[c.chan].insChanged=false; break; } case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -275,7 +281,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SU)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SU)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index 6291d4531..7315f49a3 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -27,7 +27,7 @@ class DivPlatformSoundUnit: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note; + int freq, baseFreq, pitch, pitch2, note; int ins, cutoff, res, control; signed char pan; unsigned char duty; @@ -35,10 +35,15 @@ class DivPlatformSoundUnit: public DivDispatch { bool pcmLoop, timerSync, freqSweep, volSweep, cutSweep; signed char vol, outVol, wave; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), cutoff(65535), diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 9be2883e2..b2d4fbcb8 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -185,6 +185,12 @@ void DivPlatformSwan::tick(bool sysTick) { calcAndWriteOutVol(i,chan[i].std.vol.will?chan[i].std.vol.val:15); } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].active) { @@ -194,7 +200,7 @@ void DivPlatformSwan::tick(bool sysTick) { } } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2); if (i==1 && pcm && furnaceDac) { double off=1.0; if (dacSample>=0 && dacSamplesong.sampleLen) { @@ -271,7 +277,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { } chan[1].active=true; chan[1].keyOn=true; - chan[1].std.init(ins); + chan[1].macroInit(ins); furnaceDac=true; } else { if (c.value!=DIV_NOTE_NULL) { @@ -303,7 +309,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (chan[c.chan].wave<0) { chan[c.chan].wave=0; chan[c.chan].ws.changeWave1(chan[c.chan].wave); @@ -320,7 +326,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { } chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -417,7 +423,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index fdad150b2..c03dd0d55 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -28,16 +28,21 @@ class DivPlatformSwan: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; unsigned char pan; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; int vol, outVol, wave; DivMacroInt std; DivWaveSynth ws; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), pan(255), diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index cc5151f03..f6f7dd9cf 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -117,6 +117,12 @@ void DivPlatformTIA::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { @@ -127,14 +133,14 @@ void DivPlatformTIA::tick(bool sysTick) { } chan[i].insChanged=false; } - chan[i].freq=dealWithFreq(chan[i].shape,chan[i].baseFreq,chan[i].pitch)+chan[i].std.pitch.val; + chan[i].freq=dealWithFreq(chan[i].shape,chan[i].baseFreq,chan[i].pitch)+chan[i].pitch2; if ((chan[i].shape==4 || chan[i].shape==5) && !(chan[i].baseFreq&0x80000000 && ((chan[i].baseFreq&0x7fffffff)<32))) { if (chan[i].baseFreq<39*256) { rWrite(0x15+i,6); - chan[i].freq=dealWithFreq(6,chan[i].baseFreq,chan[i].pitch)+chan[i].std.pitch.val; + chan[i].freq=dealWithFreq(6,chan[i].baseFreq,chan[i].pitch)+chan[i].pitch2; } else if (chan[i].baseFreq<59*256) { rWrite(0x15+i,12); - chan[i].freq=dealWithFreq(12,chan[i].baseFreq,chan[i].pitch)+chan[i].std.pitch.val; + chan[i].freq=dealWithFreq(12,chan[i].baseFreq,chan[i].pitch)+chan[i].pitch2; } else { rWrite(0x15+i,chan[i].shape); } @@ -163,7 +169,7 @@ int DivPlatformTIA::dispatch(DivCommand c) { chan[c.chan].active=true; chan[c.chan].keyOn=true; rWrite(0x15+c.chan,chan[c.chan].shape); - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (isMuted[c.chan]) { rWrite(0x19+c.chan,0); } else { @@ -174,7 +180,7 @@ int DivPlatformTIA::dispatch(DivCommand c) { case DIV_CMD_NOTE_OFF: chan[c.chan].keyOff=true; chan[c.chan].active=false; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -248,7 +254,7 @@ int DivPlatformTIA::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_TIA)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_TIA)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index 602cc6f1e..dc3bbfd10 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -27,13 +27,17 @@ class DivPlatformTIA: public DivDispatch { protected: struct Channel { - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; unsigned char shape; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; int vol, outVol; DivMacroInt std; - Channel(): freq(0), baseFreq(0), pitch(0), note(0), ins(-1), shape(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15) {} + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } + Channel(): freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), shape(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15) {} }; Channel chan[2]; bool isMuted[2]; diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 712335818..643b6ebcf 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -229,6 +229,12 @@ void DivPlatformTX81Z::tick(bool sysTick) { } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } @@ -391,7 +397,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { for (int i=0; i<8; i++) { if (chan[i].freqChanged) { - chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].std.pitch.val; + chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].pitch2; if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1; immWrite(i+0x28,hScale(chan[i].freq>>6)); @@ -430,7 +436,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { chan[c.chan].state=ins->fm; } - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index d9261ebd7..5df591f64 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -35,17 +35,22 @@ class DivPlatformTX81Z: public DivDispatch { DivInstrumentFM state; DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset; int vol, outVol; unsigned char chVolL, chVolR; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), active(false), diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index d579be6ca..6404553b4 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -191,10 +191,16 @@ void DivPlatformVERA::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].freqChanged) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8,chan[i].pitch2); if (chan[i].freq>65535) chan[i].freq=65535; rWrite(i,0,chan[i].freq&0xff); rWrite(i,1,(chan[i].freq>>8)&0xff); @@ -223,7 +229,7 @@ void DivPlatformVERA::tick(bool sysTick) { } } if (chan[16].freqChanged) { - chan[16].freq=parent->calcFreq(chan[16].baseFreq,chan[16].pitch,false,8)+chan[16].std.pitch.val; + chan[16].freq=parent->calcFreq(chan[16].baseFreq,chan[16].pitch,false,8,chan[16].pitch2); if (chan[16].freq>128) chan[16].freq=128; rWritePCMRate(chan[16].freq&0xff); chan[16].freqChanged=false; @@ -259,7 +265,7 @@ int DivPlatformVERA::dispatch(DivCommand c) { chan[c.chan].note=c.value; } chan[c.chan].active=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VERA)); + chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA)); break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; @@ -270,7 +276,7 @@ int DivPlatformVERA::dispatch(DivCommand c) { rWritePCMCtrl(0x80); rWritePCMRate(0); } - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -327,7 +333,7 @@ int DivPlatformVERA::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VERA)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/vera.h b/src/engine/platform/vera.h index 64dee5c78..ddcbed36a 100644 --- a/src/engine/platform/vera.h +++ b/src/engine/platform/vera.h @@ -29,7 +29,7 @@ struct VERA_PCM; class DivPlatformVERA: public DivDispatch { protected: struct Channel { - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; unsigned char pan; bool active, freqChanged, inPorta; int vol, outVol; @@ -45,7 +45,12 @@ class DivPlatformVERA: public DivDispatch { bool depth16; PCMChannel(): sample(-1), pos(0), len(0), freq(0), depth16(false) {} } pcm; - Channel(): freq(0), baseFreq(0), pitch(0), note(0), ins(-1), pan(0), active(false), freqChanged(false), inPorta(false), vol(0), outVol(0), accum(0), noiseval(0) {} + // somebody please split this into multiple lines! + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } + Channel(): freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), pan(0), active(false), freqChanged(false), inPorta(false), vol(0), outVol(0), accum(0), noiseval(0) {} }; Channel chan[17]; bool isMuted[17]; diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index efeb0a206..32b1418f2 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -120,10 +120,16 @@ void DivPlatformVIC20::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2); if (i<3) { chan[i].freq>>=(2-i); } else { @@ -166,13 +172,13 @@ int DivPlatformVIC20::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); break; } case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -232,7 +238,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VIC)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VIC)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/vic20.h b/src/engine/platform/vic20.h index 8c15c35d9..2b3f08e7f 100644 --- a/src/engine/platform/vic20.h +++ b/src/engine/platform/vic20.h @@ -27,15 +27,20 @@ class DivPlatformVIC20: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; unsigned char pan; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; int vol, outVol, wave, waveWriteCycle; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), pan(255), diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 0d25a9fc9..979bc4b84 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -179,13 +179,19 @@ void DivPlatformVRC6::tick(bool sysTick) { } } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { if (i==2) { // sawtooth - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val)-1; + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2)-1; } else { // pulse - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val)-1; + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2)-1; if (chan[i].furnaceDac) { double off=1.0; if (chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { @@ -249,7 +255,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { chan[c.chan].note=c.value; } chan[c.chan].active=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); //chan[c.chan].keyOn=true; chan[c.chan].furnaceDac=true; } else { @@ -284,7 +290,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6)); + chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6)); if (!isMuted[c.chan]) { if (c.chan==2) { // sawtooth chWrite(c.chan,0,chan[c.chan].vol); @@ -299,7 +305,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { chan[c.chan].pcm=false; chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -380,7 +386,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/vrc6.h b/src/engine/platform/vrc6.h index a44e9d336..789af7f52 100644 --- a/src/engine/platform/vrc6.h +++ b/src/engine/platform/vrc6.h @@ -28,7 +28,7 @@ class DivPlatformVRC6: public DivDispatch { struct Channel { - int freq, baseFreq, pitch, note; + int freq, baseFreq, pitch, pitch2, note; int dacPeriod, dacRate, dacOut; unsigned int dacPos; int dacSample, ins; @@ -36,10 +36,15 @@ class DivPlatformVRC6: public DivDispatch { bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, pcm, furnaceDac; signed char vol, outVol; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), dacPeriod(0), dacRate(0), diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 46db65622..9d64adfa9 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -383,6 +383,12 @@ void DivPlatformX1_010::tick(bool sysTick) { chan[i].envChanged=true; } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } if (chan[i].std.ex1.had) { @@ -476,7 +482,7 @@ void DivPlatformX1_010::tick(bool sysTick) { chan[i].envChanged=false; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2); if (chan[i].pcm) { if (chan[i].freq<1) chan[i].freq=1; if (chan[i].freq>255) chan[i].freq=255; @@ -535,7 +541,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { if (skipRegisterWrites) break; if (chan[c.chan].furnacePCM) { chan[c.chan].pcm=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); chan[c.chan].sample=ins->amiga.initSample; if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { DivSample* s=parent->getSample(chan[c.chan].sample); @@ -548,7 +554,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { chan[c.chan].freqChanged=true; } } else { - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { chWrite(c.chan,0,0); // reset @@ -560,7 +566,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { } } } else { - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { chWrite(c.chan,0,0); // reset @@ -585,7 +591,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { chan[c.chan].active=true; chan[c.chan].keyOn=true; chan[c.chan].envChanged=true; - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (chan[c.chan].wave<0) { chan[c.chan].wave=0; chan[c.chan].ws.changeWave1(chan[c.chan].wave); @@ -599,7 +605,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { chan[c.chan].pcm=false; chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: @@ -703,7 +709,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index bee546473..8dc749842 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -79,7 +79,7 @@ class DivPlatformX1_010: public DivDispatch { slide(0), slidefrac(0) {} }; - int freq, baseFreq, pitch, note; + int freq, baseFreq, pitch, pitch2, note; int wave, sample, ins; unsigned char pan, autoEnvNum, autoEnvDen; bool active, insChanged, envChanged, freqChanged, keyOn, keyOff, inPorta, furnacePCM, pcm; @@ -89,7 +89,7 @@ class DivPlatformX1_010: public DivDispatch { DivMacroInt std; DivWaveSynth ws; void reset() { - freq = baseFreq = pitch = note = 0; + freq = baseFreq = pitch = pitch2 = note = 0; wave = sample = ins = -1; pan = 255; autoEnvNum = autoEnvDen = 0; @@ -99,8 +99,12 @@ class DivPlatformX1_010: public DivDispatch { vol = outVol = lvol = rvol = 15; waveBank = 0; } + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): - freq(0), baseFreq(0), pitch(0), note(0), + freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), wave(-1), sample(-1), ins(-1), pan(255), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), envChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), furnacePCM(false), pcm(false), diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 96d43f64a..2fbd9e09a 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -414,6 +414,12 @@ void DivPlatformYM2610::tick(bool sysTick) { } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } @@ -572,9 +578,9 @@ void DivPlatformYM2610::tick(bool sysTick) { for (int i=0; i<4; i++) { if (i==1 && extMode) continue; if (chan[i].freqChanged) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].pitch2); if (chan[i].freq>262143) chan[i].freq=262143; - int freqt=toFreq(chan[i].freq)+chan[i].std.pitch.val; + int freqt=toFreq(chan[i].freq)+chan[i].pitch2; immWrite(chanOffs[i]+ADDR_FREQH,freqt>>8); immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff); chan[i].freqChanged=false; @@ -643,7 +649,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { } if (skipRegisterWrites) break; if (chan[c.chan].furnacePCM) { - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; immWrite(0x1b,chan[c.chan].outVol); @@ -675,7 +681,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { } } else { chan[c.chan].sample=-1; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { immWrite(0x10,0x01); // reset @@ -719,7 +725,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (c.chan<4) { if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; @@ -779,7 +785,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: if (c.chan>12) { @@ -981,7 +987,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { case DIV_CMD_PRE_PORTA: if (c.chan>3) { if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); } } chan[c.chan].inPorta=c.value; diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index af947199d..56f6824d0 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -43,7 +43,7 @@ class DivPlatformYM2610: public DivDispatch { struct Channel { DivInstrumentFM state; unsigned char freqH, freqL; - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; unsigned char psgMode, autoEnvNum, autoEnvDen; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; @@ -51,12 +51,17 @@ class DivPlatformYM2610: public DivDispatch { int sample; unsigned char pan; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), psgMode(1), diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 316957fb5..717e81913 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -478,6 +478,12 @@ void DivPlatformYM2610B::tick(bool sysTick) { } if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-2048,2048); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } chan[i].freqChanged=true; } @@ -635,9 +641,9 @@ void DivPlatformYM2610B::tick(bool sysTick) { for (int i=0; i<6; i++) { if (i==2 && extMode) continue; if (chan[i].freqChanged) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].std.pitch.val); + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].pitch2); if (chan[i].freq>262143) chan[i].freq=262143; - int freqt=toFreq(chan[i].freq)+chan[i].std.pitch.val; + int freqt=toFreq(chan[i].freq)+chan[i].pitch2; immWrite(chanOffs[i]+ADDR_FREQH,freqt>>8); immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff); chan[i].freqChanged=false; @@ -706,7 +712,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { } if (skipRegisterWrites) break; if (chan[c.chan].furnacePCM) { - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; immWrite(0x1b,chan[c.chan].outVol); @@ -738,7 +744,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { } } else { chan[c.chan].sample=-1; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { immWrite(0x10,0x01); // reset @@ -782,7 +788,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - chan[c.chan].std.init(ins); + chan[c.chan].macroInit(ins); if (c.chan<6) { if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; @@ -842,7 +848,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; - chan[c.chan].std.init(NULL); + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: if (c.chan>14) { @@ -1044,7 +1050,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { case DIV_CMD_PRE_PORTA: if (c.chan>5) { if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); + if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); } } chan[c.chan].inPorta=c.value; diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index d2363ed14..c01b9515a 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -35,7 +35,7 @@ class DivPlatformYM2610B: public DivDispatch { struct Channel { DivInstrumentFM state; unsigned char freqH, freqL; - int freq, baseFreq, pitch, note, ins; + int freq, baseFreq, pitch, pitch2, note, ins; unsigned char psgMode, autoEnvNum, autoEnvDen; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; @@ -43,12 +43,17 @@ class DivPlatformYM2610B: public DivDispatch { int sample; unsigned char pan; DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), + pitch2(0), note(0), ins(-1), psgMode(1), diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 74794a7d7..e930934d0 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -235,7 +235,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) { unsigned char writeMask=2; if (extMode) for (int i=0; i<4; i++) { if (opChan[i].freqChanged) { - opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch); + opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,false,octave(opChan[i].baseFreq),opChan[i].pitch2); if (opChan[i].freq>262143) opChan[i].freq=262143; int freqt=toFreq(opChan[i].freq); opChan[i].freqH=freqt>>8; diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index c2cd4fb37..5dd98c87e 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -25,12 +25,12 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B { struct OpChannel { DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, ins; + int freq, baseFreq, pitch, pitch2, ins; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause; int vol; unsigned char pan; - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {} + OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {} }; OpChannel opChan[4]; bool isOpMuted[4]; diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index df9b43511..c4cb3d9ca 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -235,7 +235,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) { unsigned char writeMask=2; if (extMode) for (int i=0; i<4; i++) { if (opChan[i].freqChanged) { - opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch); + opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,false,octave(opChan[i].baseFreq),opChan[i].pitch2); if (opChan[i].freq>262143) opChan[i].freq=262143; int freqt=toFreq(opChan[i].freq); opChan[i].freqH=freqt>>8; diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index b89229120..0ff45981e 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -25,12 +25,12 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { struct OpChannel { DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, ins; + int freq, baseFreq, pitch, pitch2, ins; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause; int vol; unsigned char pan; - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {} + OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {} }; OpChannel opChan[4]; bool isOpMuted[4]; diff --git a/src/gui/channels.cpp b/src/gui/channels.cpp index 5b2a7e0c6..397ac2f65 100644 --- a/src/gui/channels.cpp +++ b/src/gui/channels.cpp @@ -19,6 +19,8 @@ #include "gui.h" #include "misc/cpp/imgui_stdlib.h" +#include "IconsFontAwesome4.h" +#include void FurnaceGUI::drawChannels() { if (nextWindow==GUI_WINDOW_CHANNELS) { @@ -37,6 +39,18 @@ void FurnaceGUI::drawChannels() { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Checkbox("##Visible",&e->song.chanShow[i]); + ImGui::SameLine(); + ImGui::BeginDisabled(i==0); + if (ImGui::Button(ICON_FA_CHEVRON_UP)) { + e->swapChannelsP(i,i-1); + } + ImGui::EndDisabled(); + ImGui::SameLine(); + ImGui::BeginDisabled(i==(e->getTotalChannelCount()-1)); + if (ImGui::Button(ICON_FA_CHEVRON_DOWN)) { + e->swapChannelsP(i,i+1); + } + ImGui::EndDisabled(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->song.chanName[i]); diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index eb7558b66..5915739cb 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -340,10 +340,11 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %.4x",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); - ImGui::Text("- wave: %d",ch->wave); - ImGui::Text("- sample: %d",ch->sample); ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- sample: %d",ch->sample); + ImGui::Text("- wave: %d",ch->wave); ImGui::Text("* PCM:"); ImGui::Text(" - index: %d",ch->pcm.index); ImGui::Text(" - freqOffs: %.6f",ch->pcm.freqOffs); @@ -364,6 +365,8 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text(" - RVRamp: %d",ch->envelope.rVRamp); ImGui::Text(" - K1Ramp: %d",ch->envelope.k1Ramp); ImGui::Text(" - K2Ramp: %d",ch->envelope.k2Ramp); + ImGui::Text(" - K1Offs: %d",ch->k1Offs); + ImGui::Text(" - K2Offs: %d",ch->k2Offs); ImGui::Text("- vol: %.2x",ch->vol); ImGui::Text("- LVol: %.2x",ch->lVol); ImGui::Text("- RVol: %.2x",ch->rVol); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 5ef9a5640..56e046f08 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1812,7 +1812,7 @@ void FurnaceGUI::processDrags(int dragX, int dragY) { #define sysChangeOption(x,y) \ if (ImGui::MenuItem(getSystemName(y),NULL,e->song.system[x]==y)) { \ - e->changeSystem(x,y); \ + e->changeSystem(x,y,preserveChanPos); \ updateWindowTitle(); \ } @@ -2687,6 +2687,7 @@ bool FurnaceGUI::loop() { ImGui::EndMenu(); } if (ImGui::BeginMenu("change system...")) { + ImGui::Checkbox("Preserve channel positions",&preserveChanPos); for (int i=0; isong.systemLen; i++) { if (ImGui::BeginMenu(fmt::sprintf("%d. %s##_SYSC%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { for (int j=0; availableSystems[j]; j++) { @@ -2699,9 +2700,10 @@ bool FurnaceGUI::loop() { ImGui::EndMenu(); } if (ImGui::BeginMenu("remove system...")) { + ImGui::Checkbox("Preserve channel positions",&preserveChanPos); for (int i=0; isong.systemLen; i++) { if (ImGui::MenuItem(fmt::sprintf("%d. %s##_SYSR%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { - if (!e->removeSystem(i)) { + if (!e->removeSystem(i,preserveChanPos)) { showError("cannot remove system! ("+e->getLastError()+")"); } } @@ -3782,6 +3784,7 @@ FurnaceGUI::FurnaceGUI(): wantCaptureKeyboard(false), displayNew(false), fullScreen(false), + preserveChanPos(false), vgmExportVersion(0x171), drawHalt(10), curFileDialog(GUI_FILE_OPEN), diff --git a/src/gui/gui.h b/src/gui/gui.h index 3b9911c71..14b735b22 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -735,7 +735,7 @@ class FurnaceGUI { String mmlStringW; bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, wantCaptureKeyboard; - bool displayNew, fullScreen; + bool displayNew, fullScreen, preserveChanPos; bool willExport[32]; int vgmExportVersion; int drawHalt; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 09293a663..42d377288 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -218,20 +218,24 @@ const char* dualWSEffects[7]={ "Phase (dual)", }; -const char* macroAbsoluteMode[2]={ - "Relative", - "Absolute" -}; - -const char* macroDummyMode[2]={ - "Bug", - "Bug" -}; - -const char* macroFilterMode[3]={ +const char* macroAbsoluteMode[3]={ "Relative", "Absolute", - "Delta" + NULL +}; +const char* macroRelativeMode[3]={ + "Absolute", + "Relative", + NULL +}; + +const char* macroDummyMode[1]={NULL}; + +const char* macroFilterMode[4]={ + "Relative", + "Absolute", + "Delta", + NULL }; String macroHoverNote(int id, float val) { @@ -1101,7 +1105,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s #define PARAMETER MARK_MODIFIED; e->notifyInsChange(curIns); -#define NORMAL_MACRO(macro,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,sliderHigh,macroDispMin,bitOff,macroMode,macroModeMax,displayModeName,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc,blockMode) \ +#define NORMAL_MACRO(macro,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,sliderHigh,macroDispMin,bitOff,macroMode,displayModeName,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc,blockMode) \ ImGui::TableNextRow(); \ ImGui::TableNextColumn(); \ ImGui::Text("%s",displayName); \ @@ -1114,8 +1118,8 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,¯o.len,&_ONE,&_THREE)) { MARK_MODIFIED \ if (macro.len>127) macro.len=127; \ } \ - if (macroMode && macroModeMax>0) { \ - for (unsigned int m=0; m<=macroModeMax; m++) { \ + if (macroMode && displayModeName[0]!=NULL) { \ + for (unsigned int m=0; displayModeName[m]!=NULL; m++) { \ if (ImGui::RadioButton(displayModeName[m],macro.mode==m)) { \ macro.mode=m; \ } \ @@ -1196,7 +1200,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s } \ ImGui::PopStyleVar(); -#define OP_MACRO(macro,macroHeight,op,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,macroMode,macroModeMax,displayModeName,mmlStr) \ +#define OP_MACRO(macro,macroHeight,op,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,macroMode,displayModeName,mmlStr) \ ImGui::TableNextRow(); \ ImGui::TableNextColumn(); \ ImGui::Text("%s",displayName); \ @@ -1209,8 +1213,8 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,¯o.len,&_ONE,&_THREE)) { MARK_MODIFIED \ if (macro.len>127) macro.len=127; \ } \ - if (macroMode && macroModeMax>0) { \ - for (unsigned int m=0; m<=macroModeMax; m++) { \ + if (macroMode && displayModeName[0]!=NULL) { \ + for (unsigned int m=0; displayModeName[m]!=NULL; m++) { \ if (ImGui::RadioButton(displayModeName[m],macro.mode==m)) { \ macro.mode=m; \ } \ @@ -2235,31 +2239,31 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::BeginTabItem("FM Macros")) { MACRO_BEGIN(0); if (ins->type==DIV_INS_OPLL) { - NORMAL_MACRO(ins->std.algMacro,0,1,"alg",FM_NAME(FM_SUS),32,ins->std.algMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,1,NULL,false); - NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false); - NORMAL_MACRO(ins->std.fmsMacro,0,1,"fms",FM_NAME(FM_DC),32,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,1,NULL,false); - NORMAL_MACRO(ins->std.amsMacro,0,1,"ams",FM_NAME(FM_DM),32,ins->std.amsMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,1,NULL,false); + NORMAL_MACRO(ins->std.algMacro,0,1,"alg",FM_NAME(FM_SUS),32,ins->std.algMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,1,NULL,false); + NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false); + NORMAL_MACRO(ins->std.fmsMacro,0,1,"fms",FM_NAME(FM_DC),32,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,1,NULL,false); + NORMAL_MACRO(ins->std.amsMacro,0,1,"ams",FM_NAME(FM_DM),32,ins->std.amsMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,1,NULL,false); } else { - NORMAL_MACRO(ins->std.algMacro,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL,false); - NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false); + NORMAL_MACRO(ins->std.algMacro,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL,false); + NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false); if (ins->type!=DIV_INS_OPL) { if (ins->type==DIV_INS_OPZ) { // TODO: FMS2/AMS2 macros - NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false); - NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,3,NULL,false); + NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false); + NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,3,NULL,false); } else { - NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false); - NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false); + NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false); + NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false); } } } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { - NORMAL_MACRO(ins->std.ex1Macro,0,127,"ex1","AM Depth",128,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,127,NULL,false); - NORMAL_MACRO(ins->std.ex2Macro,0,127,"ex2","PM Depth",128,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,127,NULL,false); - NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","LFO Speed",128,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,255,NULL,false); - NORMAL_MACRO(ins->std.waveMacro,0,3,"wave","LFO Shape",48,ins->std.waveMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[9],0,3,¯oLFOWaves,false); - NORMAL_MACRO(ins->std.ex4Macro,0,4,"ex4","OpMask",128,ins->std.ex4Macro.open,true,fmOperatorBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],0,4,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,127,"ex1","AM Depth",128,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,127,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,127,"ex2","PM Depth",128,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,127,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","LFO Speed",128,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,255,NULL,false); + NORMAL_MACRO(ins->std.waveMacro,0,3,"wave","LFO Shape",48,ins->std.waveMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[9],0,3,¯oLFOWaves,false); + NORMAL_MACRO(ins->std.ex4Macro,0,4,"ex4","OpMask",128,ins->std.ex4Macro.open,true,fmOperatorBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],0,4,NULL,false); } MACRO_END; ImGui::EndTabItem(); @@ -2284,45 +2288,45 @@ void FurnaceGUI::drawInsEdit() { int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; if (ins->type==DIV_INS_OPL) { - OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]); - OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]); - OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]); - OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]); - OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]); - OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]); - OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]); - OP_MACRO(ins->std.opMacros[ordi].wsMacro,7,ordi,"ws",FM_NAME(FM_WS),64,ins->std.opMacros[ordi].wsMacro.open,false,NULL,false,0,macroDummyMode,mmlString[8]); + OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,macroDummyMode,mmlString[0]); + OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,macroDummyMode,mmlString[1]); + OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,macroDummyMode,mmlString[2]); + OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,macroDummyMode,mmlString[5]); + OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,macroDummyMode,mmlString[4]); + OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,macroDummyMode,mmlString[6]); + OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,macroDummyMode,mmlString[7]); + OP_MACRO(ins->std.opMacros[ordi].wsMacro,7,ordi,"ws",FM_NAME(FM_WS),64,ins->std.opMacros[ordi].wsMacro.open,false,NULL,false,macroDummyMode,mmlString[8]); - OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[9]); - OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]); - OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,0,macroDummyMode,mmlString[11]); - OP_MACRO(ins->std.opMacros[ordi].susMacro,1,ordi,"sus",FM_NAME(FM_SUS),32,ins->std.opMacros[ordi].susMacro.open,true,NULL,false,0,macroDummyMode,mmlString[12]); + OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,macroDummyMode,mmlString[9]); + OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,macroDummyMode,mmlString[10]); + OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,macroDummyMode,mmlString[11]); + OP_MACRO(ins->std.opMacros[ordi].susMacro,1,ordi,"sus",FM_NAME(FM_SUS),32,ins->std.opMacros[ordi].susMacro.open,true,NULL,false,macroDummyMode,mmlString[12]); } else if (ins->type==DIV_INS_OPLL) { - OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]); - OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]); - OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]); - OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]); - OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]); - OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]); - OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]); + OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,macroDummyMode,mmlString[0]); + OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,macroDummyMode,mmlString[1]); + OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,macroDummyMode,mmlString[2]); + OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,macroDummyMode,mmlString[5]); + OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,macroDummyMode,mmlString[4]); + OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,macroDummyMode,mmlString[6]); + OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,macroDummyMode,mmlString[7]); - OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[8]); - OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,0,macroDummyMode,mmlString[9]); - OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]); - OP_MACRO(ins->std.opMacros[ordi].egtMacro,1,ordi,"egt",FM_NAME(FM_EGS),32,ins->std.opMacros[ordi].egtMacro.open,true,NULL,false,0,macroDummyMode,mmlString[11]); + OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,macroDummyMode,mmlString[8]); + OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,macroDummyMode,mmlString[9]); + OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,macroDummyMode,mmlString[10]); + OP_MACRO(ins->std.opMacros[ordi].egtMacro,1,ordi,"egt",FM_NAME(FM_EGS),32,ins->std.opMacros[ordi].egtMacro.open,true,NULL,false,macroDummyMode,mmlString[11]); } else { - OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]); - OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]); - OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]); - OP_MACRO(ins->std.opMacros[ordi].d2rMacro,31,ordi,"d2r",FM_NAME(FM_D2R),64,ins->std.opMacros[ordi].d2rMacro.open,false,NULL,false,0,macroDummyMode,mmlString[3]); - OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]); - OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]); - OP_MACRO(ins->std.opMacros[ordi].rsMacro,3,ordi,"rs",FM_NAME(FM_RS),32,ins->std.opMacros[ordi].rsMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]); - OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]); - OP_MACRO(ins->std.opMacros[ordi].dtMacro,7,ordi,"dt",FM_NAME(FM_DT),64,ins->std.opMacros[ordi].dtMacro.open,false,NULL,false,0,macroDummyMode,mmlString[8]); - OP_MACRO(ins->std.opMacros[ordi].dt2Macro,3,ordi,"dt2",FM_NAME(FM_DT2),32,ins->std.opMacros[ordi].dt2Macro.open,false,NULL,false,0,macroDummyMode,mmlString[9]); - OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]); - OP_MACRO(ins->std.opMacros[ordi].ssgMacro,4,ordi,"ssg",FM_NAME(FM_SSG),64,ins->std.opMacros[ordi].ssgMacro.open,true,ssgEnvBits,false,0,macroDummyMode,mmlString[11]); + OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,macroDummyMode,mmlString[0]); + OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,macroDummyMode,mmlString[1]); + OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,macroDummyMode,mmlString[2]); + OP_MACRO(ins->std.opMacros[ordi].d2rMacro,31,ordi,"d2r",FM_NAME(FM_D2R),64,ins->std.opMacros[ordi].d2rMacro.open,false,NULL,false,macroDummyMode,mmlString[3]); + OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,macroDummyMode,mmlString[4]); + OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,macroDummyMode,mmlString[5]); + OP_MACRO(ins->std.opMacros[ordi].rsMacro,3,ordi,"rs",FM_NAME(FM_RS),32,ins->std.opMacros[ordi].rsMacro.open,false,NULL,false,macroDummyMode,mmlString[6]); + OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,macroDummyMode,mmlString[7]); + OP_MACRO(ins->std.opMacros[ordi].dtMacro,7,ordi,"dt",FM_NAME(FM_DT),64,ins->std.opMacros[ordi].dtMacro.open,false,NULL,false,macroDummyMode,mmlString[8]); + OP_MACRO(ins->std.opMacros[ordi].dt2Macro,3,ordi,"dt2",FM_NAME(FM_DT2),32,ins->std.opMacros[ordi].dt2Macro.open,false,NULL,false,macroDummyMode,mmlString[9]); + OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,macroDummyMode,mmlString[10]); + OP_MACRO(ins->std.opMacros[ordi].ssgMacro,4,ordi,"ssg",FM_NAME(FM_SSG),64,ins->std.opMacros[ordi].ssgMacro.open,true,ssgEnvBits,false,macroDummyMode,mmlString[11]); } MACRO_END; ImGui::PopID(); @@ -2949,32 +2953,32 @@ void FurnaceGUI::drawInsEdit() { if (settings.macroView==0) { // modern view MACRO_BEGIN(28*dpiScale); if (volMax>0) { - NORMAL_MACRO(ins->std.volMacro,volMin,volMax,"vol",volumeLabel,160,ins->std.volMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_VOLUME],mmlString[0],volMin,volMax,NULL,false); + NORMAL_MACRO(ins->std.volMacro,volMin,volMax,"vol",volumeLabel,160,ins->std.volMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_VOLUME],mmlString[0],volMin,volMax,NULL,false); } - NORMAL_MACRO(ins->std.arpMacro,arpMacroScroll,arpMacroScroll+24,"arp","Arpeggio",160,ins->std.arpMacro.open,false,NULL,true,&arpMacroScroll,(arpMode?-60:-120),120,0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[1],-120,120,(ins->std.arpMacro.mode?(¯oHoverNote):NULL),true); + NORMAL_MACRO(ins->std.arpMacro,arpMacroScroll,arpMacroScroll+24,"arp","Arpeggio",160,ins->std.arpMacro.open,false,NULL,true,&arpMacroScroll,(arpMode?-60:-120),120,0,0,true,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[1],-120,120,(ins->std.arpMacro.mode?(¯oHoverNote):NULL),true); if (dutyMax>0) { if (ins->type==DIV_INS_MIKEY) { - NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,true,mikeyFeedbackBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false); + NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,true,mikeyFeedbackBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false); } else if (ins->type==DIV_INS_C64) { - NORMAL_MACRO(ins->std.dutyMacro,dutyMin,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],dutyMin,dutyMax,NULL,false); + NORMAL_MACRO(ins->std.dutyMacro,dutyMin,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],dutyMin,dutyMax,NULL,false); } else if (ins->type==DIV_INS_ES5506) { - NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,¯oHoverES5506FilterMode,false); + NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,¯oHoverES5506FilterMode,false); } else { - NORMAL_MACRO(ins->std.dutyMacro,dutyMin,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],dutyMin,dutyMax,NULL,false); + NORMAL_MACRO(ins->std.dutyMacro,dutyMin,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],dutyMin,dutyMax,NULL,false); } } if (waveMax>0) { - NORMAL_MACRO(ins->std.waveMacro,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacro.open,bitMode,waveNames,false,NULL,0,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false); + NORMAL_MACRO(ins->std.waveMacro,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacro.open,bitMode,waveNames,false,NULL,0,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),false,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false); } if (panMax>0) { if (panSingle) { - NORMAL_MACRO(ins->std.panLMacro,0,2,"panL","Panning",32,ins->std.panLMacro.open,true,panBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false); + NORMAL_MACRO(ins->std.panLMacro,0,2,"panL","Panning",32,ins->std.panLMacro.open,true,panBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false); } else { - NORMAL_MACRO(ins->std.panLMacro,0,panMax,"panL","Panning (left)",MIN(160,(31+panMax)),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false); - NORMAL_MACRO(ins->std.panRMacro,0,panMax,"panR","Panning (right)",MIN(160,(31+panMax)),ins->std.panRMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],0,panMax,NULL,false); + NORMAL_MACRO(ins->std.panLMacro,0,panMax,"panL","Panning (left)",MIN(160,(31+panMax)),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false); + NORMAL_MACRO(ins->std.panRMacro,0,panMax,"panR","Panning (right)",MIN(160,(31+panMax)),ins->std.panRMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],0,panMax,NULL,false); } } - NORMAL_MACRO(ins->std.pitchMacro,pitchMacroScroll,pitchMacroScroll+160,"pitch","Pitch",160,ins->std.pitchMacro.open,false,NULL,true,&pitchMacroScroll,-2048,2047,0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[15],-2048,2047,NULL,!ins->std.pitchMacro.mode); + NORMAL_MACRO(ins->std.pitchMacro,pitchMacroScroll,pitchMacroScroll+160,"pitch","Pitch",160,ins->std.pitchMacro.open,false,NULL,true,&pitchMacroScroll,-2048,2047,0,0,true,macroRelativeMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[15],-2048,2047,NULL,!ins->std.pitchMacro.mode); if (ins->type==DIV_INS_FM || ins->type==DIV_INS_STD || ins->type==DIV_INS_OPL || @@ -2988,74 +2992,74 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_SWAN || ins->type==DIV_INS_ES5506 || ins->type==DIV_INS_SU) { - NORMAL_MACRO(ins->std.phaseResetMacro,0,1,"phaseReset","Phase Reset",32,ins->std.phaseResetMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[16],0,1,NULL,false); + NORMAL_MACRO(ins->std.phaseResetMacro,0,1,"phaseReset","Phase Reset",32,ins->std.phaseResetMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[16],0,1,NULL,false); } if (ex1Max>0) { if (ins->type==DIV_INS_C64) { - NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Filter Mode",64,ins->std.ex1Macro.open,true,filtModeBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Filter Mode",64,ins->std.ex1Macro.open,true,filtModeBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else if (ins->type==DIV_INS_SAA1099) { - NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope",160,ins->std.ex1Macro.open,true,saaEnvBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope",160,ins->std.ex1Macro.open,true,saaEnvBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else if (ins->type==DIV_INS_X1_010) { - NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope Mode",160,ins->std.ex1Macro.open,true,x1_010EnvBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope Mode",160,ins->std.ex1Macro.open,true,x1_010EnvBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else if (ins->type==DIV_INS_N163) { - NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Waveform len.",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Waveform len.",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else if (ins->type==DIV_INS_FDS) { - NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Mod Depth",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Mod Depth",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else if (ins->type==DIV_INS_ES5506) { - NORMAL_MACRO(ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,"ex1","Filter K1",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,true,2,macroFilterMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,"ex1","Filter K1",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,true,macroFilterMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,NULL,false); } else if (ins->type==DIV_INS_SU) { - NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Cutoff",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Cutoff",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else { - NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Duty",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Duty",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } } if (ex2Max>0) { if (ins->type==DIV_INS_C64) { - NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",64,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",64,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } else if (ins->type==DIV_INS_N163) { - NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Waveform update",64,ins->std.ex2Macro.open,true,n163UpdateBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Waveform update",64,ins->std.ex2Macro.open,true,n163UpdateBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } else if (ins->type==DIV_INS_FDS) { - NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Mod Speed",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Mod Speed",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } else if (ins->type==DIV_INS_ES5506) { - NORMAL_MACRO(ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,"ex2","Filter K2",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,true,2,macroFilterMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,"ex2","Filter K2",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,true,macroFilterMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,NULL,false); } else if (ins->type==DIV_INS_SU) { - NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } else { - NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Envelope",ex2Bit?64:160,ins->std.ex2Macro.open,ex2Bit,ayEnvBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Envelope",ex2Bit?64:160,ins->std.ex2Macro.open,ex2Bit,ayEnvBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } } if (ins->type==DIV_INS_C64) { - NORMAL_MACRO(ins->std.ex3Macro,0,2,"ex3","Special",32,ins->std.ex3Macro.open,true,c64SpecialBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false); - NORMAL_MACRO(ins->std.ex4Macro,0,1,"ex4","Test/Gate",32,ins->std.ex4Macro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,1,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,2,"ex3","Special",32,ins->std.ex3Macro.open,true,c64SpecialBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false); + NORMAL_MACRO(ins->std.ex4Macro,0,1,"ex4","Test/Gate",32,ins->std.ex4Macro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,1,NULL,false); } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_X1_010) { - NORMAL_MACRO(ins->std.ex3Macro,0,15,"ex3","AutoEnv Num",96,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,15,NULL,false); - NORMAL_MACRO(ins->std.algMacro,0,15,"alg","AutoEnv Den",96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,15,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,15,"ex3","AutoEnv Num",96,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,15,NULL,false); + NORMAL_MACRO(ins->std.algMacro,0,15,"alg","AutoEnv Den",96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,15,NULL,false); } if (ins->type==DIV_INS_AY8930) { // oh my i am running out of macros - NORMAL_MACRO(ins->std.fbMacro,0,8,"fb","Noise AND Mask",96,ins->std.fbMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,8,NULL,false); - NORMAL_MACRO(ins->std.fmsMacro,0,8,"fms","Noise OR Mask",96,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,8,NULL,false); + NORMAL_MACRO(ins->std.fbMacro,0,8,"fb","Noise AND Mask",96,ins->std.fbMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,8,NULL,false); + NORMAL_MACRO(ins->std.fmsMacro,0,8,"fms","Noise OR Mask",96,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,8,NULL,false); } if (ins->type==DIV_INS_N163) { - NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","Waveform to Load",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false); - NORMAL_MACRO(ins->std.algMacro,0,255,"alg","Wave pos. to Load",160,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,255,NULL,false); - NORMAL_MACRO(ins->std.fbMacro,0,252,"fb","Wave len. to Load",160,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,252,NULL,false); - NORMAL_MACRO(ins->std.fmsMacro,0,2,"fms","Waveform load",64,ins->std.fmsMacro.open,true,n163UpdateBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,2,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","Waveform to Load",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false); + NORMAL_MACRO(ins->std.algMacro,0,255,"alg","Wave pos. to Load",160,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,255,NULL,false); + NORMAL_MACRO(ins->std.fbMacro,0,252,"fb","Wave len. to Load",160,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,252,NULL,false); + NORMAL_MACRO(ins->std.fmsMacro,0,2,"fms","Waveform load",64,ins->std.fmsMacro.open,true,n163UpdateBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,2,NULL,false); } if (ins->type==DIV_INS_FDS) { - NORMAL_MACRO(ins->std.ex3Macro,0,127,"ex3","Mod Position",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,127,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,127,"ex3","Mod Position",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,127,NULL,false); } if (ins->type==DIV_INS_ES5506) { - NORMAL_MACRO(ins->std.ex3Macro,0,511,"ex3","Envelope counter",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,511,NULL,false); - NORMAL_MACRO(ins->std.ex4Macro,-128,127,"ex4","Envelope left volume ramp",160,ins->std.ex4Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],-128,127,NULL,false); - NORMAL_MACRO(ins->std.ex5Macro,-128,127,"ex5","Envelope right volume ramp",160,ins->std.ex5Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],-128,127,NULL,false); - NORMAL_MACRO(ins->std.ex6Macro,-128,127,"ex6","Envelope K1 ramp",160,ins->std.ex6Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],-128,127,NULL,false); - NORMAL_MACRO(ins->std.ex7Macro,-128,127,"ex7","Envelope K2 ramp",160,ins->std.ex7Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],-128,127,NULL,false); - NORMAL_MACRO(ins->std.ex8Macro,0,2,"ex8","Envelope mode",64,ins->std.ex8Macro.open,true,es5506EnvelopeModes,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[11],0,2,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,511,"ex3","Envelope counter",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,511,NULL,false); + NORMAL_MACRO(ins->std.ex4Macro,-128,127,"ex4","Envelope left volume ramp",160,ins->std.ex4Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],-128,127,NULL,false); + NORMAL_MACRO(ins->std.ex5Macro,-128,127,"ex5","Envelope right volume ramp",160,ins->std.ex5Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],-128,127,NULL,false); + NORMAL_MACRO(ins->std.ex6Macro,-128,127,"ex6","Envelope K1 ramp",160,ins->std.ex6Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],-128,127,NULL,false); + NORMAL_MACRO(ins->std.ex7Macro,-128,127,"ex7","Envelope K2 ramp",160,ins->std.ex7Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],-128,127,NULL,false); + NORMAL_MACRO(ins->std.ex8Macro,0,2,"ex8","Envelope mode",64,ins->std.ex8Macro.open,true,es5506EnvelopeModes,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[11],0,2,NULL,false); } if (ins->type==DIV_INS_SU) { - NORMAL_MACRO(ins->std.ex3Macro,0,4,"ex3","Control",64,ins->std.ex3Macro.open,true,suControlBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,4,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,4,"ex3","Control",64,ins->std.ex3Macro.open,true,suControlBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,4,NULL,false); } MACRO_END; diff --git a/src/ta-utils.h b/src/ta-utils.h index 3a619248b..1f07df33c 100644 --- a/src/ta-utils.h +++ b/src/ta-utils.h @@ -40,6 +40,7 @@ typedef std::string String; #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) +#define CLAMP_VAL(s,min,max) (MIN(MAX((s),(min)),(max))) typedef std::wstring WString;