diff --git a/papers/doc/4-instrument/n163.md b/papers/doc/4-instrument/n163.md index ccf2c46e..0bd91445 100644 --- a/papers/doc/4-instrument/n163.md +++ b/papers/doc/4-instrument/n163.md @@ -1,7 +1,16 @@ # Namco 163 instrument editor -Namco 163 instrument editor consists of 10 macros. +Namco 163 instrument editor consists of two tabs: one controlling various parameters for waveform initialize and macro tab containing 10 macros. +## N163 +- [Initial Waveform] - Determines the initial waveform for playing. +- [Initial Waveform position in RAM] - Determines the initial waveform position will be load to RAM. +- [Initial Waveform length in RAM] - Determines the initial waveform length will be load to RAM. +- [Load waveform before playback] - Determines the load initial waveform into RAM before playback. +- [Update waveforms into RAM when every waveform changes] - Determines the update every different waveform changes in playback. + + +## Macros - [Volume] - volume levels sequence - [Arpeggio]- pitch sequence - [Waveform pos.] - sets the waveform source address in RAM for playback (single nibble unit) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 785c9b19..41ccea39 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -385,6 +385,8 @@ void DivInstrument::putInsData(SafeWriter* w) { w->write(amiga.noteFreq,120*sizeof(unsigned int)); w->write(amiga.noteMap,120*sizeof(short)); } + + // N163 } DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { @@ -733,6 +735,7 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { } } + // N163 return DIV_DATA_SUCCESS; } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index ea52e6d8..a69800a1 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -385,6 +385,17 @@ struct DivInstrumentAmiga { } }; +struct DivInstrumentN163 { + int wave, wavePos, waveLen; + unsigned char waveMode; + + DivInstrumentN163(): + wave(-1), + wavePos(0), + waveLen(0), + waveMode(0) {} +}; + struct DivInstrument { String name; bool mode; @@ -394,6 +405,7 @@ struct DivInstrument { DivInstrumentGB gb; DivInstrumentC64 c64; DivInstrumentAmiga amiga; + DivInstrumentN163 n163; /** * save the instrument to a SafeWriter. diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 9d22bd27..42b55e90 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -172,10 +172,13 @@ void DivPlatformN163::acquire(short* bufL, short* bufR, size_t start, size_t len } void DivPlatformN163::updateWave(int wave, int pos, int len) { - len=MAX(0,MIN(((0x78-(chanMax<<3))<<1)-pos,len)); // avoid conflict with channel register area + len&=0xfc; // 4 nibble boundary DivWavetable* wt=parent->getWave(wave); for (int i=0; i=((0x78-(chanMax<<3))<<1)) { // avoid conflict with channel register area + break; + } unsigned char mask=(addr&1)?0xf0:0x0f; if (wt->max<1 || wt->len<1) { rWriteMask(addr>>1,0,mask); @@ -253,16 +256,16 @@ void DivPlatformN163::tick() { } } if (chan[i].std.hadEx2) { - if ((chan[i].waveMode&0x1)!=(chan[i].std.ex2&0x1)) { // update waveform now - chan[i].waveMode=(chan[i].waveMode&~0x1)|(chan[i].std.ex2&0x1); - if (chan[i].waveMode&0x1) { // rising edge + if ((chan[i].waveMode&0x2)!=(chan[i].std.ex2&0x2)) { // update when every waveform changed + chan[i].waveMode=(chan[i].waveMode&~0x2)|(chan[i].std.ex2&0x2); + if (chan[i].waveMode&0x2) { chan[i].waveUpdated=true; chan[i].waveChanged=true; } } - if ((chan[i].waveMode&0x2)!=(chan[i].std.ex2&0x2)) { // update when every waveform changed - chan[i].waveMode=(chan[i].waveMode&~0x2)|(chan[i].std.ex2&0x2); - if (chan[i].waveMode&0x2) { + if ((chan[i].waveMode&0x1)!=(chan[i].std.ex2&0x1)) { // update waveform now + chan[i].waveMode=(chan[i].waveMode&~0x1)|(chan[i].std.ex2&0x1); + if (chan[i].waveMode&0x1) { // rising edge chan[i].waveUpdated=true; chan[i].waveChanged=true; } @@ -287,15 +290,15 @@ void DivPlatformN163::tick() { } } if (chan[i].std.hadFms) { + if ((chan[i].loadMode&0x2)!=(chan[i].std.fms&0x2)) { // load when every waveform changes + chan[i].loadMode=(chan[i].loadMode&~0x2)|(chan[i].std.fms&0x2); + } if ((chan[i].loadMode&0x1)!=(chan[i].std.fms&0x1)) { // load now chan[i].loadMode=(chan[i].loadMode&~0x1)|(chan[i].std.fms&0x1); if (chan[i].loadMode&0x1) { // rising edge updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc); } } - if ((chan[i].loadMode&0x2)!=(chan[i].std.fms&0x2)) { // load when every waveform changes - chan[i].loadMode=(chan[i].loadMode&~0x2)|(chan[i].std.fms&0x2); - } } if (chan[i].volumeChanged) { if ((!chan[i].active) || isMuted[i]) { @@ -316,7 +319,7 @@ void DivPlatformN163::tick() { 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/16)*(chanMax+1),chan[i].pitch,false,0); + chan[i].freq=parent->calcFreq((((chan[i].baseFreq*chan[i].waveLen)*(chanMax+1))/16),chan[i].pitch,false,0); if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>0x3ffff) chan[i].freq=0x3ffff; if (chan[i].keyOn) { @@ -344,6 +347,17 @@ int DivPlatformN163::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].wave=ins->n163.wave; + chan[c.chan].wavePos=ins->n163.wavePos; + chan[c.chan].waveLen=ins->n163.waveLen; + chan[c.chan].waveMode=ins->n163.waveMode; + chan[c.chan].waveChanged=true; + if (chan[c.chan].waveMode&0x3) { + chan[c.chan].waveUpdated=true; + } + chan[c.chan].insChanged=false; + } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].freqChanged=true; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 24533c8d..b26ea534 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1522,6 +1522,35 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndTabItem(); } + if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem("N163")) { + ImGui::Text("Initial waveform"); + if (ImGui::InputInt("##WAVE",&ins->n163.wave,1,10)) { PARAMETER + if (ins->n163.wave<0) ins->n163.wave=0; + if (ins->n163.wave>=e->song.waveLen) ins->n163.wave=e->song.waveLen-1; + } + ImGui::Text("Initial waveform position in RAM"); + if (ImGui::InputInt("##WAVEPOS",&ins->n163.wavePos,1,16)) { PARAMETER + if (ins->n163.wavePos<0) ins->n163.wavePos=0; + if (ins->n163.wavePos>255) ins->n163.wavePos=255; + } + ImGui::Text("Initial waveform length in RAM"); + if (ImGui::InputInt("##WAVELEN",&ins->n163.waveLen,4,16)) { PARAMETER + if (ins->n163.waveLen<0) ins->n163.waveLen=0; + if (ins->n163.waveLen>252) ins->n163.waveLen=252; + ins->n163.waveLen&=0xfc; + } + + bool preLoad=ins->n163.waveMode&0x1; + if (ImGui::Checkbox("Load waveform before playback",&preLoad)) { PARAMETER + ins->n163.waveMode=(ins->n163.waveMode&~0x1)|(preLoad?0x1:0); + } + bool waveMode=ins->n163.waveMode&0x2; + if (ImGui::Checkbox("Update waveforms into RAM when every waveform changes",&waveMode)) { PARAMETER + ins->n163.waveMode=(ins->n163.waveMode&~0x2)|(waveMode?0x2:0); + } + + ImGui::EndTabItem(); + } if (ImGui::BeginTabItem("Macros")) { float asFloat[256]; int asInt[256]; diff --git a/src/gui/intConst.cpp b/src/gui/intConst.cpp index dae78ff1..9c7f53b9 100644 --- a/src/gui/intConst.cpp +++ b/src/gui/intConst.cpp @@ -29,6 +29,7 @@ const int _THIRTY_ONE=31; const int _SIXTY_FOUR=64; const int _ONE_HUNDRED=100; const int _ONE_HUNDRED_TWENTY_SEVEN=127; +const int _TWO_HUNDRED_FIFTY_FIVE=255; const int _TWO_THOUSAND_FORTY_SEVEN=2047; const int _FOUR_THOUSAND_NINETY_FIVE=4095; const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN=-127; diff --git a/src/gui/intConst.h b/src/gui/intConst.h index 2618ec65..c6b13b9a 100644 --- a/src/gui/intConst.h +++ b/src/gui/intConst.h @@ -31,6 +31,7 @@ extern const int _THIRTY_ONE; extern const int _SIXTY_FOUR; extern const int _ONE_HUNDRED; extern const int _ONE_HUNDRED_TWENTY_SEVEN; +extern const int _TWO_HUNDRED_FIFTY_FIVE; extern const int _TWO_THOUSAND_FORTY_SEVEN; extern const int _FOUR_THOUSAND_NINETY_FIVE; extern const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN;