diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 09efbd6c..9ad6793f 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -300,10 +300,12 @@ struct DivInstrumentAmiga { struct NoteMap { int freq; short ind; + bool reversed; NoteMap(): freq(0), - ind(-1) {} + ind(-1), + reversed(false) {} }; short initSample; diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 22a3d709..3205586f 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -236,21 +236,30 @@ void DivPlatformES5506::tick(bool sysTick) { DivInstrument* ins=parent->getIns(chan[i].ins); // volume/panning macros if (chan[i].std.vol.had) { - chan[i].outVol=((chan[i].vol&0xff)*MIN(0xffff,chan[i].std.vol.val))/0xff; - if (!isMuted[i]) { - chan[i].volChanged=true; + const unsigned int nextVol=((chan[i].vol&0xff)*MIN(0xffff,chan[i].std.vol.val))/0xff; + if (chan[i].outVol!=nextVol) { + chan[i].outVol=nextVol; + if (!isMuted[i]) { + chan[i].volChanged.changed=0xff; + } } } if (chan[i].std.panL.had) { - chan[i].outLVol=(((ins->es5506.lVol*(chan[i].lVol&0xf))/0xf)*MIN(0xffff,chan[i].std.panL.val))/0xffff; - if (!isMuted[i]) { - chan[i].volChanged=true; + const unsigned int nextLVol=(((ins->es5506.lVol*(chan[i].lVol&0xff))/0xff)*MIN(0xffff,chan[i].std.panL.val))/0xffff; + if (chan[i].outLVol!=nextLVol) { + chan[i].outLVol=nextLVol; + if (!isMuted[i]) { + chan[i].volChanged.lVol=1; + } } } if (chan[i].std.panR.had) { - chan[i].outRVol=(((ins->es5506.rVol*(chan[i].rVol&0xf))/0xf)*MIN(0xffff,chan[i].std.panR.val))/0xffff; - if (!isMuted[i]) { - chan[i].volChanged=true; + const unsigned int nextRVol=(((ins->es5506.rVol*(chan[i].rVol&0xff))/0xff)*MIN(0xffff,chan[i].std.panR.val))/0xffff; + if (chan[i].outRVol!=nextRVol) { + chan[i].outRVol=nextRVol; + if (!isMuted[i]) { + chan[i].volChanged.rVol=1; + } } } // arpeggio/pitch macros, frequency related @@ -306,7 +315,7 @@ void DivPlatformES5506::tick(bool sysTick) { } break; case 2: { // delta - signed int next_k1=CLAMP_VAL(chan[i].k1Offs+chan[i].std.ex1.val,-65535,65535); + const 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; @@ -332,7 +341,7 @@ void DivPlatformES5506::tick(bool sysTick) { } break; case 2: { // delta - signed int next_k2=CLAMP_VAL(chan[i].k2Offs+chan[i].std.ex2.val,-65535,65535); + const 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; @@ -385,19 +394,54 @@ void DivPlatformES5506::tick(bool sysTick) { } } // update registers - if (chan[i].volChanged) { + if (chan[i].volChanged.changed) { if (!isMuted[i]) { // calculate volume (16 bit) - chan[i].resLVol=(chan[i].outVol*chan[i].outLVol)/0xffff; - chan[i].resRVol=(chan[i].outVol*chan[i].outRVol)/0xffff; - if (!chan[i].keyOn) { - pageWrite(0x00|i,0x02,chan[i].resLVol); - pageWrite(0x00|i,0x04,chan[i].resRVol); + if (chan[i].volChanged.lVol) { + chan[i].resLVol=(chan[i].outVol*chan[i].outLVol)/0xffff; + if (!chan[i].keyOn) { + pageWrite(0x00|i,0x02,chan[i].resLVol); + } + } + if (chan[i].volChanged.rVol) { + chan[i].resRVol=(chan[i].outVol*chan[i].outRVol)/0xffff; + if (!chan[i].keyOn) { + pageWrite(0x00|i,0x04,chan[i].resRVol); + } } } else { // mute pageWrite(0x00|i,0x02,0); pageWrite(0x00|i,0x04,0); } - chan[i].volChanged=false; + chan[i].volChanged.changed=0; + } + if (chan[i].pcmChanged) { + DivInstrument* ins=parent->getIns(chan[i].ins); + if (!ins->amiga.useNoteMap) { + double off=1.0; + if (chan[i].pcm.next>=0 && chan[i].pcm.nextsong.sampleLen) { + chan[i].pcm.index=chan[i].pcm.next; + DivSample* s=parent->getSample(chan[i].pcm.next); + if (s->centerRate<1) { + off=1.0; + } else { + off=(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[i].pcm.loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; + chan[i].pcm.freqOffs=off; + chan[i].pcm.reversed=ins->amiga.reversed; + chan[i].pcm.bank=(s->offES5506>>22)&3; + chan[i].pcm.start=start; + chan[i].pcm.end=end; + chan[i].pcm.length=length; + chan[i].pcm.loopStart=(start+(s->loopStart<<11))&0xfffff800; + chan[i].pcm.loopEnd=(start+((s->loopEnd-1)<<11))&0xffffff80; + chan[i].keyOn=true; + } + } + chan[i].pcmChanged=false; } if (chan[i].filterChanged.changed) { if (!chan[i].keyOn) { @@ -527,7 +571,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { 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.reversed=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].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; @@ -545,17 +589,17 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_ES5506(c.chan,c.value); chan[c.chan].freqChanged=true; - chan[c.chan].volChanged=true; + chan[c.chan].volChanged.changed=0xff; chan[c.chan].note=c.value; } if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=(0xffff*chan[c.chan].vol)/0xff; } if (!chan[c.chan].std.panL.will) { - chan[c.chan].outLVol=(ins->es5506.lVol*chan[c.chan].lVol)/0xf; + chan[c.chan].outLVol=(ins->es5506.lVol*chan[c.chan].lVol)/0xff; } if (!chan[c.chan].std.panR.will) { - chan[c.chan].outRVol=(ins->es5506.rVol*chan[c.chan].rVol)/0xf; + chan[c.chan].outRVol=(ins->es5506.rVol*chan[c.chan].rVol)/0xff; } chan[c.chan].active=true; chan[c.chan].keyOn=true; @@ -580,12 +624,12 @@ int DivPlatformES5506::dispatch(DivCommand c) { } break; case DIV_CMD_VOLUME: - if (chan[c.chan].vol!=c.value) { + if (chan[c.chan].vol!=(unsigned int)(c.value)) { chan[c.chan].vol=c.value; if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=(0xffff*c.value)/0xff; if (!isMuted[c.chan]) { - chan[c.chan].volChanged=true; + chan[c.chan].volChanged.changed=0xff; } } } @@ -600,24 +644,24 @@ int DivPlatformES5506::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan[c.chan].ins); // 08LR, each nibble means volume multipler for each channels // Left volume - unsigned char lVol=(c.value>>4)&0xf; + const unsigned int lVol=(0xff*((c.value>>4)&0xf))/0xf; if (chan[c.chan].lVol!=lVol) { chan[c.chan].lVol=lVol; if (!chan[c.chan].std.panL.has) { - chan[c.chan].outLVol=(ins->es5506.lVol*lVol)/0xf; + chan[c.chan].outLVol=(ins->es5506.lVol*lVol)/0xff; if (!isMuted[c.chan]) { - chan[c.chan].volChanged=true; + chan[c.chan].volChanged.lVol=1; } } } // Right volume - unsigned char rVol=(c.value>>0)&0xf; + const unsigned int rVol=(0xff*((c.value>>0)&0xf))/0xf; if (chan[c.chan].rVol!=rVol) { chan[c.chan].rVol=rVol; if (!chan[c.chan].std.panR.has) { - chan[c.chan].outRVol=(ins->es5506.rVol*rVol)/0xf; + chan[c.chan].outRVol=(ins->es5506.rVol*rVol)/0xff; if (!isMuted[c.chan]) { - chan[c.chan].volChanged=true; + chan[c.chan].volChanged.rVol=1; } } } @@ -667,7 +711,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].envChanged.k2Ramp=1; break; case DIV_CMD_NOTE_PORTA: { - int destFreq=NOTE_ES5506(c.chan,c.value2); + const int destFreq=NOTE_ES5506(c.chan,c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { chan[c.chan].baseFreq+=c.value; @@ -704,7 +748,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { case DIV_CMD_SAMPLE_POS: { if (chan[c.chan].useWave) break; if (chan[c.chan].active) { - unsigned int pos=chan[c.chan].pcm.reversed?(chan[c.chan].pcm.length-c.value):c.value; + const unsigned int pos=chan[c.chan].pcm.reversed?(chan[c.chan].pcm.length-c.value):c.value; if ((chan[c.chan].pcm.reversed && pos>0) || ((!chan[c.chan].pcm.reversed) && posactive?colorOn:colorOff,">> Active"); ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); - ImGui::TextColored(ch->volChanged?colorOn:colorOff,">> VolChanged"); + ImGui::TextColored(ch->volChanged.lVol?colorOn:colorOff,">> LVolChanged"); + ImGui::TextColored(ch->volChanged.rVol?colorOn:colorOff,">> RVolChanged"); ImGui::TextColored(ch->filterChanged.mode?colorOn:colorOff,">> FilterModeChanged"); ImGui::TextColored(ch->filterChanged.k1?colorOn:colorOff,">> FilterK1Changed"); ImGui::TextColored(ch->filterChanged.k2?colorOn:colorOff,">> FilterK2Changed"); @@ -387,6 +388,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::TextColored(ch->envChanged.rVRamp?colorOn:colorOff,">> EnvRVRampChanged"); ImGui::TextColored(ch->envChanged.k1Ramp?colorOn:colorOff,">> EnvK1RampChanged"); ImGui::TextColored(ch->envChanged.k2Ramp?colorOn:colorOff,">> EnvK2RampChanged"); + ImGui::TextColored(ch->pcmChanged?colorOn:colorOff,">> PCMChanged"); ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index cc1c6f49..c979093a 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2513,10 +2513,11 @@ void FurnaceGUI::drawInsEdit() { ImGui::BeginDisabled(ins->amiga.useWave); P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); if (ins->amiga.useNoteMap) { - if (ImGui::BeginTable("NoteMap",3,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { + if (ImGui::BeginTable("NoteMap",4,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupScrollFreeze(0,1); @@ -2526,6 +2527,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("Sample"); ImGui::TableNextColumn(); ImGui::Text("Frequency"); + ImGui::TableNextColumn(); + ImGui::Text("Reversed"); for (int i=0; i<120; i++) { ImGui::TableNextRow(); ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); @@ -2559,6 +2562,8 @@ void FurnaceGUI::drawInsEdit() { if (ins->amiga.noteMap[i].freq<0) ins->amiga.noteMap[i].freq=0; if (ins->amiga.noteMap[i].freq>262144) ins->amiga.noteMap[i].freq=262144; } + ImGui::TableNextColumn(); + P(ImGui::Checkbox("##SR",&ins->amiga.noteMap[i].reversed)); ImGui::PopID(); } ImGui::EndTable();