From 8e1ce1abb10884528037172f826d644ab8ab413c Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 25 Sep 2022 18:32:34 +0900 Subject: [PATCH] Sync to master --- src/engine/engine.h | 1 - src/engine/instrument.h | 2 +- src/engine/platform/es5506.cpp | 412 ++++----- src/engine/platform/es5506.h | 19 +- src/engine/platform/sound/es550x/es5504.cpp | 453 ---------- src/engine/platform/sound/es550x/es5504.hpp | 97 --- src/engine/platform/sound/es550x/es5505.cpp | 606 ------------- src/engine/platform/sound/es550x/es5505.hpp | 152 ---- src/engine/platform/sound/es550x/es5506.cpp | 794 ------------------ src/engine/platform/sound/es550x/es5506.hpp | 190 ----- src/engine/platform/sound/es550x/es550x.cpp | 78 -- src/engine/platform/sound/es550x/es550x.hpp | 284 ------- .../platform/sound/es550x/es550x_alu.cpp | 116 --- .../platform/sound/es550x/es550x_filter.cpp | 71 -- src/engine/platform/sound/es550x/util.hpp | 141 ---- src/engine/sample.h | 6 - src/gui/debugWindow.cpp | 1 + src/gui/gui.h | 2 +- src/gui/guiConst.cpp | 5 +- src/gui/insEdit.cpp | 96 +-- src/gui/sampleEdit.cpp | 10 - 21 files changed, 238 insertions(+), 3298 deletions(-) delete mode 100644 src/engine/platform/sound/es550x/es5504.cpp delete mode 100644 src/engine/platform/sound/es550x/es5504.hpp delete mode 100644 src/engine/platform/sound/es550x/es5505.cpp delete mode 100644 src/engine/platform/sound/es550x/es5505.hpp delete mode 100644 src/engine/platform/sound/es550x/es5506.cpp delete mode 100644 src/engine/platform/sound/es550x/es5506.hpp delete mode 100644 src/engine/platform/sound/es550x/es550x.cpp delete mode 100644 src/engine/platform/sound/es550x/es550x.hpp delete mode 100644 src/engine/platform/sound/es550x/es550x_alu.cpp delete mode 100644 src/engine/platform/sound/es550x/es550x_filter.cpp delete mode 100644 src/engine/platform/sound/es550x/util.hpp diff --git a/src/engine/engine.h b/src/engine/engine.h index 596829f0..ff01d2e1 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -384,7 +384,6 @@ class DivEngine { sample(-1), wave(-1), pos(0), - dir(false), pBegin(-1), pEnd(-1), dir(false) {} diff --git a/src/engine/instrument.h b/src/engine/instrument.h index b6d35935..1336bbd3 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -405,7 +405,7 @@ struct DivInstrumentAmiga { reversed(0), loopStart(-1), loopEnd(-1), - loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {} + loopMode(DIV_SAMPLE_LOOP_MAX) {} }; short initSample; diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 577486af..16cec93e 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -27,7 +27,7 @@ #define NOTE_ES5506(c,note) (parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false)) #define rWrite(a,...) {if(!skipRegisterWrites) {hostIntf32.emplace(4,(a),__VA_ARGS__); }} -#define rRead(a,...) {hostIntf32.emplace(4,(a),__VA_ARGS__);} +#define rRead(a,st,...) {hostIntf32.emplace(st,4,(a),__VA_ARGS__);} #define immWrite(a,...) {hostIntf32.emplace(4,(a),__VA_ARGS__);} #define pageWrite(p,a,...) \ if (!skipRegisterWrites) { \ @@ -47,13 +47,13 @@ rWrite((a),__VA_ARGS__); \ } -#define pageReadMask(p,pm,a,...) \ +#define pageReadMask(p,pm,a,st,...) \ if (!skipRegisterWrites) { \ if ((curPage&(pm))!=((p)&(pm))) { \ curPage=(curPage&~(pm))|((p)&(pm)); \ rWrite(0xf,curPage,(pm)); \ } \ - rRead((a),__VA_ARGS__); \ + rRead(st,(a),__VA_ARGS__); \ } @@ -112,90 +112,16 @@ const char** DivPlatformES5506::getRegisterSheet() { return regCheatSheetES5506; } -const char* DivPlatformES5506::getEffectName(unsigned char effect) { - switch (effect) { - case 0x10: - return "10xx: Change waveform or sample, transwave index"; - break; - case 0x11: - return "11xx: Set filter mode (00 to 03)"; - break; - case 0x12: - return "120x: Set pause (bit 0)"; - break; - case 0x13: - return "130x: Set transwave slice mode (bit 0)"; - break; - case 0x14: - return "14xx: Set filter coefficient K1 low byte"; - break; - case 0x15: - return "15xx: Set filter coefficient K1 high byte"; - break; - case 0x16: - return "16xx: Set filter coefficient K2 low byte"; - break; - case 0x17: - return "17xx: Set filter coefficient K2 high byte"; - break; - case 0x18: - return "18xx: Set filter coefficient K1 slide up"; - break; - case 0x19: - return "19xx: Set filter coefficient K1 slide down"; - break; - case 0x1a: - return "1axx: Set filter coefficient K2 slide up"; - break; - case 0x1b: - return "1bxx: Set filter coefficient K2 slide down"; - break; - case 0x20: - return "20xx: Set envelope count (000 to 0FF)"; - break; - case 0x21: - return "21xx: Set envelope count (100 to 1FF)"; - break; - case 0x22: - return "22xx: Set envelope left volume ramp (signed)"; - break; - case 0x23: - return "23xx: Set envelope right volume ramp (signed)"; - break; - case 0x24: - return "24xx: Set envelope filter coefficient k1 ramp (signed)"; - break; - case 0x25: - return "25xx: Set envelope filter coefficient k1 ramp (signed, slower)"; - break; - case 0x26: - return "26xx: Set envelope filter coefficient k2 ramp (signed)"; - break; - case 0x27: - return "27xx: Set envelope filter coefficient k2 ramp (signed, slower)"; - break; - default: - if ((effect&0xf0)==0x30) { - return "3xxx: Set filter coefficient K1"; - } else if ((effect&0xf0)==0x40) { - return "4xxx: Set filter coefficient K2"; - } else if ((effect&0xf0)==0x50) { - return "5xxx: Set transwave slice point"; - } - break; - } - return NULL; -} void DivPlatformES5506::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; h0) { cycle+=w.delay; } + queuedReadState.emplace(w.read,w.state); isReaded=true; } else { isReaded=false; @@ -272,116 +199,127 @@ void DivPlatformES5506::e_pin(bool state) } } } - if (isReaded) { - isReaded=false; - if (irqTrigger) { - irqTrigger=false; - if ((irqv&0x80)==0) { - unsigned char ch=irqv&0x1f; - if (chan[ch].isReverseLoop) { // Reversed loop - pageWriteMask(0x00|ch,0x5f,0x00,(chan[ch].pcm.reversed?0x0000:0x0040)|0x08,0x78); - chan[ch].isReverseLoop=false; + if (!queuedReadState.empty()) { + QueuedReadState w=queuedReadState.front(); + const unsigned char state=w.state; + if (state&0x80) { + if (irqTrigger) { + if ((irqv&0x80)==0) { + queuedRead.emplace(irqv&0x1f); } - if (chan[ch].transwaveIRQ) { - if ((chan[ch].cr&0x37)==0x34) { // IRQE = 1, BLE = 1, LPE = 0, LEI = 1 - DivInstrument* ins=parent->getIns(chan[ch].ins); - if (!ins->amiga.useNoteMap && ins->amiga.transWave.enable) { - const int next=chan[ch].pcm.next; - if (next>=0 && next<(int)ins->amiga.transWaveMap.size()) { - DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; - int sample=transWaveInd.ind; - if (sample>=0 && samplesong.sampleLen) { - chan[ch].pcm.index=sample; - chan[ch].transWave.ind=next; - DivSample* s=parent->getSample(sample); - // get frequency offset - double off=1.0; - double center=(double)s->centerRate; - if (center<1) { - off=1.0; - } else { - off=(double)center/8363.0; - } - // get loop mode, transwave loop - double loopStart=(double)s->loopStart; - double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) { - loopMode=transWaveInd.loopMode; - } else if ((chan[ch].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; - } - // get loop position - loopStart=(double)transWaveInd.loopStart; - loopEnd=(double)transWaveInd.loopEnd; - if (ins->amiga.transWave.sliceEnable) { // sliced loop position? - chan[ch].transWave.updateSize(s->samples,loopStart,loopEnd); - chan[ch].transWave.slicePos(double(chan[ch].transWave.slice)/4095.0); - loopStart=transWaveInd.sliceStart; - loopEnd=transWaveInd.sliceEnd; - } - // get reversed - bool reversed=ins->amiga.reversed; - if (transWaveInd.reversed!=2) { - reversed=transWaveInd.reversed; - } - const unsigned int start=s->offES5506<<10; - const unsigned int length=s->samples-1; - const unsigned int end=start+(length<<11); - const double nextFreqOffs=PITCH_OFFSET*off; - chan[ch].pcm.loopMode=loopMode; - chan[ch].pcm.reversed=reversed; - chan[ch].pcm.bank=(s->offES5506>>22)&3; - chan[ch].pcm.start=start; - chan[ch].pcm.loopStart=(start+(unsigned int)(loopStart*2048.0))&0xfffff800; - chan[ch].pcm.loopEnd=(start+(unsigned int)((loopEnd-1.0)*2048.0))&0xffffff80; - chan[ch].pcm.end=end; - chan[ch].pcm.length=length; - pageWrite(0x20|ch,0x01,chan[ch].pcm.loopStart); - pageWrite(0x20|ch,0x02,chan[ch].pcm.loopEnd); - pageWrite(0x20|ch,0x03,(chan[ch].pcm.reversed)?chan[ch].pcm.loopEnd:chan[ch].pcm.loopStart); - unsigned int loopFlag=(chan[ch].pcm.bank<<14)|(chan[ch].pcm.reversed?0x0040:0x0000); - chan[ch].isReverseLoop=false; - switch (chan[ch].pcm.loopMode) { - case DIV_SAMPLE_LOOPMODE_ONESHOT: // One shot (no loop) - default: - break; - case DIV_SAMPLE_LOOPMODE_FORWARD: // Foward loop - loopFlag|=0x0008; - break; - case DIV_SAMPLE_LOOPMODE_BACKWARD: // Backward loop: IRQ enable - loopFlag|=0x0038; - chan[ch].isReverseLoop=true; - break; - case DIV_SAMPLE_LOOPMODE_PINGPONG: // Pingpong loop: Hardware support - loopFlag|=0x0018; - break; - } - // Set loop mode & Bank - pageWriteMask(0x00|ch,0x5f,0x00,loopFlag,0xfcfc); - if (chan[ch].pcm.nextFreqOffs!=nextFreqOffs) { - chan[ch].pcm.nextFreqOffs=nextFreqOffs; - chan[ch].noteChanged.offs=1; - } + irqTrigger=false; + } + } else { + unsigned char ch=w.state&0x1f; + if (chan[ch].transwaveIRQ) { + if ((chan[ch].cr&0x37)==0x34) { // IRQE = 1, BLE = 1, LPE = 0, LEI = 1 + DivInstrument* ins=parent->getIns(chan[ch].ins); + if (!ins->amiga.useNoteMap && ins->amiga.transWave.enable) { + const int next=chan[ch].pcm.next; + if (next>=0 && next<(int)ins->amiga.transWaveMap.size()) { + DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; + int sample=transWaveInd.ind; + if (sample>=0 && samplesong.sampleLen) { + chan[ch].pcm.index=sample; + chan[ch].transWave.ind=next; + DivSample* s=parent->getSample(sample); + // get frequency offset + double off=1.0; + double center=(double)s->centerRate; + if (center<1) { + off=1.0; + } else { + off=(double)center/8363.0; + } + // get loop mode, transwave loop + double loopStart=(double)s->loopStart; + double loopEnd=(double)s->loopEnd; + DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; + if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { + loopMode=transWaveInd.loopMode; + } else if ((chan[ch].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default + loopMode=DIV_SAMPLE_LOOP_PINGPONG; + } + // get loop position + loopStart=(double)transWaveInd.loopStart; + loopEnd=(double)transWaveInd.loopEnd; + if (ins->amiga.transWave.sliceEnable) { // sliced loop position? + chan[ch].transWave.updateSize(s->samples,loopStart,loopEnd); + chan[ch].transWave.slicePos(double(chan[ch].transWave.slice)/4095.0); + loopStart=transWaveInd.sliceStart; + loopEnd=transWaveInd.sliceEnd; + } + // get reversed + bool reversed=ins->amiga.reversed; + if (transWaveInd.reversed!=2) { + reversed=transWaveInd.reversed; + } + const unsigned int start=s->offES5506<<10; + const unsigned int length=s->samples-1; + const unsigned int end=start+(length<<11); + const double nextFreqOffs=PITCH_OFFSET*off; + chan[ch].pcm.loopMode=loopMode; + chan[ch].pcm.reversed=reversed; + chan[ch].pcm.bank=(s->offES5506>>22)&3; + chan[ch].pcm.start=start; + chan[ch].pcm.loopStart=(start+(unsigned int)(loopStart*2048.0))&0xfffff800; + chan[ch].pcm.loopEnd=(start+(unsigned int)((loopEnd-1.0)*2048.0))&0xffffff80; + chan[ch].pcm.end=end; + chan[ch].pcm.length=length; + pageWrite(0x20|ch,0x01,chan[ch].pcm.loopStart); + pageWrite(0x20|ch,0x02,chan[ch].pcm.loopEnd); + pageWrite(0x20|ch,0x03,(chan[ch].pcm.reversed)?chan[ch].pcm.loopEnd:chan[ch].pcm.loopStart); + unsigned int loopFlag=(chan[ch].pcm.bank<<14)|(chan[ch].pcm.reversed?0x0040:0x0000); + chan[ch].isReverseLoop=false; + switch (chan[ch].pcm.loopMode) { + case DIV_SAMPLE_LOOP_MAX: // One shot (no loop) + default: + break; + case DIV_SAMPLE_LOOP_FORWARD: // Foward loop + loopFlag|=0x0008; + break; + case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable + loopFlag|=0x0038; + chan[ch].isReverseLoop=true; + break; + case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support + loopFlag|=0x0018; + break; + } + // Set loop mode & Bank + pageWriteMask(0x00|ch,0x5f,0x00,loopFlag,0xfcfc); + if (chan[ch].pcm.nextFreqOffs!=nextFreqOffs) { + chan[ch].pcm.nextFreqOffs=nextFreqOffs; + chan[ch].noteChanged.offs=1; } } - chan[ch].pcmChanged.changed=0; } + chan[ch].pcmChanged.changed=0; } - chan[ch].transwaveIRQ=false; - } - if (chan[ch].isTranswave) { - pageReadMask(0x00|ch,0x5f,0x00,&chan[ch].cr); - chan[ch].transwaveIRQ=true; - chan[ch].isTranswave=false; } + chan[ch].transwaveIRQ=false; } } + queuedReadState.pop(); } + if (!queuedRead.empty()) { + unsigned char ch=queuedRead.front()&0x1f; + if (chan[ch].isReverseLoop) { // Reversed loop + pageWriteMask(0x00|ch,0x5f,0x00,(chan[ch].pcm.reversed?0x0000:0x0040)|0x08,0x78); + chan[ch].isReverseLoop=false; + } + if (chan[ch].isTranswave) { + pageReadMask(0x00|ch,0x5f,0x00,ch,&chan[ch].cr); + chan[ch].transwaveIRQ=true; + chan[ch].isTranswave=false; + } + queuedRead.pop(); + } + isReaded=false; } void DivPlatformES5506::irqb(bool state) { - rRead(0x0e,&irqv,0x9f); + rRead(0x0e,0x80,&irqv,0x9f); irqTrigger=true; } @@ -392,7 +330,7 @@ void DivPlatformES5506::tick(bool sysTick) { signed int k1=chan[i].k1Prev,k2=chan[i].k2Prev; // volume/panning macros if (chan[i].std.vol.had) { - const unsigned int nextVol=((chan[i].vol&0xff)*MIN(0xffff,(0xffff*chan[i].std.vol.val)/chan[i].volMacroMax))/0xff; + const unsigned int nextVol=VOL_SCALE_LOG((0xffff*chan[i].vol)/0xff,(0xffff*chan[i].std.vol.val)/chan[i].volMacroMax,0xffff); if (chan[i].outVol!=nextVol) { chan[i].outVol=nextVol; if (!isMuted[i]) { @@ -401,7 +339,7 @@ void DivPlatformES5506::tick(bool sysTick) { } } if (chan[i].std.panL.had) { - const unsigned int nextLVol=(((ins->es5506.lVol*(chan[i].lVol&0xff))/0xff)*MIN(0xffff,(0xffff*chan[i].std.panL.val)/chan[i].panMacroMax))/0xffff; + const unsigned int nextLVol=VOL_SCALE_LOG((0xffff*chan[i].lVol)/0xff,(0xffff*chan[i].std.panL.val)/chan[i].panMacroMax,0xffff); if (chan[i].outLVol!=nextLVol) { chan[i].outLVol=nextLVol; if (!isMuted[i]) { @@ -410,7 +348,7 @@ void DivPlatformES5506::tick(bool sysTick) { } } if (chan[i].std.panR.had) { - const unsigned int nextRVol=(((ins->es5506.rVol*(chan[i].rVol&0xff))/0xff)*MIN(0xffff,(0xffff*chan[i].std.panR.val)/chan[i].panMacroMax))/0xffff; + const unsigned int nextRVol=VOL_SCALE_LOG((0xffff*chan[i].rVol)/0xff,(0xffff*chan[i].std.panR.val)/chan[i].panMacroMax,0xffff); if (chan[i].outRVol!=nextRVol) { chan[i].outRVol=nextRVol; if (!isMuted[i]) { @@ -458,18 +396,19 @@ void DivPlatformES5506::tick(bool sysTick) { } if (chan[i].std.ex1.had) { switch (chan[i].std.ex1.mode) { - case 0: // relative - if (chan[i].k1Offs!=chan[i].std.ex1.val) { - chan[i].k1Offs=chan[i].std.ex1.val; - chan[i].filterChanged.k1=1; - } - break; - case 1: // absolute + case 0: // absolute if (chan[i].filter.k1!=(chan[i].std.ex1.val&0xffff)) { chan[i].filter.k1=chan[i].std.ex1.val&0xffff; chan[i].filterChanged.k1=1; } break; + case 1: // relative + if (chan[i].k1Offs!=chan[i].std.ex1.val) { + chan[i].k1Offs=chan[i].std.ex1.val; + chan[i].filterChanged.k1=1; + } + break; + /* case 2: { // delta const signed int next_k1=CLAMP(chan[i].k1Offs+chan[i].std.ex1.val,-65535,65535); if (chan[i].k1Offs!=next_k1) { @@ -478,24 +417,26 @@ void DivPlatformES5506::tick(bool sysTick) { } break; } + */ default: break; } } if (chan[i].std.ex2.had) { switch (chan[i].std.ex2.mode) { - case 0: // relative - if (chan[i].k2Offs!=chan[i].std.ex1.val) { - chan[i].k2Offs=chan[i].std.ex1.val; - chan[i].filterChanged.k2=1; - } - break; - case 1: // absolute + case 0: // absolute if (chan[i].filter.k2!=(chan[i].std.ex2.val&0xffff)) { chan[i].filter.k2=chan[i].std.ex2.val&0xffff; chan[i].filterChanged.k2=1; } break; + case 1: // relative + if (chan[i].k2Offs!=chan[i].std.ex1.val) { + chan[i].k2Offs=chan[i].std.ex1.val; + chan[i].filterChanged.k2=1; + } + break; + /* case 2: { // delta const signed int next_k2=CLAMP(chan[i].k2Offs+chan[i].std.ex2.val,-65535,65535); if (chan[i].k2Offs!=next_k2) { @@ -504,6 +445,7 @@ void DivPlatformES5506::tick(bool sysTick) { } break; } + */ default: break; } @@ -621,13 +563,13 @@ void DivPlatformES5506::tick(bool sysTick) { if (chan[i].volChanged.changed) { if (!isMuted[i]) { // calculate volume (16 bit) if (chan[i].volChanged.lVol) { - chan[i].resLVol=(chan[i].outVol*chan[i].outLVol)/0xffff; + chan[i].resLVol=VOL_SCALE_LOG(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; + chan[i].resRVol=VOL_SCALE_LOG(chan[i].outVol,chan[i].outRVol,0xffff); if (!chan[i].keyOn) { pageWrite(0x00|i,0x04,chan[i].resRVol); } @@ -655,11 +597,11 @@ void DivPlatformES5506::tick(bool sysTick) { // get loop mode, transwave loop double loopStart=(double)s->loopStart; double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) { + DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; + if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { loopMode=transWaveInd.loopMode; - } else if ((chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; + } else if ((chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default + loopMode=DIV_SAMPLE_LOOP_PINGPONG; } // get loop position loopStart=(double)transWaveInd.loopStart; @@ -693,13 +635,13 @@ void DivPlatformES5506::tick(bool sysTick) { if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (next>=0 && next<120)) || ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (next>=0 && next<(int)ins->amiga.transWaveMap.size())) || ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (next>=0 && nextsong.sampleLen))) { - DivInstrumentAmiga::NoteMap& noteMapind=ins->amiga.noteMap[next]; + DivInstrumentAmiga::SampleMap& noteMapind=ins->amiga.noteMap[next]; DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[next]; int sample=next; if (ins->amiga.transWave.enable) { sample=transWaveInd.ind; } else if (ins->amiga.useNoteMap) { - sample=noteMapind.ind; + sample=noteMapind.map; } if (sample>=0 && samplesong.sampleLen) { sampleVaild=true; @@ -723,12 +665,12 @@ void DivPlatformES5506::tick(bool sysTick) { // get loop mode, transwave loop double loopStart=(double)s->loopStart; double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; + DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; if (ins->amiga.transWave.enable) { - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) { + if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { loopMode=transWaveInd.loopMode; - } else if ((chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; + } else if ((chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default + loopMode=DIV_SAMPLE_LOOP_PINGPONG; } // get loop position loopStart=(double)transWaveInd.loopStart; @@ -805,8 +747,8 @@ void DivPlatformES5506::tick(bool sysTick) { } if (chan[i].pcmChanged.position) { if (!chan[i].keyOn) { - pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.start:chan[i].pcm.loopStart); - pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.end:chan[i].pcm.loopEnd); + pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart); + pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd); } chan[i].pcmChanged.position=0; } @@ -815,17 +757,17 @@ void DivPlatformES5506::tick(bool sysTick) { unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.reversed?0x0040:0x0000); chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOPMODE_ONESHOT: // One shot (no loop) + case DIV_SAMPLE_LOOP_MAX: // One shot (no loop) default: break; - case DIV_SAMPLE_LOOPMODE_FORWARD: // Foward loop + case DIV_SAMPLE_LOOP_FORWARD: // Foward loop loopFlag|=0x0008; break; - case DIV_SAMPLE_LOOPMODE_BACKWARD: // Backward loop: IRQ enable + case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable loopFlag|=0x0038; chan[i].isReverseLoop=true; break; - case DIV_SAMPLE_LOOPMODE_PINGPONG: // Pingpong loop: Hardware support + case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support loopFlag|=0x0018; break; } @@ -844,14 +786,14 @@ 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!=1) { // Relative + if (chan[i].std.ex2.mode!=0) { // Relative k2=CLAMP(chan[i].filter.k2+chan[i].k2Offs,0,65535); } else { k2=chan[i].filter.k2; } } if (chan[i].filterChanged.k1) { - if (chan[i].std.ex1.mode!=1) { // Relative + if (chan[i].std.ex1.mode!=0) { // Relative k1=CLAMP(chan[i].filter.k1+chan[i].k1Offs,0,65535); } else { k1=chan[i].filter.k1; @@ -921,8 +863,8 @@ void DivPlatformES5506::tick(bool sysTick) { pageWrite(0x00|i,0x07,0xffff); // Set K1 and K2 to 0xffff pageWrite(0x00|i,0x09,0xffff,~0,(chanMax+1)*4*2); // needs to 4 sample period delay pageWrite(0x00|i,0x01,chan[i].freq); - pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.start:chan[i].pcm.loopStart); - pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT)?chan[i].pcm.end:chan[i].pcm.loopEnd); + pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart); + pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd); // initialize envelope pageWrite(0x00|i,0x03,((unsigned char)chan[i].envelope.lVRamp)<<8); pageWrite(0x00|i,0x05,((unsigned char)chan[i].envelope.rVRamp)<<8); @@ -930,14 +872,14 @@ 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!=1) && (chan[i].std.ex2.had)) { + if ((chan[i].std.ex2.mode!=0) && (chan[i].std.ex2.had)) { k2=CLAMP(chan[i].filter.k2+chan[i].k2Offs,0,65535); } else { k2=chan[i].filter.k2; } pageWrite(0x00|i,0x07,k2); chan[i].k2Prev=k2; - if ((chan[i].std.ex1.mode!=1) && (chan[i].std.ex1.had)) { + if ((chan[i].std.ex1.mode!=0) && (chan[i].std.ex1.had)) { k1=CLAMP(chan[i].filter.k1+chan[i].k1Offs,0,65535); } else { k1=chan[i].filter.k1; @@ -949,17 +891,17 @@ void DivPlatformES5506::tick(bool sysTick) { unsigned int loopFlag=chan[i].pcm.reversed?0x0040:0x0000; chan[i].isReverseLoop=false; switch (chan[i].pcm.loopMode) { - case DIV_SAMPLE_LOOPMODE_ONESHOT: // One shot (no loop) + case DIV_SAMPLE_LOOP_MAX: // One shot (no loop) default: break; - case DIV_SAMPLE_LOOPMODE_FORWARD: // Foward loop + case DIV_SAMPLE_LOOP_FORWARD: // Foward loop loopFlag|=0x0008; break; - case DIV_SAMPLE_LOOPMODE_BACKWARD: // Backward loop: IRQ enable + case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable loopFlag|=0x0038; chan[i].isReverseLoop=true; break; - case DIV_SAMPLE_LOOPMODE_PINGPONG: // Pingpong loop: Hardware support + case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support loopFlag|=0x0018; break; } @@ -1001,13 +943,13 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (((ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (c.value>=0 && c.value<120)) || ((!ins->amiga.useNoteMap && ins->amiga.transWave.enable) && (ins->amiga.transWave.ind>=0 && ins->amiga.transWave.ind<(int)ins->amiga.transWaveMap.size())) || ((!ins->amiga.useNoteMap && !ins->amiga.transWave.enable) && (ins->amiga.initSample>=0 && ins->amiga.initSamplesong.sampleLen))) { - DivInstrumentAmiga::NoteMap& noteMapind=ins->amiga.noteMap[c.value]; + DivInstrumentAmiga::SampleMap& noteMapind=ins->amiga.noteMap[c.value]; DivInstrumentAmiga::TransWaveMap& transWaveInd=ins->amiga.transWaveMap[ins->amiga.transWave.ind]; int sample=ins->amiga.initSample; if (ins->amiga.transWave.enable) { sample=transWaveInd.ind; } else if (ins->amiga.useNoteMap) { - sample=noteMapind.ind; + sample=noteMapind.map; } if (sample>=0 && samplesong.sampleLen) { sampleVaild=true; @@ -1033,12 +975,12 @@ int DivPlatformES5506::dispatch(DivCommand c) { // get loop mode, transwave loop double loopStart=(double)s->loopStart; double loopEnd=(double)s->loopEnd; - DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOPMODE_ONESHOT; + DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX; if (ins->amiga.transWave.enable) { - if (transWaveInd.loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) { + if (transWaveInd.loopMode!=DIV_SAMPLE_LOOP_MAX) { loopMode=transWaveInd.loopMode; - } else if ((chan[c.chan].pcm.loopMode==DIV_SAMPLE_LOOPMODE_ONESHOT) || (!s->isLoopable())) { // default - loopMode=DIV_SAMPLE_LOOPMODE_PINGPONG; + } else if ((chan[c.chan].pcm.loopMode==DIV_SAMPLE_LOOP_MAX) || (!s->isLoopable())) { // default + loopMode=DIV_SAMPLE_LOOP_PINGPONG; } // get loop position loopStart=(double)transWaveInd.loopStart; @@ -1093,10 +1035,10 @@ int DivPlatformES5506::dispatch(DivCommand c) { 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)/0xff; + chan[c.chan].outLVol=(0xffff*chan[c.chan].lVol)/0xff; } if (!chan[c.chan].std.panR.will) { - chan[c.chan].outRVol=(ins->es5506.rVol*chan[c.chan].rVol)/0xff; + chan[c.chan].outRVol=(0xffff*chan[c.chan].rVol)/0xff; } chan[c.chan].active=true; chan[c.chan].keyOn=true; @@ -1142,7 +1084,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (chan[c.chan].lVol!=(unsigned int)(c.value)) { chan[c.chan].lVol=c.value; if (!chan[c.chan].std.panL.has) { - chan[c.chan].outLVol=(ins->es5506.lVol*c.value)/0xff; + chan[c.chan].outLVol=(0xffff*c.value)/0xff; if (!isMuted[c.chan]) { chan[c.chan].volChanged.lVol=1; } @@ -1152,7 +1094,7 @@ int DivPlatformES5506::dispatch(DivCommand c) { if (chan[c.chan].rVol!=(unsigned int)(c.value2)) { chan[c.chan].rVol=c.value2; if (!chan[c.chan].std.panR.has) { - chan[c.chan].outRVol=(ins->es5506.rVol*c.value2)/0xff; + chan[c.chan].outRVol=(0xffff*c.value2)/0xff; if (!isMuted[c.chan]) { chan[c.chan].volChanged.rVol=1; } @@ -1336,6 +1278,8 @@ DivMacroInt* DivPlatformES5506::getChanMacroInt(int ch) { void DivPlatformES5506::reset() { while (!hostIntf32.empty()) hostIntf32.pop(); while (!hostIntf8.empty()) hostIntf8.pop(); + while (!queuedRead.empty()) queuedRead.pop(); + while (!queuedReadState.empty()) queuedReadState.pop(); for (int i=0; i<32; i++) { chan[i]=DivPlatformES5506::Channel(); chan[i].std.setEngine(parent); diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index 18b6a4c1..55f61751 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -27,7 +27,7 @@ #include #include "../macroInt.h" #include "../sample.h" -#include "sound/es550x/es5506.hpp" +#include "vgsound_emu/src/es550x/es5506.hpp" class DivPlatformES5506: public DivDispatch, public es550x_intf { struct Channel { @@ -60,7 +60,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { length(0), loopStart(0), loopEnd(0), - loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {} + loopMode(DIV_SAMPLE_LOOP_MAX) {} } pcm; int freq, baseFreq, nextFreq, pitch, pitch2, note, nextNote, currNote, ins, wave; unsigned int volMacroMax, panMacroMax; @@ -213,6 +213,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { signed short* sampleMem; // ES5506 uses 16 bit data bus for samples size_t sampleMemLen; struct QueuedHostIntf { + unsigned char state; unsigned char step; unsigned char addr; unsigned int val; @@ -221,6 +222,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { unsigned short delay; bool isRead; QueuedHostIntf(unsigned char s, unsigned char a, unsigned int v, unsigned int m=(unsigned int)(~0), unsigned short d=0): + state(0), step(s), addr(a), val(v), @@ -228,7 +230,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { read(NULL), delay(0), isRead(false) {} - QueuedHostIntf(unsigned char s, unsigned char a, unsigned int* r, unsigned int m=(unsigned int)(~0), unsigned short d=0): + QueuedHostIntf(unsigned char st, unsigned char s, unsigned char a, unsigned int* r, unsigned int m=(unsigned int)(~0), unsigned short d=0): + state(st), step(s), addr(a), val(0), @@ -237,8 +240,17 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { delay(d), isRead(true) {} }; + struct QueuedReadState { + unsigned int* read; + unsigned char state; + QueuedReadState(unsigned int* r, unsigned char s): + read(r), + state(s) {} + }; std::queue hostIntf32; std::queue hostIntf8; + std::queue queuedRead; + std::queue queuedReadState; int cycle, curPage; unsigned char maskedVal; unsigned int irqv; @@ -288,7 +300,6 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { virtual size_t getSampleMemUsage(int index = 0) override; virtual void renderSamples() override; virtual const char** getRegisterSheet() override; - virtual const char* getEffectName(unsigned char effect) override; virtual int init(DivEngine* parent, int channels, int sugRate, unsigned int flags) override; virtual void quit() override; DivPlatformES5506(): diff --git a/src/engine/platform/sound/es550x/es5504.cpp b/src/engine/platform/sound/es550x/es5504.cpp deleted file mode 100644 index c2644fbd..00000000 --- a/src/engine/platform/sound/es550x/es5504.cpp +++ /dev/null @@ -1,453 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504 emulation core - - see es550x.cpp for more info -*/ - -#include "es5504.hpp" - -// Internal functions -void es5504_core::tick() -{ - m_voice_update = false; - m_voice_end = false; - // /CAS, E - if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock - { - // /CAS - if (m_cas.tick()) - { - // /CAS high, E low: get sample address - if (m_cas.falling_edge()) - { - // /CAS low, E low: fetch sample - if (!m_e.current_edge()) - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - } - // E - if (m_clkin.falling_edge()) // falling edge triggers E clock - { - if (m_e.tick()) - { - m_intf.e_pin(m_e.current_edge()); - if (m_e.rising_edge()) // Host access - { - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - voice_tick(); - } - if (m_e.falling_edge()) // Voice memory - { - m_host_intf.m_host_access = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - } - if (m_e.current_edge()) // Host interface - { - if (m_host_intf.m_host_access) - { - if (m_host_intf.m_rw && (m_e.cycle() == 2)) // Read - { - m_hd = read(m_ha); - m_host_intf.m_host_access = false; - } - else if ((!m_host_intf.m_rw) && (m_e.cycle() == 2)) // Write - write(m_ha, m_hd); - } - } - else if (!m_e.current_edge()) - { - if (m_e.cycle() == 2) - { - // reset host access state - m_hd = 0; - m_host_intf.m_host_access_strobe = false; - } - } - } - } -} - -// less cycle accurate, but less CPU heavy routine -void es5504_core::tick_perf() -{ - m_voice_update = false; - m_voice_end = false; - // update - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; -} - -void es5504_core::voice_tick() -{ - // Voice updates every 2 E clock cycle (= 1 CHSTRB cycle or 4 BCLK clock cycle) - m_voice_update = bitfield(m_voice_fetch++, 0); - if (m_voice_update) - { - // Update voice - m_voice[m_voice_cycle].tick(m_voice_cycle); - - // Refresh output (Multiplexed analog output) - m_ch[m_voice[m_voice_cycle].m_cr.ca] = m_voice[m_voice_cycle].m_ch; - - if ((++m_voice_cycle) > std::min(24, m_active)) // ~ 25 voices - { - m_voice_end = true; - m_voice_cycle = 0; - } - - m_voice_fetch = 0; - } -} - -void es5504_core::voice_t::fetch(u8 voice, u8 cycle) -{ - m_alu.m_sample[cycle] = m_host.m_intf.read_sample(voice, bitfield(m_cr.ca, 0, 3), bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer)); -} - -void es5504_core::voice_t::tick(u8 voice) -{ - m_ch = 0; - - // Filter execute - m_filter.tick(m_alu.interpolation()); - - if (m_alu.busy()) - { - // Send to output - m_ch = ((sign_ext(m_filter.m_o4_1, 16) >> 3) * m_volume) >> 12; // Analog multiplied in real chip, 13/12 bit ladder DAC - - // ALU execute - if (m_alu.tick()) - { - m_alu.loop_exec(); - } - - // ADC check - adc_exec(); - } - - // Update IRQ - m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); -} - -// ADC; Correct? -void es5504_core::voice_t::adc_exec() -{ - if (m_cr.adc) - m_host.m_adc = m_host.m_intf.adc_r() & ~0x7; -} - -void es5504_core::reset() -{ - es550x_shared_core::reset(); - for (auto & elem : m_voice) - elem.reset(); - - m_adc = 0; - std::fill(std::begin(m_ch), std::end(m_ch), 0); -} - -void es5504_core::voice_t::reset() -{ - es550x_shared_core::es550x_voice_t::reset(); - m_volume = 0; - m_ch = 0; -} - -// Accessors -u16 es5504_core::host_r(u8 address) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - if (m_e.rising_edge()) // update directly - m_hd = read(m_ha, true); - else - { - m_host_intf.m_rw_strobe = true; - m_host_intf.m_host_access_strobe = true; - } - } - return m_hd; -} - -void es5504_core::host_w(u8 address, u16 data) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - m_hd = data; - if (m_e.rising_edge()) // update directly - write(m_ha, m_hd, true); - else - { - m_host_intf.m_rw_strobe = false; - m_host_intf.m_host_access_strobe = true; - } - } -} - -u16 es5504_core::read(u8 address, bool cpu_access) -{ - return regs_r(m_page, address, cpu_access); -} - -void es5504_core::write(u8 address, u16 data, bool cpu_access) -{ - regs_w(m_page, address, data, cpu_access); -} - -u16 es5504_core::regs_r(u8 page, u8 address, bool cpu_access) -{ - u16 ret = 0xffff; - address = bitfield(address, 0, 4); // 4 bit address for CPU access - - if (address >= 12) // Global registers - { - switch (address) - { - case 12: // A/D (A to D Convert/Test) - ret = (ret & ~0xfffb) | (m_adc & 0xfffb); - break; - case 13: // ACT (Number of voices) - ret = (ret & ~0x1f) | bitfield(m_active, 0, 5); - break; - case 14: // IRQV (Interrupting voice vector) - ret = (ret & ~0x9f) | (m_irqv.irqb ? 0x80 : 0) | bitfield(m_irqv.voice, 0, 5); - if (cpu_access) - { - m_irqv.clear(); - if (bitfield(ret, 7) != m_irqv.irqb) - m_voice[m_irqv.voice].m_alu.irq_update(m_intf, m_irqv); - } - break; - case 15: // PAGE (Page select register) - ret = (ret & ~0x3f) | bitfield(m_page, 0, 6); - break; - } - } - else // Voice specific registers - { - const u8 voice = bitfield(page, 0, 5); // Voice select - if (voice < 25) - { - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 56 - { - switch (address) - { - case 1: // O4(n-1) (Filter 4 Temp Register) - ret = v.m_filter.m_o4_1; - break; - case 2: // O3(n-2) (Filter 3 Temp Register #2) - ret = v.m_filter.m_o3_2; - break; - case 3: // O3(n-1) (Filter 3 Temp Register #1) - ret = v.m_filter.m_o3_1; - break; - case 4: // O2(n-2) (Filter 2 Temp Register #2) - ret = v.m_filter.m_o2_2; - break; - case 5: // O2(n-1) (Filter 2 Temp Register #1) - ret = v.m_filter.m_o2_1; - break; - case 6: // O1(n-1) (Filter 1 Temp Register) - ret = v.m_filter.m_o1_1; - break; - } - } - else // Page 0 - 24 - { - switch (address) - { - case 0: // CR (Control Register) - ret = (ret & ~0xff) | - (v.m_alu.m_cr.stop0 ? 0x01 : 0x00) - | (v.m_alu.m_cr.stop1 ? 0x02 : 0x00) - | (v.m_cr.adc ? 0x04 : 0x00) - | (v.m_alu.m_cr.lpe ? 0x08 : 0x00) - | (v.m_alu.m_cr.ble ? 0x10 : 0x00) - | (v.m_alu.m_cr.irqe ? 0x20 : 0x00) - | (v.m_alu.m_cr.dir ? 0x40 : 0x00) - | (v.m_alu.m_cr.irq ? 0x80 : 0x00); - break; - case 1: // FC (Frequency Control) - ret = (ret & ~0xfffe) | (v.m_alu.m_fc << 1); - break; - case 2: // STRT-H (Loop Start Register High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_start, 16, 13); - break; - case 3: // STRT-L (Loop Start Register Low) - ret = (ret & ~0xffe0) | (v.m_alu.m_start & 0xffe0); - break; - case 4: // END-H (Loop End Register High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_end, 16, 13); - break; - case 5: // END-L (Loop End Register Low) - ret = (ret & ~0xffe0) | (v.m_alu.m_end & 0xffe0); - break; - case 6: // K2 (Filter Cutoff Coefficient #2) - ret = (ret & ~0xfff0) | (v.m_filter.m_k2 & 0xfff0); - break; - case 7: // K1 (Filter Cutoff Coefficient #1) - ret = (ret & ~0xfff0) | (v.m_filter.m_k1 & 0xfff0); - break; - case 8: // Volume - ret = (ret & ~0xfff0) | ((v.m_volume << 4) & 0xfff0); - break; - case 9: // CA (Filter Config, Channel Assign) - ret = (ret & ~0x3f) | - bitfield(v.m_cr.ca, 0, 4) - | (bitfield(v.m_filter.m_lp, 0, 2) << 4); - break; - case 10: // ACCH (Accumulator High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_accum, 16, 13); - break; - case 11: // ACCL (Accumulator Low) - ret = bitfield(v.m_alu.m_accum, 0, 16); - break; - } - } - } - } - - return ret; -} - -void es5504_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) -{ - address = bitfield(address, 0, 4); // 4 bit address for CPU access - - if (address >= 12) // Global registers - { - switch (address) - { - case 12: // A/D (A to D Convert/Test) - if (bitfield(m_adc, 0)) // Writable ADC - { - m_adc = (m_adc & 7) | (data & ~7); - m_intf.adc_w(m_adc & ~7); - } - m_adc = (m_adc & ~3) | (data & 3); - break; - case 13: // ACT (Number of voices) - m_active = std::min(24, bitfield(data, 0, 5)); - break; - case 14: // IRQV (Interrupting voice vector) - // Read only - break; - case 15: // PAGE (Page select register) - m_page = bitfield(data, 0, 6); - break; - } - } - else // Voice specific registers - { - const u8 voice = bitfield(page, 0, 5); // Voice select - if (voice < 25) - { - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 56 - { - switch (address) - { - case 1: // O4(n-1) (Filter 4 Temp Register) - v.m_filter.m_o4_1 = sign_ext(data, 16); - break; - case 2: // O3(n-2) (Filter 3 Temp Register #2) - v.m_filter.m_o3_2 = sign_ext(data, 16); - break; - case 3: // O3(n-1) (Filter 3 Temp Register #1) - v.m_filter.m_o3_1 = sign_ext(data, 16); - break; - case 4: // O2(n-2) (Filter 2 Temp Register #2) - v.m_filter.m_o2_2 = sign_ext(data, 16); - break; - case 5: // O2(n-1) (Filter 2 Temp Register #1) - v.m_filter.m_o2_1 = sign_ext(data, 16); - break; - case 6: // O1(n-1) (Filter 1 Temp Register) - v.m_filter.m_o1_1 = sign_ext(data, 16); - break; - } - } - else // Page 0 - 24 - { - switch (address) - { - case 0: // CR (Control Register) - v.m_alu.m_cr.stop0 = bitfield(data, 0); - v.m_alu.m_cr.stop1 = bitfield(data, 1); - v.m_cr.adc = bitfield(data, 2); - v.m_alu.m_cr.lpe = bitfield(data, 3); - v.m_alu.m_cr.ble = bitfield(data, 4); - v.m_alu.m_cr.irqe = bitfield(data, 5); - v.m_alu.m_cr.dir = bitfield(data, 6); - v.m_alu.m_cr.irq = bitfield(data, 7); - break; - case 1: // FC (Frequency Control) - v.m_alu.m_fc = bitfield(data, 1, 15); - break; - case 2: // STRT-H (Loop Start Register High) - v.m_alu.m_start = (v.m_alu.m_start & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 3: // STRT-L (Loop Start Register Low) - v.m_alu.m_start = (v.m_alu.m_start & ~0xffe0) | (data & 0xffe0); - break; - case 4: // END-H (Loop End Register High) - v.m_alu.m_end = (v.m_alu.m_end & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 5: // END-L (Loop End Register Low) - v.m_alu.m_end = (v.m_alu.m_end & ~0xffe0) | (data & 0xffe0); - break; - case 6: // K2 (Filter Cutoff Coefficient #2) - v.m_filter.m_k2 = data & 0xfff0; - break; - case 7: // K1 (Filter Cutoff Coefficient #1) - v.m_filter.m_k1 = data & 0xfff0; - break; - case 8: // Volume - v.m_volume = bitfield(data, 4, 12); - break; - case 9: // CA (Filter Config, Channel Assign) - v.m_cr.ca = bitfield(data, 0, 4); - v.m_filter.m_lp = bitfield(data, 4, 2); - break; - case 10: // ACCH (Accumulator High) - v.m_alu.m_accum = (v.m_alu.m_accum & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 11: // ACCL (Accumulator Low) - v.m_alu.m_accum = (v.m_alu.m_accum & ~0xffff) | data; - break; - } - } - } - } -} diff --git a/src/engine/platform/sound/es550x/es5504.hpp b/src/engine/platform/sound/es550x/es5504.hpp deleted file mode 100644 index be6e44d1..00000000 --- a/src/engine/platform/sound/es550x/es5504.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504 emulation core - - See es550x.cpp for more info -*/ - -#include "es550x.hpp" - -#ifndef _VGSOUND_EMU_ES5504_HPP -#define _VGSOUND_EMU_ES5504_HPP - -#pragma once - -// ES5504 specific -class es5504_core : public es550x_shared_core -{ -public: - // constructor - es5504_core(es550x_intf &intf) - : es550x_shared_core(intf) - , m_voice{*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this, - *this,*this,*this,*this,*this, - *this,*this,*this,*this,*this, - *this,*this,*this,*this,*this} - { - } - // host interface - u16 host_r(u8 address); - void host_w(u8 address, u16 data); - - // internal state - virtual void reset() override; - virtual void tick() override; - - // less cycle accurate, but also less cpu heavy update routine - void tick_perf(); - - // 16 analog output channels - s32 out(u8 ch) { return m_ch[ch & 0xf]; } - -//----------------------------------------------------------------- -// -// for preview/debug purpose only, not for serious emulators -// -//----------------------------------------------------------------- - - // bypass chips host interface for debug purpose only - u16 read(u8 address, bool cpu_access = false); - void write(u8 address, u16 data, bool cpu_access = false); - - u16 regs_r(u8 page, u8 address, bool cpu_access = false); - void regs_w(u8 page, u8 address, u16 data, bool cpu_access = false); - - u16 regs_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u16 ret = read(address, false); m_page = prev; return ret; } - - // per-voice outputs - s32 voice_out(u8 voice) { return (voice < 25) ? m_voice[voice].m_ch : 0; } - -protected: - virtual inline u8 max_voices() override { return 25; } - virtual void voice_tick() override; - -private: - // es5504 voice structs - struct voice_t : es550x_voice_t - { - // constructor - voice_t(es5504_core &host) - : es550x_voice_t(20, 9, false) - , m_host(host) - {} - - // internal state - virtual void reset() override; - virtual void fetch(u8 voice, u8 cycle) override; - virtual void tick(u8 voice) override; - - void adc_exec(); - - // registers - es5504_core &m_host; - u16 m_volume = 0; // 12 bit Volume - s32 m_ch = 0; // channel outputs - }; - - voice_t m_voice[25]; // 25 voices - u16 m_adc = 0; // ADC register - s32 m_ch[16] = {0}; // 16 channel outputs -}; - -#endif diff --git a/src/engine/platform/sound/es550x/es5505.cpp b/src/engine/platform/sound/es550x/es5505.cpp deleted file mode 100644 index fae6b393..00000000 --- a/src/engine/platform/sound/es550x/es5505.cpp +++ /dev/null @@ -1,606 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5505 emulation core - - see es550x.cpp for more info -*/ - -#include "es5505.hpp" - -// Internal functions -void es5505_core::tick() -{ - m_voice_update = false; - m_voice_end = false; - // CLKIN - if (m_clkin.tick()) - { - // SERBCLK - if (m_clkin.m_edge.m_changed) // BCLK is freely running clock - { - if (m_bclk.tick()) - { - m_intf.bclk(m_bclk.current_edge()); - // Serial output - if (m_bclk.falling_edge()) - { - // SERLRCLK - if (m_lrclk.tick()) - m_intf.lrclk(m_lrclk.current_edge()); - } - // SERWCLK - if (m_lrclk.m_edge.m_changed) - m_wclk = 0; - if (m_bclk.falling_edge()) - { - if (m_wclk == ((m_sermode.sony_bb) ? 1 : 0)) - { - if (m_lrclk.current_edge()) - { - for (int i = 0; i < 4; i++) - { - // copy output - m_output[i] = m_output_temp[i]; - m_output_latch[i] = m_ch[i]; - m_output_temp[i].reset(); - // clamp to 16 bit (upper 5 bits are overflow guard bits) - m_output_latch[i].m_left = clamp(m_output_latch[i].m_left, -0x8000, 0x7fff); - m_output_latch[i].m_right = clamp(m_output_latch[i].m_right, -0x8000, 0x7fff); - // set signed - if (m_output_latch[i].m_left < 0) - m_output_temp[i].m_left = -1; - if (m_output_latch[i].m_right < 0) - m_output_temp[i].m_right = -1; - } - } - m_wclk_lr = m_lrclk.current_edge(); - m_output_bit = 16; - } - s8 output_bit = --m_output_bit; - if (m_output_bit >= 0) - { - for (int i = 0; i < 4; i++) - { - if (m_wclk_lr) // Right output - m_output_temp[i].m_right = (m_output_temp[i].m_right << 1) | bitfield(m_output_latch[i].m_right, output_bit); - else // Left output - m_output_temp[i].m_left = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_left, output_bit); - } - } - m_wclk++; - } - } - } - // /CAS, E - if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock - { - // /CAS - if (m_cas.tick()) - { - // /CAS high, E low: get sample address - if (m_cas.falling_edge()) - { - // /CAS low, E low: fetch sample - if (!m_e.current_edge()) - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - } - // E - if (m_e.tick()) - { - m_intf.e_pin(m_e.current_edge()); - if (m_e.rising_edge()) // Host access - { - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - voice_tick(); - } - else if (m_e.falling_edge()) // Voice memory - { - m_host_intf.m_host_access = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - if (m_e.current_edge()) // Host interface - { - if (m_host_intf.m_host_access) - { - if (m_host_intf.m_rw && (m_e.cycle() == 2)) // Read - { - m_hd = read(m_ha); - m_host_intf.m_host_access = false; - } - else if ((!m_host_intf.m_rw) && (m_e.cycle() == 2)) // Write - write(m_ha, m_hd); - } - } - else if (!m_e.current_edge()) - { - if (m_e.cycle() == 2) - { - // reset host access state - m_hd = 0; - m_host_intf.m_host_access_strobe = false; - } - } - } - } - } -} - -// less cycle accurate, but less CPU heavy routine -void es5505_core::tick_perf() -{ - m_voice_update = false; - m_voice_end = false; - // output - for (int c = 0; c < 4; c++) - { - m_output[c].m_left = clamp(m_ch[c].m_left, -0x8000, 0x7fff); - m_output[c].m_right = clamp(m_ch[c].m_right, -0x8000, 0x7fff); - } - - // update - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; -} - -void es5505_core::voice_tick() -{ - // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) - m_voice_update = bitfield(m_voice_fetch++, 0); - if (m_voice_update) - { - // Update voice - m_voice[m_voice_cycle].tick(m_voice_cycle); - - // Refresh output - if ((++m_voice_cycle) > clamp(m_active, 7, 31)) // 8 ~ 32 voices - { - m_voice_end = true; - m_voice_cycle = 0; - for (auto & elem : m_ch) - elem.reset(); - - for (auto & elem : m_voice) - { - m_ch[bitfield(elem.m_cr.ca, 0, 2)].m_left += elem.m_ch.m_left; - m_ch[bitfield(elem.m_cr.ca, 0, 2)].m_right += elem.m_ch.m_right; - elem.m_ch.reset(); - } - } - m_voice_fetch = 0; - } -} - -void es5505_core::voice_t::fetch(u8 voice, u8 cycle) -{ - m_alu.m_sample[cycle] = m_host.m_intf.read_sample(voice, bitfield(m_cr.bs, 0), bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer)); -} - -void es5505_core::voice_t::tick(u8 voice) -{ - m_ch.reset(); - - // Filter execute - m_filter.tick(m_alu.interpolation()); - - if (m_alu.busy()) - { - // Send to output - m_ch.m_left = volume_calc(m_lvol, sign_ext(m_filter.m_o4_1, 16)); - m_ch.m_right = volume_calc(m_rvol, sign_ext(m_filter.m_o4_1, 16)); - - // ALU execute - if (m_alu.tick()) - m_alu.loop_exec(); - } - - // Update IRQ - m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); -} - -// volume calculation -s32 es5505_core::voice_t::volume_calc(u8 volume, s32 in) -{ - u8 exponent = bitfield(volume, 4, 4); - u8 mantissa = bitfield(volume, 0, 4); - return exponent ? (in * s32(0x10 | mantissa)) >> (20 - exponent) : 0; -} - -void es5505_core::reset() -{ - es550x_shared_core::reset(); - for (auto & elem : m_voice) - elem.reset(); - - m_sermode.reset(); - m_bclk.reset(); - m_lrclk.reset(); - m_wclk = 0; - m_wclk_lr = false; - m_output_bit = 0; - for (auto & elem : m_ch) - elem.reset(); - for (auto & elem : m_output) - elem.reset(); - for (auto & elem : m_output_temp) - elem.reset(); - for (auto & elem : m_output_latch) - elem.reset(); -} - -void es5505_core::voice_t::reset() -{ - es550x_shared_core::es550x_voice_t::reset(); - m_lvol = 0; - m_rvol = 0; - m_ch.reset(); -} - -// Accessors -u16 es5505_core::host_r(u8 address) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - if (m_e.rising_edge()) // update directly - m_hd = read(m_ha, true); - else - { - m_host_intf.m_rw_strobe = true; - m_host_intf.m_host_access_strobe = true; - } - } - return m_hd; -} - -void es5505_core::host_w(u8 address, u16 data) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - m_hd = data; - if (m_e.rising_edge()) // update directly - write(m_ha, m_hd, true); - else - { - m_host_intf.m_rw_strobe = false; - m_host_intf.m_host_access_strobe = true; - } - } -} - -u16 es5505_core::read(u8 address, bool cpu_access) -{ - return regs_r(m_page, address, cpu_access); -} - -void es5505_core::write(u8 address, u16 data, bool cpu_access) -{ - regs_w(m_page, address, data, cpu_access); -} - -u16 es5505_core::regs_r(u8 page, u8 address, bool cpu_access) -{ - u16 ret = 0xffff; - address = bitfield(address, 0, 4); // 4 bit address for CPU access - - if (address >= 13) // Global registers - { - switch (address) - { - case 13: // ACT (Number of voices) - ret = (ret & ~0x1f) | bitfield(m_active, 0, 5); - break; - case 14: // IRQV (Interrupting voice vector) - ret = (ret & ~0x9f) | (m_irqv.irqb ? 0x80 : 0) | bitfield(m_irqv.voice, 0, 5); - if (cpu_access) - { - m_irqv.clear(); - if (bitfield(ret, 7) != m_irqv.irqb) - m_voice[m_irqv.voice].m_alu.irq_update(m_intf, m_irqv); - } - break; - case 15: // PAGE (Page select register) - ret = (ret & ~0x7f) | bitfield(m_page, 0, 7); - break; - } - } - else - { - if (bitfield(page, 6)) // Channel registers - { - switch (address) - { - case 0: // CH0L (Channel 0 Left) - case 2: // CH1L (Channel 1 Left) - case 4: // CH2L (Channel 2 Left) - if (!cpu_access) // CPU can't read here - ret = m_ch[bitfield(address, 0, 2)].m_left; - break; - case 1: // CH0R (Channel 0 Right) - case 3: // CH1R (Channel 1 Right) - case 5: // CH2R (Channel 2 Right) - if (!cpu_access) // CPU can't read here - ret = m_ch[bitfield(address, 0, 2)].m_right; - break; - case 6: // CH3L (Channel 3 Left) - if ((!cpu_access) || m_sermode.adc) - ret = m_ch[3].m_left; - break; - case 7: // CH3R (Channel 3 Right) - if ((!cpu_access) || m_sermode.adc) - ret = m_ch[3].m_right; - break; - case 8: // SERMODE (Serial Mode) - ret = (ret & ~0xf807) | - (m_sermode.adc ? 0x01 : 0x00) - | (m_sermode.test ? 0x02 : 0x00) - | (m_sermode.sony_bb ? 0x04 : 0x00) - | (bitfield(m_sermode.msb, 0, 5) << 11); - break; - case 9: // PAR (Port A/D Register) - ret = (ret & ~0x3f) | (m_intf.adc_r() & ~0x3f); - break; - } - } - else // Voice specific registers - { - const u8 voice = bitfield(page, 0, 5); // Voice select - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 63 - { - switch (address) - { - case 1: // O4(n-1) (Filter 4 Temp Register) - ret = v.m_filter.m_o4_1; - break; - case 2: // O3(n-2) (Filter 3 Temp Register #2) - ret = v.m_filter.m_o3_2; - break; - case 3: // O3(n-1) (Filter 3 Temp Register #1) - ret = v.m_filter.m_o3_1; - break; - case 4: // O2(n-2) (Filter 2 Temp Register #2) - ret = v.m_filter.m_o2_2; - break; - case 5: // O2(n-1) (Filter 2 Temp Register #1) - ret = v.m_filter.m_o2_1; - break; - case 6: // O1(n-1) (Filter 1 Temp Register) - ret = v.m_filter.m_o1_1; - break; - } - } - else // Page 0 - 31 - { - switch (address) - { - case 0: // CR (Control Register) - ret = (ret & ~0xfff) | - (v.m_alu.m_cr.stop0 ? 0x01 : 0x00) - | (v.m_alu.m_cr.stop1 ? 0x02 : 0x00) - | (bitfield(v.m_cr.bs, 0) ? 0x04 : 0x00) - | (v.m_alu.m_cr.lpe ? 0x08 : 0x00) - | (v.m_alu.m_cr.ble ? 0x10 : 0x00) - | (v.m_alu.m_cr.irqe ? 0x20 : 0x00) - | (v.m_alu.m_cr.dir ? 0x40 : 0x00) - | (v.m_alu.m_cr.irq ? 0x80 : 0x00) - | (bitfield(v.m_cr.ca, 0, 2) << 8) - | (bitfield(v.m_filter.m_lp, 0, 2) << 10); - break; - case 1: // FC (Frequency Control) - ret = (ret & ~0xfffe) | (bitfield(v.m_alu.m_fc, 0, 15) << 1); - break; - case 2: // STRT-H (Loop Start Register High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_start, 16, 13); - break; - case 3: // STRT-L (Loop Start Register Low) - ret = (ret & ~0xffe0) | (v.m_alu.m_start & 0xffe0); - break; - case 4: // END-H (Loop End Register High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_end, 16, 13); - break; - case 5: // END-L (Loop End Register Low) - ret = (ret & ~0xffe0) | (v.m_alu.m_end & 0xffe0); - break; - case 6: // K2 (Filter Cutoff Coefficient #2) - ret = (ret & ~0xfff0) | (v.m_filter.m_k2 & 0xfff0); - break; - case 7: // K1 (Filter Cutoff Coefficient #1) - ret = (ret & ~0xfff0) | (v.m_filter.m_k1 & 0xfff0); - break; - case 8: // LVOL (Left Volume) - ret = (ret & ~0xff00) | ((v.m_lvol << 8) & 0xff00); - break; - case 9: // RVOL (Right Volume) - ret = (ret & ~0xff00) | ((v.m_rvol << 8) & 0xff00); - break; - case 10: // ACCH (Accumulator High) - ret = (ret & ~0x1fff) | bitfield(v.m_alu.m_accum, 16, 13); - break; - case 11: // ACCL (Accumulator Low) - ret = bitfield(v.m_alu.m_accum, 0, 16); - break; - } - } - } - } - - return ret; -} - -void es5505_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access) -{ - address = bitfield(address, 0, 4); // 4 bit address for CPU access - - if (address >= 12) // Global registers - { - switch (address) - { - case 13: // ACT (Number of voices) - m_active = std::max(7, bitfield(data, 0, 5)); - break; - case 14: // IRQV (Interrupting voice vector) - // Read only - break; - case 15: // PAGE (Page select register) - m_page = bitfield(data, 0, 7); - break; - } - } - else // Voice specific registers - { - if (bitfield(page, 6)) // Channel registers - { - switch (address) - { - case 0: // CH0L (Channel 0 Left) - if (m_sermode.test) - m_ch[0].m_left = data; - break; - case 1: // CH0R (Channel 0 Right) - if (m_sermode.test) - m_ch[0].m_right = data; - break; - case 2: // CH1L (Channel 1 Left) - if (m_sermode.test) - m_ch[1].m_left = data; - break; - case 3: // CH1R (Channel 1 Right) - if (m_sermode.test) - m_ch[1].m_right = data; - break; - case 4: // CH2L (Channel 2 Left) - if (m_sermode.test) - m_ch[2].m_left = data; - break; - case 5: // CH2R (Channel 2 Right) - if (m_sermode.test) - m_ch[2].m_right = data; - break; - case 6: // CH3L (Channel 3 Left) - if (m_sermode.test) - m_ch[3].m_left = data; - break; - case 7: // CH3R (Channel 3 Right) - if (m_sermode.test) - m_ch[3].m_right = data; - break; - case 8: // SERMODE (Serial Mode) - m_sermode.adc = bitfield(data, 0); - m_sermode.test = bitfield(data, 1); - m_sermode.sony_bb = bitfield(data, 2); - m_sermode.msb = bitfield(data, 11, 5); - break; - case 9: // PAR (Port A/D Register) - // Read only - break; - } - } - else // Voice specific registers - { - const u8 voice = bitfield(page, 0, 5); // Voice select - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 56 - { - switch (address) - { - case 1: // O4(n-1) (Filter 4 Temp Register) - v.m_filter.m_o4_1 = sign_ext(data, 16); - break; - case 2: // O3(n-2) (Filter 3 Temp Register #2) - v.m_filter.m_o3_2 = sign_ext(data, 16); - break; - case 3: // O3(n-1) (Filter 3 Temp Register #1) - v.m_filter.m_o3_1 = sign_ext(data, 16); - break; - case 4: // O2(n-2) (Filter 2 Temp Register #2) - v.m_filter.m_o2_2 = sign_ext(data, 16); - break; - case 5: // O2(n-1) (Filter 2 Temp Register #1) - v.m_filter.m_o2_1 = sign_ext(data, 16); - break; - case 6: // O1(n-1) (Filter 1 Temp Register) - v.m_filter.m_o1_1 = sign_ext(data, 16); - break; - } - } - else // Page 0 - 24 - { - switch (address) - { - case 0: // CR (Control Register) - v.m_alu.m_cr.stop0 = bitfield(data, 0); - v.m_alu.m_cr.stop1 = bitfield(data, 1); - v.m_cr.bs = bitfield(data, 2); - v.m_alu.m_cr.lpe = bitfield(data, 3); - v.m_alu.m_cr.ble = bitfield(data, 4); - v.m_alu.m_cr.irqe = bitfield(data, 5); - v.m_alu.m_cr.dir = bitfield(data, 6); - v.m_alu.m_cr.irq = bitfield(data, 7); - v.m_cr.ca = bitfield(data, 8, 2); - v.m_filter.m_lp = bitfield(data, 10, 2); - break; - case 1: // FC (Frequency Control) - v.m_alu.m_fc = bitfield(data, 1, 15); - break; - case 2: // STRT-H (Loop Start Register High) - v.m_alu.m_start = (v.m_alu.m_start & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 3: // STRT-L (Loop Start Register Low) - v.m_alu.m_start = (v.m_alu.m_start & ~0xffe0) | (data & 0xffe0); - break; - case 4: // END-H (Loop End Register High) - v.m_alu.m_end = (v.m_alu.m_end & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 5: // END-L (Loop End Register Low) - v.m_alu.m_end = (v.m_alu.m_end & ~0xffe0) | (data & 0xffe0); - break; - case 6: // K2 (Filter Cutoff Coefficient #2) - v.m_filter.m_k2 = data & 0xfff0; - break; - case 7: // K1 (Filter Cutoff Coefficient #1) - v.m_filter.m_k1 = data & 0xfff0; - break; - case 8: // LVOL (Left Volume) - v.m_lvol = bitfield(data, 8, 8); - break; - case 9: // RVOL (Right Volume) - v.m_rvol = bitfield(data, 8, 8); - break; - case 10: // ACCH (Accumulator High) - v.m_alu.m_accum = (v.m_alu.m_accum & ~0x1fff0000) | (bitfield(data, 0, 13) << 16); - break; - case 11: // ACCL (Accumulator Low) - v.m_alu.m_accum = (v.m_alu.m_accum & ~0xffff) | data; - break; - } - } - } - } -} diff --git a/src/engine/platform/sound/es550x/es5505.hpp b/src/engine/platform/sound/es550x/es5505.hpp deleted file mode 100644 index 6498ddff..00000000 --- a/src/engine/platform/sound/es550x/es5505.hpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504 emulation core - - See es550x.cpp for more info -*/ - -#include "es550x.hpp" - -#ifndef _VGSOUND_EMU_ES5505_HPP -#define _VGSOUND_EMU_ES5505_HPP - -#pragma once - -// ES5505 specific -class es5505_core : public es550x_shared_core -{ -public: - // constructor - es5505_core(es550x_intf &intf) - : es550x_shared_core(intf) - , m_voice{*this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this} - { - } - // host interface - u16 host_r(u8 address); - void host_w(u8 address, u16 data); - - // internal state - virtual void reset() override; - virtual void tick() override; - - // less cycle accurate, but also less cpu heavy update routine - void tick_perf(); - - // clock outputs - bool bclk() { return m_bclk.current_edge(); } - bool bclk_rising_edge() { return m_bclk.rising_edge(); } - bool bclk_falling_edge() { return m_bclk.falling_edge(); } - - // Input mode for Channel 3 - void lin(s32 in) { if (m_sermode.adc) { m_ch[3].m_left = in; } } - void rin(s32 in) { if (m_sermode.adc) { m_ch[3].m_right = in; } } - - // 4 stereo output channels - s32 lout(u8 ch) { return m_ch[ch & 0x3].m_left; } - s32 rout(u8 ch) { return m_ch[ch & 0x3].m_right; } - -//----------------------------------------------------------------- -// -// for preview/debug purpose only, not for serious emulators -// -//----------------------------------------------------------------- - - // bypass chips host interface for debug purpose only - u16 read(u8 address, bool cpu_access = false); - void write(u8 address, u16 data, bool cpu_access = false); - - u16 regs_r(u8 page, u8 address, bool cpu_access = false); - void regs_w(u8 page, u8 address, u16 data, bool cpu_access = false); - - u16 regs_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u16 ret = read(address, false); m_page = prev; return ret; } - - // per-voice outputs - s32 voice_lout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_left : 0; } - s32 voice_rout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_right : 0; } - -protected: - virtual inline u8 max_voices() override { return 32; } - virtual void voice_tick() override; - -private: - struct output_t - { - void reset() - { - m_left = 0; - m_right = 0; - }; - - s32 m_left = 0; - s32 m_right = 0; - }; - - // es5505 voice structs - struct voice_t : es550x_voice_t - { - // constructor - voice_t(es5505_core &host) - : es550x_voice_t(20, 9, false) - , m_host(host) - {} - - // internal state - virtual void reset() override; - virtual void fetch(u8 voice, u8 cycle) override; - virtual void tick(u8 voice) override; - - s32 volume_calc(u8 volume, s32 in); - - // registers - es5505_core &m_host; - u8 m_lvol = 0; // Left volume - u8 m_rvol = 0; // Right volume - output_t m_ch; // channel output - }; - - struct sermode_t - { - sermode_t() - : adc(0) - , test(0) - , sony_bb(0) - , msb(0) - {}; - - void reset() - { - adc = 0; - test = 0; - sony_bb = 0; - msb = 0; - } - - u8 adc : 1; // A/D - u8 test : 1; // Test - u8 sony_bb : 1; // Sony/BB format serial output - u8 msb : 5; // Serial output MSB - }; - - voice_t m_voice[32]; // 32 voices - // Serial related stuffs - sermode_t m_sermode; // Serial mode register - clock_pulse_t m_bclk; // BCLK clock (CLKIN / 4), freely running clock - clock_pulse_t m_lrclk; // LRCLK - s16 m_wclk = 0; // WCLK - bool m_wclk_lr = false; // WCLK, L/R output select - s8 m_output_bit = 0; // Bit position in output - output_t m_ch[4]; // 4 stereo output channels - output_t m_output[4]; // Serial outputs - output_t m_output_temp[4]; // temporary signal for serial output - output_t m_output_latch[4]; // output latch -}; - -#endif diff --git a/src/engine/platform/sound/es550x/es5506.cpp b/src/engine/platform/sound/es550x/es5506.cpp deleted file mode 100644 index c401a4b6..00000000 --- a/src/engine/platform/sound/es550x/es5506.cpp +++ /dev/null @@ -1,794 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5506 emulation core - - see es550x.cpp for more info -*/ - -#include "es5506.hpp" - -// Internal functions -void es5506_core::tick() -{ - m_voice_update = false; - m_voice_end = false; - // CLKIN - if (m_clkin.tick()) - { - // BCLK - if (m_clkin.m_edge.m_changed && (!m_mode.bclk_en)) // BCLK is freely running clock - { - if (m_bclk.tick()) - { - m_intf.bclk(m_bclk.current_edge()); - // Serial output - if (!m_mode.lrclk_en) - { - if (m_bclk.falling_edge()) - { - // LRCLK - if (m_lrclk.tick()) - { - m_intf.lrclk(m_lrclk.current_edge()); - if (m_lrclk.rising_edge()) - { - m_w_st_curr = m_w_st; - m_w_end_curr = m_w_end; - } - if (m_lrclk.falling_edge()) // update width - m_lrclk.set_width_latch(m_lr_end); - } - } - } - // WCLK - if (!m_mode.wclk_en) - { - if (!m_mode.lrclk_en) - { - if (m_lrclk.m_edge.m_changed) - m_wclk = 0; - } - if (m_bclk.falling_edge()) - { - if (m_wclk == m_w_st_curr) - { - m_intf.wclk(true); - if (m_lrclk.current_edge()) - { - for (int i = 0; i < 6; i++) - { - // copy output - m_output[i] = m_output_temp[i]; - m_output_latch[i] = m_ch[i]; - m_output_temp[i].reset(); - // clamp to 20 bit (upper 3 bits are overflow guard bits) - m_output_latch[i].m_left = clamp(m_output_latch[i].m_left, -0x80000, 0x7ffff); - m_output_latch[i].m_right = clamp(m_output_latch[i].m_right, -0x80000, 0x7ffff); - // set signed - if (m_output_latch[i].m_left < 0) - m_output_temp[i].m_left = -1; - if (m_output_latch[i].m_right < 0) - m_output_temp[i].m_right = -1; - } - } - m_wclk_lr = m_lrclk.current_edge(); - m_output_bit = 20; - } - if (m_wclk < m_w_end_curr) - { - s8 output_bit = --m_output_bit; - if (m_output_bit >= 0) - { - for (int i = 0; i < 6; i++) - { - if (m_wclk_lr) // Right output - m_output_temp[i].m_right = (m_output_temp[i].m_right << 1) | bitfield(m_output_latch[i].m_right, output_bit); - else // Left output - m_output_temp[i].m_left = (m_output_temp[i].m_left << 1) | bitfield(m_output_latch[i].m_left, output_bit); - } - } - } - if (m_wclk == m_w_end_curr) - m_intf.wclk(false); - - m_wclk++; - } - } - } - } - // /CAS, E - if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock - { - // /CAS - if (m_cas.tick()) - { - // single OTTO master mode, /CAS high, E low: get sample address - // single OTTO early mode, /CAS falling, E high: get sample address - if (m_cas.falling_edge()) - { - if (!m_e.current_edge()) - { - // single OTTO master mode, /CAS low, E low: fetch sample - if (m_mode.master) - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - else if (m_e.current_edge()) - { - // dual OTTO slave mode, /CAS low, E high: fetch sample - if (m_mode.dual && (!m_mode.master)) // Dual OTTO, slave mode - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - } - } - } - // E - if (m_e.tick()) - { - m_intf.e_pin(m_e.current_edge()); - if (m_e.rising_edge()) - { - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - } - else if (m_e.falling_edge()) - { - m_host_intf.m_host_access = false; - voice_tick(); - } - if (m_e.current_edge()) // Host interface - { - if (m_host_intf.m_host_access) - { - if (m_host_intf.m_rw && (m_e.cycle() == 0)) // Read - { - m_hd = read(m_ha); - m_host_intf.m_host_access = false; - } - else if ((!m_host_intf.m_rw) && (m_e.cycle() == 2)) // Write - write(m_ha, m_hd); - } - } - else if (!m_e.current_edge()) - { - if (m_e.cycle() == 2) - { - // reset host access state - m_hd = 0; - m_host_intf.m_host_access_strobe = false; - } - } - } - } - } -} - -// less cycle accurate, but less CPU heavy routine -void es5506_core::tick_perf() -{ - m_voice_update = false; - m_voice_end = false; - // output - 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) - { - for (int c = 0; c < 6; c++) - { - m_output[c].m_left = clamp(m_ch[c].m_left, -0x80000, 0x7ffff) >> output_bits; - m_output[c].m_right = clamp(m_ch[c].m_right, -0x80000, 0x7ffff) >> output_bits; - } - } - } - else - { - for (int c = 0; c < 6; c++) - { - m_output[c].m_left = 0; - m_output[c].m_right = 0; - } - } - - // update - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; - // falling edge - m_e.m_edge.set(false); - m_intf.e_pin(false); - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe = false; - m_voice[m_voice_cycle].fetch(m_voice_cycle, m_voice_fetch); - voice_tick(); - // rising edge - m_e.m_edge.set(true); - m_intf.e_pin(true); - m_host_intf.m_rw = m_host_intf.m_rw_strobe; - m_host_intf.m_host_access = m_host_intf.m_host_access_strobe; -} - -void es5506_core::voice_tick() -{ - // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) - m_voice_update = bitfield(m_voice_fetch++, 0); - if (m_voice_update) - { - // Update voice - m_voice[m_voice_cycle].tick(m_voice_cycle); - - // Refresh output - if ((++m_voice_cycle) > clamp(m_active, 4, 31)) // 5 ~ 32 voices - { - m_voice_end = true; - m_voice_cycle = 0; - for (auto & elem : m_ch) - elem.reset(); - - for (auto & elem : m_voice) - { - const u8 ca = bitfield(elem.m_cr.ca, 0, 3); - if (ca < 6) - { - m_ch[ca].m_left += elem.m_ch.m_left; - m_ch[ca].m_right += elem.m_ch.m_right; - } - elem.m_ch.reset(); - } - } - m_voice_fetch = 0; - } -} - -void es5506_core::voice_t::fetch(u8 voice, u8 cycle) -{ - m_alu.m_sample[cycle] = m_host.m_intf.read_sample(voice, bitfield(m_cr.bs, 0, 1), bitfield(m_alu.get_accum_integer() + cycle, 0, m_alu.m_integer)); - if (m_cr.cmpd) // Decompress (Upper 8 bit is used for compressed format) - m_alu.m_sample[cycle] = decompress(bitfield(m_alu.m_sample[cycle], 8, 8)); -} - -void es5506_core::voice_t::tick(u8 voice) -{ - m_ch.reset(); - - // Filter execute - m_filter.tick(m_alu.interpolation()); - - if (m_alu.busy()) - { - if (!m_mute) - { - // Send to output - m_ch.m_left = volume_calc(m_lvol, sign_ext(m_filter.m_o4_1, 16)); - m_ch.m_right = volume_calc(m_rvol, sign_ext(m_filter.m_o4_1, 16)); - } - - // ALU execute - if (m_alu.tick()) - m_alu.loop_exec(); - } - // Envelope - if (m_ecount != 0) - { - // Left and Right volume - if (bitfield(m_lvramp, 0, 8) != 0) - m_lvol = clamp(m_lvol + sign_ext(bitfield(m_lvramp, 0, 8), 8), 0, 0xffff); - if (bitfield(m_rvramp, 0, 8) != 0) - m_rvol = clamp(m_rvol + sign_ext(bitfield(m_rvramp, 0, 8), 8), 0, 0xffff); - - // Filter coeffcient - if ((m_k1ramp.ramp != 0) && ((m_k1ramp.slow == 0) || (bitfield(m_filtcount, 0, 3) == 0))) - m_filter.m_k1 = clamp(m_filter.m_k1 + sign_ext(m_k1ramp.ramp, 8), 0, 0xffff); - if ((m_k2ramp.ramp != 0) && ((m_k2ramp.slow == 0) || (bitfield(m_filtcount, 0, 3) == 0))) - m_filter.m_k2 = clamp(m_filter.m_k2 + sign_ext(m_k2ramp.ramp, 8), 0, 0xffff); - - m_ecount--; - } - m_filtcount = bitfield(m_filtcount + 1, 0, 3); - - // Update IRQ - m_alu.irq_exec(m_host.m_intf, m_host.m_irqv, voice); -} - -// Compressed format -s16 es5506_core::voice_t::decompress(u8 sample) -{ - u8 exponent = bitfield(sample, 5, 3); - u8 mantissa = bitfield(sample, 0, 5); - return (exponent > 0) ? - s16(((bitfield(mantissa, 4) ? 0x10 : ~0x1f) | bitfield(mantissa, 0, 4)) << (4 + (exponent - 1))) : - s16(((bitfield(mantissa, 4) ? ~0xf : 0) | bitfield(mantissa, 0, 4)) << 4); -} - -// volume calculation -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)) >> (20 - exponent); -} - -void es5506_core::reset() -{ - es550x_shared_core::reset(); - for (auto & elem : m_voice) - elem.reset(); - - m_read_latch = 0xffffffff; - m_write_latch = 0xffffffff; - m_w_st = 0; - m_w_end = 0; - m_lr_end = 0; - m_w_st_curr = 0; - m_w_end_curr = 0; - m_mode.reset(); - m_bclk.reset(); - m_lrclk.reset(32); - m_wclk = 0; - m_wclk_lr = false; - m_output_bit = 0; - for (auto & elem : m_ch) - elem.reset(); - for (auto & elem : m_output) - elem.reset(); - for (auto & elem : m_output_temp) - elem.reset(); - for (auto & elem : m_output_latch) - elem.reset(); -} - -void es5506_core::voice_t::reset() -{ - es550x_shared_core::es550x_voice_t::reset(); - m_lvol = 0; - m_lvramp = 0; - m_rvol = 0; - m_rvramp = 0; - m_ecount = 0; - m_k2ramp.reset(); - m_k1ramp.reset(); - m_filtcount = 0; - m_ch.reset(); - m_mute = false; -} - -// Accessors -u8 es5506_core::host_r(u8 address) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - if (m_e.rising_edge()) // update directly - m_hd = read(m_ha, true); - else - { - m_host_intf.m_rw_strobe = true; - m_host_intf.m_host_access_strobe = true; - } - } - return m_hd; -} - -void es5506_core::host_w(u8 address, u8 data) -{ - if (!m_host_intf.m_host_access) - { - m_ha = address; - m_hd = data; - if (m_e.rising_edge()) // update directly - write(m_ha, m_hd, true); - else - { - m_host_intf.m_rw_strobe = false; - m_host_intf.m_host_access_strobe = true; - } - } -} - -u8 es5506_core::read(u8 address, bool cpu_access) -{ - const u8 byte = bitfield(address, 0, 2); // byte select - const u8 shift = 24 - (byte << 3); - if (byte != 0) // Return already latched register if not highest byte is accessing - return bitfield(m_read_latch, shift, 8); - - address = bitfield(address, 2, 4); // 4 bit address for CPU access - - // get read register - m_read_latch = regs_r(m_page, address, cpu_access); - - return bitfield(m_read_latch, 24, 8); -} - -void es5506_core::write(u8 address, u8 data, bool cpu_access) -{ - const u8 byte = bitfield(address, 0, 2); // byte select - const u8 shift = 24 - (byte << 3); - address = bitfield(address, 2, 4); // 4 bit address for CPU access - - // Update register latch - m_write_latch = (m_write_latch & ~(0xff << shift)) | (u32(data) << shift); - - if (byte != 3) // Wait until lowest byte is writed - return; - - regs_w(m_page, address, m_write_latch, cpu_access); - - // Reset latch - m_write_latch = 0; -} - -u32 es5506_core::regs_r(u8 page, u8 address, bool cpu_access) -{ - u32 read_latch = 0xffffffff; - if (address >= 13) // Global registers - { - switch (address) - { - case 13: // POT (Pot A/D Register) - read_latch = (read_latch & ~0x3ff) | bitfield(m_intf.adc_r(), 0, 10); - break; - case 14: // IRQV (Interrupting voice vector) - read_latch = (read_latch & ~0x9f) | (m_irqv.irqb ? 0x80 : 0) | bitfield(m_irqv.voice, 0, 5); - if (cpu_access) - { - m_irqv.clear(); - if (bitfield(read_latch, 7) != m_irqv.irqb) - m_voice[m_irqv.voice].m_alu.irq_update(m_intf, m_irqv); - } - break; - case 15: // PAGE (Page select register) - read_latch = (read_latch & ~0x7f) | bitfield(m_page, 0, 7); - break; - } - } - else - { - if (bitfield(page, 6)) // Channel registers are Write only - { - if (!cpu_access) // CPU can't read here - { - switch (address) - { - case 0: // CH0L (Channel 0 Left) - case 2: // CH1L (Channel 1 Left) - case 4: // CH2L (Channel 2 Left) - case 6: // CH3L (Channel 3 Left) - case 8: // CH4L (Channel 4 Left) - case 10: // CH5L (Channel 5 Left) - read_latch = m_ch[bitfield(address, 1, 3)].m_left; - break; - case 1: // CH0R (Channel 0 Right) - case 3: // CH1R (Channel 1 Right) - case 5: // CH2R (Channel 2 Right) - case 7: // CH3R (Channel 3 Right) - case 9: // CH4R (Channel 4 Right) - case 11: // CH5R (Channel 5 Right) - read_latch = m_ch[bitfield(address, 1, 3)].m_right; - break; - } - } - } - else - { - const u8 voice = bitfield(page, 0, 5); // Voice select - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 63 - { - switch (address) - { - case 0: // CR (Control Register) - read_latch = (read_latch & ~0xffff) | - (v.m_alu.m_cr.stop0 ? 0x0001 : 0x0000) - | (v.m_alu.m_cr.stop1 ? 0x0002 : 0x0000) - | (v.m_alu.m_cr.lei ? 0x0004 : 0x0000) - | (v.m_alu.m_cr.lpe ? 0x0008 : 0x0000) - | (v.m_alu.m_cr.ble ? 0x0010 : 0x0000) - | (v.m_alu.m_cr.irqe ? 0x0020 : 0x0000) - | (v.m_alu.m_cr.dir ? 0x0040 : 0x0000) - | (v.m_alu.m_cr.irq ? 0x0080 : 0x0000) - | (bitfield(v.m_filter.m_lp, 0, 2) << 8) - | (bitfield(v.m_cr.ca, 0, 3) << 10) - | (v.m_cr.cmpd ? 0x2000 : 0x0000) - | (bitfield(v.m_cr.bs, 0, 2) << 14); - break; - case 1: // START (Loop Start Register) - read_latch = (read_latch & ~0xfffff800) | (v.m_alu.m_start & 0xfffff800); - break; - case 2: // END (Loop End Register) - read_latch = (read_latch & ~0xffffff80) | (v.m_alu.m_end & 0xffffff80); - break; - case 3: // ACCUM (Accumulator Register) - read_latch = v.m_alu.m_accum; - break; - case 4: // O4(n-1) (Filter 4 Temp Register) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o4_1, 0, 18); - else - read_latch = v.m_filter.m_o4_1; - break; - case 5: // O3(n-2) (Filter 3 Temp Register #2) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o3_2, 0, 18); - else - read_latch = v.m_filter.m_o3_2; - break; - case 6: // O3(n-1) (Filter 3 Temp Register #1) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o3_1, 0, 18); - else - read_latch = v.m_filter.m_o3_1; - break; - case 7: // O2(n-2) (Filter 2 Temp Register #2) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o2_2, 0, 18); - else - read_latch = v.m_filter.m_o2_2; - break; - case 8: // O2(n-1) (Filter 2 Temp Register #1) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o2_1, 0, 18); - else - read_latch = v.m_filter.m_o2_1; - break; - case 9: // O1(n-1) (Filter 1 Temp Register) - if (cpu_access) - read_latch = (read_latch & ~0x3ffff) | bitfield(v.m_filter.m_o1_1, 0, 18); - else - read_latch = v.m_filter.m_o1_1; - break; - case 10: // W_ST (Word Clock Start Register) - read_latch = (read_latch & ~0x7f) | bitfield(m_w_st, 0, 7); - break; - case 11: // W_END (Word Clock End Register) - read_latch = (read_latch & ~0x7f) | bitfield(m_w_end, 0, 7); - break; - case 12: // LR_END (Left/Right Clock End Register) - read_latch = (read_latch & ~0x7f) | bitfield(m_lr_end, 0, 7); - break; - } - } - else // Page 0 - 31 - { - switch (address) - { - case 0: // CR (Control Register) - read_latch = (read_latch & ~0xffff) | - (v.m_alu.m_cr.stop0 ? 0x0001 : 0x0000) - | (v.m_alu.m_cr.stop1 ? 0x0002 : 0x0000) - | (v.m_alu.m_cr.lei ? 0x0004 : 0x0000) - | (v.m_alu.m_cr.lpe ? 0x0008 : 0x0000) - | (v.m_alu.m_cr.ble ? 0x0010 : 0x0000) - | (v.m_alu.m_cr.irqe ? 0x0020 : 0x0000) - | (v.m_alu.m_cr.dir ? 0x0040 : 0x0000) - | (v.m_alu.m_cr.irq ? 0x0080 : 0x0000) - | (bitfield(v.m_filter.m_lp, 0, 2) << 8) - | (bitfield(v.m_cr.ca, 0, 3) << 10) - | (v.m_cr.cmpd ? 0x2000 : 0x0000) - | (bitfield(v.m_cr.bs, 0, 2) << 14); - break; - case 1: // FC (Frequency Control) - read_latch = (read_latch & ~0x1ffff) | bitfield(v.m_alu.m_fc, 0, 17); - break; - case 2: // LVOL (Left Volume) - read_latch = (read_latch & ~0xffff) | bitfield(v.m_lvol, 0, 16); - break; - case 3: // LVRAMP (Left Volume Ramp) - read_latch = (read_latch & ~0xff00) | (bitfield(v.m_lvramp, 0, 8) << 8); - break; - case 4: // RVOL (Right Volume) - read_latch = (read_latch & ~0xffff) | bitfield(v.m_rvol, 0, 16); - break; - case 5: // RVRAMP (Right Volume Ramp) - read_latch = (read_latch & ~0xff00) | (bitfield(v.m_rvramp, 0, 8) << 8); - break; - case 6: // ECOUNT (Envelope Counter) - read_latch = (read_latch & ~0x01ff) | bitfield(v.m_ecount, 0, 9); - break; - case 7: // K2 (Filter Cutoff Coefficient #2) - read_latch = (read_latch & ~0xffff) | bitfield(v.m_filter.m_k2, 0, 16); - break; - case 8: // K2RAMP (Filter Cutoff Coefficient #2 Ramp) - read_latch = (read_latch & ~0xff01) | (bitfield(v.m_k2ramp.ramp, 0, 8) << 8) | (v.m_k2ramp.slow ? 0x0001 : 0x0000); - break; - case 9: // K1 (Filter Cutoff Coefficient #1) - read_latch = (read_latch & ~0xffff) | bitfield(v.m_filter.m_k1, 0, 16); - break; - case 10: // K1RAMP (Filter Cutoff Coefficient #1 Ramp) - read_latch = (read_latch & ~0xff01) | (bitfield(v.m_k1ramp.ramp, 0, 8) << 8) | (v.m_k1ramp.slow ? 0x0001 : 0x0000); - break; - case 11: // ACT (Number of voices) - read_latch = (read_latch & ~0x1f) | bitfield(m_active, 0, 5); - break; - case 12: // MODE (Global Mode) - read_latch = (read_latch & ~0x1f) | - (m_mode.lrclk_en ? 0x01 : 0x00) - | (m_mode.wclk_en ? 0x02 : 0x00) - | (m_mode.bclk_en ? 0x04 : 0x00) - | (m_mode.master ? 0x08 : 0x00) - | (m_mode.dual ? 0x10 : 0x00); - break; - } - } - } - } - - return read_latch; -} - -void es5506_core::regs_w(u8 page, u8 address, u32 data, bool cpu_access) -{ - if (address >= 13) // Global registers - { - switch (address) - { - case 13: // POT (Pot A/D Register) - // Read only - break; - case 14: // IRQV (Interrupting voice vector) - // Read only - break; - case 15: // PAGE (Page select register) - m_page = bitfield(data, 0, 7); - break; - } - } - else - { - if (bitfield(page, 6)) // Channel registers are Write only, and for test purposes - { - switch (address) - { - case 0: // CH0L (Channel 0 Left) - case 2: // CH1L (Channel 1 Left) - case 4: // CH2L (Channel 2 Left) - case 6: // CH3L (Channel 3 Left) - case 8: // CH4L (Channel 4 Left) - case 10: // CH5L (Channel 5 Left) - m_ch[bitfield(address, 1, 3)].m_left = sign_ext(bitfield(data, 0, 23), 23); - break; - case 1: // CH0R (Channel 0 Right) - case 3: // CH1R (Channel 1 Right) - case 5: // CH2R (Channel 2 Right) - case 7: // CH3R (Channel 3 Right) - case 9: // CH4R (Channel 4 Right) - case 11: // CH5R (Channel 5 Right) - m_ch[bitfield(address, 1, 3)].m_right = sign_ext(bitfield(data, 0, 23), 23); - break; - } - } - else - { - const u8 voice = bitfield(page, 0, 5); // Voice select - voice_t &v = m_voice[voice]; - if (bitfield(page, 5)) // Page 32 - 63 - { - switch (address) - { - case 0: // CR (Control Register) - v.m_alu.m_cr.stop0 = bitfield(data, 0); - v.m_alu.m_cr.stop1 = bitfield(data, 1); - v.m_alu.m_cr.lei = bitfield(data, 2); - v.m_alu.m_cr.lpe = bitfield(data, 3); - v.m_alu.m_cr.ble = bitfield(data, 4); - v.m_alu.m_cr.irqe = bitfield(data, 5); - v.m_alu.m_cr.dir = bitfield(data, 6); - v.m_alu.m_cr.irq = bitfield(data, 7); - v.m_filter.m_lp = bitfield(data, 8, 2); - v.m_cr.ca = std::min(5, bitfield(data, 10, 3)); - v.m_cr.cmpd = bitfield(data, 13); - v.m_cr.bs = bitfield(data, 14, 2); - break; - case 1: // START (Loop Start Register) - v.m_alu.m_start = data & 0xfffff800; - break; - case 2: // END (Loop End Register) - v.m_alu.m_end = data & 0xffffff80; - break; - case 3: // ACCUM (Accumulator Register) - v.m_alu.m_accum = data; - break; - case 4: // O4(n-1) (Filter 4 Temp Register) - v.m_filter.m_o4_1 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 5: // O3(n-2) (Filter 3 Temp Register #2) - v.m_filter.m_o3_2 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 6: // O3(n-1) (Filter 3 Temp Register #1) - v.m_filter.m_o3_1 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 7: // O2(n-2) (Filter 2 Temp Register #2) - v.m_filter.m_o2_2 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 8: // O2(n-1) (Filter 2 Temp Register #1) - v.m_filter.m_o2_1 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 9: // O1(n-1) (Filter 1 Temp Register) - v.m_filter.m_o1_1 = sign_ext(bitfield(data, 0, 18), 18); - break; - case 10: // W_ST (Word Clock Start Register) - m_w_st = bitfield(data, 0, 7); - break; - case 11: // W_END (Word Clock End Register) - m_w_end = bitfield(data, 0, 7); - break; - case 12: // LR_END (Left/Right Clock End Register) - m_lr_end = bitfield(data, 0, 7); - m_lrclk.set_width(m_lr_end); - break; - } - } - else // Page 0 - 31 - { - switch (address) - { - case 0: // CR (Control Register) - v.m_alu.m_cr.stop0 = bitfield(data, 0); - v.m_alu.m_cr.stop1 = bitfield(data, 1); - v.m_alu.m_cr.lei = bitfield(data, 2); - v.m_alu.m_cr.lpe = bitfield(data, 3); - v.m_alu.m_cr.ble = bitfield(data, 4); - v.m_alu.m_cr.irqe = bitfield(data, 5); - v.m_alu.m_cr.dir = bitfield(data, 6); - v.m_alu.m_cr.irq = bitfield(data, 7); - v.m_filter.m_lp = bitfield(data, 8, 2); - v.m_cr.ca = std::min(5, bitfield(data, 10, 3)); - v.m_cr.cmpd = bitfield(data, 13); - v.m_cr.bs = bitfield(data, 14, 2); - break; - case 1: // FC (Frequency Control) - v.m_alu.m_fc = bitfield(data, 0, 17); - break; - case 2: // LVOL (Left Volume) - v.m_lvol = bitfield(data, 0, 16); - break; - case 3: // LVRAMP (Left Volume Ramp) - v.m_lvramp = bitfield(data, 8, 8); - break; - case 4: // RVOL (Right Volume) - v.m_rvol = bitfield(data, 0, 16); - break; - case 5: // RVRAMP (Right Volume Ramp) - v.m_rvramp = bitfield(data, 8, 8); - break; - case 6: // ECOUNT (Envelope Counter) - v.m_ecount = bitfield(data, 0, 9); - break; - case 7: // K2 (Filter Cutoff Coefficient #2) - v.m_filter.m_k2 = bitfield(data, 0, 16); - break; - case 8: // K2RAMP (Filter Cutoff Coefficient #2 Ramp) - v.m_k2ramp.slow = bitfield(data, 0); - v.m_k2ramp.ramp = bitfield(data, 8, 8); - break; - case 9: // K1 (Filter Cutoff Coefficient #1) - v.m_filter.m_k1 = bitfield(data, 0, 16); - break; - case 10: // K1RAMP (Filter Cutoff Coefficient #1 Ramp) - v.m_k1ramp.slow = bitfield(data, 0); - v.m_k1ramp.ramp = bitfield(data, 8, 8); - break; - case 11: // ACT (Number of voices) - m_active = std::max(4, bitfield(data, 0, 5)); - break; - case 12: // MODE (Global Mode) - m_mode.lrclk_en = bitfield(data, 0); - m_mode.wclk_en = bitfield(data, 1); - m_mode.bclk_en = bitfield(data, 2); - m_mode.master = bitfield(data, 3); - m_mode.dual = bitfield(data, 4); - break; - } - } - } - } -} diff --git a/src/engine/platform/sound/es550x/es5506.hpp b/src/engine/platform/sound/es550x/es5506.hpp deleted file mode 100644 index b16be367..00000000 --- a/src/engine/platform/sound/es550x/es5506.hpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504 emulation core - - See es550x.cpp for more info -*/ - -#include "es550x.hpp" - -#ifndef _VGSOUND_EMU_ES5506_HPP -#define _VGSOUND_EMU_ES5506_HPP - -#pragma once - -// ES5506 specific -class es5506_core : public es550x_shared_core -{ -public: - // constructor - es5506_core(es550x_intf &intf) - : es550x_shared_core(intf) - , m_voice{*this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this, - *this,*this,*this,*this,*this,*this,*this,*this} - { - } - // host interface - u8 host_r(u8 address); - void host_w(u8 address, u8 data); - - // internal state - virtual void reset() override; - virtual void tick() override; - - // less cycle accurate, but also less cpu heavy update routine - void tick_perf(); - - // clock outputs - bool bclk() { return m_bclk.current_edge(); } - bool bclk_rising_edge() { return m_bclk.rising_edge(); } - bool bclk_falling_edge() { return m_bclk.falling_edge(); } - - // 6 stereo output channels - s32 lout(u8 ch) { return m_output[std::min(5, ch & 0x7)].m_left; } - s32 rout(u8 ch) { return m_output[std::min(5, ch & 0x7)].m_right; } - -//----------------------------------------------------------------- -// -// for preview/debug purpose only, not for serious emulators -// -//----------------------------------------------------------------- - - // bypass chips host interface for debug purpose only - u8 read(u8 address, bool cpu_access = false); - void write(u8 address, u8 data, bool cpu_access = false); - - u32 regs_r(u8 page, u8 address, bool cpu_access = false); - void regs_w(u8 page, u8 address, u32 data, bool cpu_access = false); - - u8 regs8_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u8 ret = read(address, false); m_page = prev; return ret; } - void set_mute(u8 ch, bool mute) { m_voice[ch & 0x1f].m_mute = mute; } - - // per-voice outputs - s32 voice_lout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_left : 0; } - s32 voice_rout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_right : 0; } - -protected: - virtual inline u8 max_voices() override { return 32; } - virtual void voice_tick() override; - -private: - struct output_t - { - void reset() - { - m_left = 0; - m_right = 0; - }; - - s32 m_left = 0; - s32 m_right = 0; - }; - - // es5506 voice structs - struct voice_t : es550x_voice_t - { - // constructor - voice_t(es5506_core &host) - : es550x_voice_t(21, 11, true) - , m_host(host) {} - - // internal state - virtual void reset() override; - virtual void fetch(u8 voice, u8 cycle) override; - virtual void tick(u8 voice) override; - - // accessors, getters, setters - s16 decompress(u8 sample); - s32 volume_calc(u16 volume, s32 in); - - struct filter_ramp_t - { - filter_ramp_t() - : slow(0) - , ramp(0) - { }; - - void reset() - { - slow = 0; - ramp = 0; - }; - - u16 slow : 1; // Slow mode flag - u16 ramp = 8; // Ramp value - }; - - // registers - es5506_core &m_host; - s32 m_lvol = 0; // Left volume - 4 bit exponent, 8 bit mantissa, 4 LSBs are used for fine control of ramp increment for hardware envelope - s32 m_lvramp = 0; // Left volume ramp - s32 m_rvol = 0; // Right volume - s32 m_rvramp = 0; // Righr volume ramp - s16 m_ecount = 0; // Envelope counter - filter_ramp_t m_k2ramp; // Filter coefficient 2 Ramp - filter_ramp_t m_k1ramp; // Filter coefficient 1 Ramp - u8 m_filtcount = 0; // Internal counter for slow mode - output_t m_ch; // channel output - bool m_mute = false; // mute flag (for debug purpose) - }; - - // 5 bit mode - struct mode_t - { - mode_t() - : bclk_en(0) - , wclk_en(0) - , lrclk_en(0) - , master(0) - , dual(0) - { }; - - void reset() - { - bclk_en = 1; - wclk_en = 1; - lrclk_en = 1; - master = 0; - dual = 0; - } - - u8 bclk_en : 1; // Set BCLK to output - u8 wclk_en : 1; // Set WCLK to output - u8 lrclk_en : 1; // Set LRCLK to output - u8 master : 1; // Set memory mode to master - u8 dual : 1; // Set dual chip config - }; - - voice_t m_voice[32]; // 32 voices - - // Host interfaces - u32 m_read_latch = 0; // 32 bit register latch for host read - u32 m_write_latch = 0; // 32 bit register latch for host write - - // Serial register - u8 m_w_st = 0; // Word clock start register - u8 m_w_end = 0; // Word clock end register - u8 m_lr_end = 0; // Left/Right clock end register - mode_t m_mode; // Global mode - - // Serial related stuffs - u8 m_w_st_curr = 0; // Word clock start, current status - u8 m_w_end_curr = 0; // Word clock end register - clock_pulse_t m_bclk; // BCLK clock (CLKIN / 4), freely running clock - clock_pulse_t m_lrclk; // LRCLK - s16 m_wclk = 0; // WCLK - bool m_wclk_lr = false; // WCLK, L/R output select - s8 m_output_bit = 0; // Bit position in output - output_t m_ch[6]; // 6 stereo output channels - output_t m_output[6]; // Serial outputs - output_t m_output_temp[6]; // temporary signal for serial output - output_t m_output_latch[6]; // output latch -}; - -#endif diff --git a/src/engine/platform/sound/es550x/es550x.cpp b/src/engine/platform/sound/es550x/es550x.cpp deleted file mode 100644 index 10d1d9a9..00000000 --- a/src/engine/platform/sound/es550x/es550x.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504/ES5505/ES5506 emulation core - - After ES5503 DOC's appeared, Ensoniq announces ES5504 DOC II, ES5505 OTIS, ES5506 OTTO. - - These are not just PCM chip; but with built-in 4 pole filters and variable voice limits. - - It can be trades higher sample rate and finer frequency and Tons of voices, or vice-versa. - - These are mainly used with their synthesizers, musical stuffs. It's also mainly paired with ES5510 ESP/ES5511 ESP2 for post processing. - ES5506 can be paired with itself, It's called Dual chip configuration and Both chips are can be shares same memory spaces. - - ES5505 was also mainly used on Taito's early- to late-90s arcade hardware for their PCM sample based sound system, - paired with ES5510 ESP for post processing. It's configuration is borrowed from Ensoniq's 32 Voice synths powered by these chips. - It's difference is external logic to adds per-voice bankswitching looks like what Konami doing on K007232. - - Atari Panther was will be use ES5505, but finally canceled. - - Ensoniq's ISA Sound Card for PC, Soundscape used ES5506, "Elite" model has optional daughterboard with ES5510 for digital effects. - - Related chips: - ES5530 "OPUS" variant is 2-in-one chip with built-in ES5506 and Sequoia. - ES5540 "OTTOFX" variant is ES5506 and ES5510 merged in single package. - ES5548 "OTTO48" variant is used at late-90s ensoniq synths and musical instruments, 2 ES5506s are merged in single package, or with 48 voices in chip? - - Chip difference: - ES5504 to ES5505: - Total voice amount is expanded to 32, rather than 25. - ADC and DAC is completely redesigned. it's has now voice-independent 10 bit and Sony/Burr-Brown format DAC. - Output channel and Volume is changed to 16 mono to 4 stereo, 12 bit Analog to 8 bit Stereo digital, also Floating point-ish format and independent per left and right output. - Channel 3 is can be Input/Output. - Channel output is can be accessible at host for test purpose. - Max sample memory is expanded to 2MWords (1MWords * 2 Banks) - - ES5505 to ES5506: - Frequency is more finer now: 11 bit fraction rather than 9 bit. - Output channel and Volume is changed to 4 stereo to 6 stereo, 8 bit to 16 bit, but only 12 bit is used for calculation; 4 LSB is used for envelope ramping. - Transwave flag is added - its helpful for transwave process, with interrupt per voices. - Hardware envelope is added - K1, K2, Volume value is can be modified in run-time. also K1, K2 is expanded to 16 bit for finer envelope ramping. - Filter calculation resolution is expanded to 18 bit. - All channels are output, Serial output is now partially programmable. - Max sample memory is expanded to 8MWords (2MWords * 4 Banks) - - Register format between these chips are incompatible. - -*/ - -#include "es550x.hpp" - -// Shared functions -void es550x_shared_core::reset() -{ - m_host_intf.reset(); - m_ha = 0; - m_hd = 0; - m_page = 0; - m_irqv.reset(); - m_active = max_voices() - 1; - m_voice_cycle = 0; - m_voice_fetch = 0; - m_voice_update = false; - m_voice_end = false; - m_clkin.reset(); - m_cas.reset(); - m_e.reset(); -} - -void es550x_shared_core::es550x_voice_t::reset() -{ - m_cr.reset(); - m_alu.reset(); - m_filter.reset(); -} diff --git a/src/engine/platform/sound/es550x/es550x.hpp b/src/engine/platform/sound/es550x/es550x.hpp deleted file mode 100644 index e5106b78..00000000 --- a/src/engine/platform/sound/es550x/es550x.hpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504/ES5505/ES5506 emulation core - - See es550x.cpp for more info -*/ - -#ifndef _VGSOUND_EMU_ES550X_HPP -#define _VGSOUND_EMU_ES550X_HPP - -#pragma once - -#include -#include -#include "util.hpp" - -// ES5504/ES5505/ES5506 interface -class es550x_intf -{ -public: - virtual void e_pin(bool state) {} // E output - virtual void bclk(bool state) {} // BCLK output (serial specific) - virtual void lrclk(bool state) {} // LRCLK output (serial specific) - virtual void wclk(bool state) {} // WCLK output (serial specific) - - virtual void irqb(bool state) {} // IRQB output - virtual u16 adc_r() { return 0; } // ADC input - virtual void adc_w(u16 data) {} // ADC output - virtual s16 read_sample(u8 voice, u8 bank, u32 address) { return 0; } -}; - -// Shared functions for ES5504/ES5505/ES5506 -class es550x_shared_core -{ - friend class es550x_intf; // es550x specific memory interface -public: - // constructor - es550x_shared_core(es550x_intf &intf) - : m_intf(intf) - { }; - - // internal state - virtual void reset(); - virtual void tick() {} - - // clock outputs - bool _cas() { return m_cas.current_edge(); } - bool _cas_rising_edge() { return m_cas.rising_edge(); } - bool _cas_falling_edge() { return m_cas.falling_edge(); } - - bool e() { return m_e.current_edge(); } - bool e_rising_edge() { return m_e.rising_edge(); } - bool e_falling_edge() { return m_e.falling_edge(); } - -//----------------------------------------------------------------- -// -// for preview/debug purpose only, not for serious emulators -// -//----------------------------------------------------------------- - - // voice cycle - u8 voice_cycle() { return m_voice_cycle; } - - // voice update flag - bool voice_update() { return m_voice_update; } - bool voice_end() { return m_voice_end; } - -protected: - // Constants - virtual inline u8 max_voices() { return 32; } - - // Shared registers, functions - virtual void voice_tick() {} // voice tick - - // Interrupt bits - struct es550x_irq_t - { - es550x_irq_t() - : voice(0) - , irqb(1) - { }; - - void reset() - { - voice = 0; - irqb = 1; - } - - void set(u8 index) - { - irqb = 0; - voice = index; - } - - void clear() - { - irqb = 1; - voice = 0; - } - - u8 voice : 5; - u8 irqb : 1; - }; - - // Common control bits - struct es550x_control_t - { - es550x_control_t() - : ca(0) - , adc(0) - , bs(0) - , cmpd(0) - { }; - - void reset() - { - ca = 0; - adc = 0; - bs = 0; - cmpd = 0; - } - - u8 ca : 4; // Channel assign (4 bit (16 channel or Bank) for ES5504, 2 bit (4 stereo channels) for ES5505, 3 bit (6 stereo channels) for ES5506) - // ES5504 Specific - u8 adc : 1; // Start ADC - // ES5505/ES5506 Specific - u8 bs : 2; // Bank bit (1 bit for ES5505, 2 bit for ES5506) - u8 cmpd : 1; // Use compressed sample format - }; - - // Accumulator - struct es550x_alu_t - { - es550x_alu_t(u8 integer, u8 fraction, bool transwave) - : m_integer(integer) - , m_fraction(fraction) - , m_total_bits(integer + fraction) - , m_accum_mask(u32(std::min(~0, u64(u64(1) << u64(integer + fraction)) - 1))) - , m_transwave(transwave) - {} - - const u8 m_integer; - const u8 m_fraction; - const u8 m_total_bits; - const u32 m_accum_mask; - const bool m_transwave; - - void reset(); - bool busy(); - bool tick(); - void loop_exec(); - s32 interpolation(); - u32 get_accum_integer(); - void irq_exec(es550x_intf &intf, es550x_irq_t &irqv, u8 index); - void irq_update(es550x_intf &intf, es550x_irq_t &irqv) { intf.irqb(irqv.irqb ? false : true); } - - struct es550x_alu_cr_t - { - es550x_alu_cr_t() - : stop0(0) - , stop1(0) - , lpe(0) - , ble(0) - , irqe(0) - , dir(0) - , irq(0) - , lei(0) - { }; - - void reset() - { - stop0 = 0; - stop1 = 0; - lpe = 0; - ble = 0; - irqe = 0; - dir = 0; - irq = 0; - lei = 0; - } - - u8 stop0 : 1; // Stop with ALU - u8 stop1 : 1; // Stop with processor - u8 lpe : 1; // Loop enable - u8 ble : 1; // Bidirectional loop enable - u8 irqe : 1; // IRQ enable - u8 dir : 1; // Playback direction - u8 irq : 1; // IRQ bit - u8 lei : 1; // Loop end ignore (ES5506 specific) - }; - - es550x_alu_cr_t m_cr; - u32 m_fc = 0; // Frequency - 6 integer, 9 fraction for ES5506/ES5505, 6 integer, 11 fraction for ES5506 - u32 m_start = 0; // Start register - u32 m_end = 0; // End register - u32 m_accum = 0; // Accumulator - 20 integer, 9 fraction for ES5506/ES5505, 21 integer, 11 fraction for ES5506 - s32 m_sample[2] = {0}; // Samples - }; - - // Filter - struct es550x_filter_t - { - void reset(); - void tick(s32 in); - s32 lp_exec(s32 coeff, s32 in, s32 prev_out); - s32 hp_exec(s32 coeff, s32 in, s32 prev_out, s32 prev_in); - - // Registers - u8 m_lp = 0; // Filter mode - // Filter coefficient registers - s32 m_k2 = 0; // Filter coefficient 2 - 12 bit for filter calculation, 4 LSBs are used for fine control of ramp increment for hardware envelope (ES5506) - s32 m_k1 = 0; // Filter coefficient 1 - // Filter storage registers - s32 m_o1_1 = 0; // First stage - s32 m_o2_1 = 0; // Second stage - s32 m_o2_2 = 0; // Second stage HP - s32 m_o3_1 = 0; // Third stage - s32 m_o3_2 = 0; // Third stage HP - s32 m_o4_1 = 0; // Final stage - }; - - // Common voice struct - struct es550x_voice_t - { - es550x_voice_t(u8 integer, u8 fraction, bool transwave) - : m_alu(integer, fraction, transwave) - {} - - // internal state - virtual void reset(); - virtual void fetch(u8 voice, u8 cycle) = 0; - virtual void tick(u8 voice) = 0; - - es550x_control_t m_cr; - es550x_alu_t m_alu; - es550x_filter_t m_filter; - }; - - - // Host interfaces - struct host_interface_flag_t - { - host_interface_flag_t() - : m_host_access(0) - , m_host_access_strobe(0) - , m_rw(0) - , m_rw_strobe(0) - {} - - void reset() - { - m_host_access = 0; - m_host_access_strobe = 0; - m_rw = 0; - m_rw_strobe = 0; - } - - u8 m_host_access : 1; // Host access trigger - u8 m_host_access_strobe : 1; // Host access strobe - u8 m_rw : 1; // R/W state - u8 m_rw_strobe : 1; // R/W strobe - }; - host_interface_flag_t m_host_intf; // Host interface flag - u8 m_ha = 0; // Host address (4 bit) - u16 m_hd = 0; // Host data (16 bit for ES5504/ES5505, 8 bit for ES5506) - u8 m_page = 0; // Page - es550x_irq_t m_irqv; // Voice interrupt vector registers - // Internal states - u8 m_active = max_voices() - 1; // Activated voices (-1, ~25 for ES5504, ~32 for ES5505/ES5506) - u8 m_voice_cycle = 0; // Voice cycle - u8 m_voice_fetch = 0; // Voice fetch cycle - bool m_voice_update = false; // Voice update flag - bool m_voice_end = false; // End of one voice cycle flag - es550x_intf &m_intf; // es550x specific memory interface - clock_pulse_t m_clkin; // CLKIN clock - clock_pulse_t m_cas; // /CAS clock (CLKIN / 4), falling edge of CLKIN trigger this clock - clock_pulse_t m_e; // E clock (CLKIN / 8), falling edge of CLKIN trigger this clock -}; - -#endif diff --git a/src/engine/platform/sound/es550x/es550x_alu.cpp b/src/engine/platform/sound/es550x/es550x_alu.cpp deleted file mode 100644 index 6b11d9ec..00000000 --- a/src/engine/platform/sound/es550x/es550x_alu.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504/ES5505/ES5506 Shared Accumulator emulation core - - see es550x.cpp for more info -*/ - -#include "es550x.hpp" - -// Accumulator functions -void es550x_shared_core::es550x_alu_t::reset() -{ - m_cr.reset(); - m_fc = 0; - m_start = 0; - m_end = 0; - m_accum = 0; - m_sample[0] = m_sample[1] = 0; -} - -bool es550x_shared_core::es550x_alu_t::busy() -{ - return ((!m_cr.stop0) && (!m_cr.stop1)); -} - -bool es550x_shared_core::es550x_alu_t::tick() -{ - if (m_cr.dir) - m_accum -= m_fc; - else - m_accum += m_fc; - - m_accum &= m_accum_mask; - return ((!m_cr.lei) - && ((( m_cr.dir) && (m_accum < m_start)) - || ((!m_cr.dir) && (m_accum > m_end)))) ? true : false; -} - -void es550x_shared_core::es550x_alu_t::loop_exec() -{ - if (m_cr.irqe) // Set IRQ - m_cr.irq = 1; - - if (m_cr.dir) // Reverse playback - { - if (m_cr.lpe) // Loop enable - { - if (m_cr.ble) // Bidirectional - { - m_cr.dir = 0; - m_accum = m_start + (m_start - m_accum); - } - else// Normal - m_accum = m_end - (m_start - m_accum); - } - else if (m_cr.ble && m_transwave) // m_transwave - { - m_cr.lpe = m_cr.ble = 0; - m_cr.lei = 1; // Loop end ignore - m_accum = m_end - (m_start - m_accum); - } - else // Stop - m_cr.stop0 = 1; - } - else - { - if (m_cr.lpe) // Loop enable - { - if (m_cr.ble) // Bidirectional - { - m_cr.dir = 1; - m_accum = m_end - (m_end - m_accum); - } - else // Normal - m_accum = (m_accum - m_end) + m_start; - } - else if (m_cr.ble && m_transwave) // m_transwave - { - m_cr.lpe = m_cr.ble = 0; - m_cr.lei = 1; // Loop end ignore - m_accum = (m_accum - m_end) + m_start; - } - else // Stop - m_cr.stop0 = 1; - } -} - -s32 es550x_shared_core::es550x_alu_t::interpolation() -{ - // SF = S1 + ACCfr * (S2 - S1) - return m_sample[0] + ((bitfield(m_accum, std::max(0, m_fraction - 9), 9) * (m_sample[1] - m_sample[0])) >> 9); -} - -u32 es550x_shared_core::es550x_alu_t::get_accum_integer() -{ - return bitfield(m_accum, m_fraction, m_integer); -} - -void es550x_shared_core::es550x_alu_t::irq_exec(es550x_intf &intf, es550x_irq_t &irqv, u8 index) -{ - const u8 prev = irqv.irqb; - if (m_cr.irq) - { - if (irqv.irqb) - { - irqv.set(index); - m_cr.irq = 0; - } - } - if (prev != irqv.irqb) - irq_update(intf, irqv); -} diff --git a/src/engine/platform/sound/es550x/es550x_filter.cpp b/src/engine/platform/sound/es550x/es550x_filter.cpp deleted file mode 100644 index bf0b260c..00000000 --- a/src/engine/platform/sound/es550x/es550x_filter.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Ensoniq ES5504/ES5505/ES5506 Shared Filter emulation core - - see es550x.cpp for more info -*/ - -#include "es550x.hpp" - -// Filter functions -void es550x_shared_core::es550x_filter_t::reset() -{ - m_lp = 0; - m_k2 = 0; - m_k1 = 0; - m_o1_1 = 0; - m_o2_1 = 0; - m_o2_2 = 0; - m_o3_1 = 0; - m_o3_2 = 0; - m_o4_1 = 0; -} - -void es550x_shared_core::es550x_filter_t::tick(s32 in) -{ - s32 coeff_k1 = s32(bitfield(m_k1, 4, 12)); // 12 MSB used - s32 coeff_k2 = s32(bitfield(m_k2, 4, 12)); // 12 MSB used - // Store previous filter data - m_o2_2 = m_o2_1; - m_o3_2 = m_o3_1; - - // First and second stage: LP/K1, LP/K1 Fixed - m_o1_1 = lp_exec(coeff_k1, in, m_o1_1); - m_o2_1 = lp_exec(coeff_k1, m_o1_1, m_o2_1); - switch (m_lp) - { - case 0: // LP3 = 0, LP4 = 0: HP/K2, HP/K2 - default: - m_o3_1 = hp_exec(coeff_k2, m_o2_1, m_o3_1, m_o2_2); - m_o4_1 = hp_exec(coeff_k2, m_o3_1, m_o4_1, m_o3_2); - break; - case 1: // LP3 = 0, LP4 = 1: HP/K2, LP/K1 - m_o3_1 = lp_exec(coeff_k1, m_o2_1, m_o3_1); - m_o4_1 = hp_exec(coeff_k2, m_o3_1, m_o4_1, m_o3_2); - break; - case 2: // LP3 = 1, LP4 = 0: LP/K2, LP/K2 - m_o3_1 = lp_exec(coeff_k2, m_o2_1, m_o3_1); - m_o4_1 = lp_exec(coeff_k2, m_o3_1, m_o4_1); - break; - case 3: // LP3 = 1, LP4 = 1: LP/K2, LP/K1 - m_o3_1 = lp_exec(coeff_k1, m_o2_1, m_o3_1); - m_o4_1 = lp_exec(coeff_k2, m_o3_1, m_o4_1); - break; - } -} - -s32 es550x_shared_core::es550x_filter_t::lp_exec(s32 coeff, s32 in, s32 prev_out) -{ - // Yn = K*(Xn - Yn-1) + Yn-1 - return ((coeff * (in - prev_out)) / 4096) + prev_out; -} - -s32 es550x_shared_core::es550x_filter_t::hp_exec(s32 coeff, s32 in, s32 prev_out, s32 prev_in) -{ - // Yn = Xn - Xn-1 + K*Yn-1 - return in - prev_in + ((coeff * prev_out) / 8192) + (prev_out / 2); -} diff --git a/src/engine/platform/sound/es550x/util.hpp b/src/engine/platform/sound/es550x/util.hpp deleted file mode 100644 index ad85fdf9..00000000 --- a/src/engine/platform/sound/es550x/util.hpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - License: BSD-3-Clause - see https://github.com/cam900/vgsound_emu/blob/vgsound_emu_v1/LICENSE for more details - - Copyright holder(s): cam900 - Modifiers and Contributors for Furnace: cam900 - Various core utilities for vgsound_emu -*/ - -#ifndef _VGSOUND_EMU_CORE_UTIL_HPP -#define _VGSOUND_EMU_CORE_UTIL_HPP - -#pragma once - -#include -#include -#include - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; -typedef signed char s8; -typedef signed short s16; -typedef signed int s32; - -// get bitfield, bitfield(input, position, len) -template T bitfield(T in, u8 pos, u8 len = 1) -{ - return (in >> pos) & (len ? (T(1 << len) - 1) : 1); -} - -// get sign extended value, sign_ext(input, len) -template T sign_ext(T in, u8 len) -{ - len = std::max(0, (8 * sizeof(T)) - len); - return T(T(in) << len) >> len; -} - -// std::clamp is only for C++17 or later; I use my own code -template T clamp(T in, T min, T max) -{ - return std::min(std::max(in, min), max); -} - -template -struct clock_pulse_t -{ - void reset(T init = InitWidth) - { - m_edge.reset(); - m_width = m_width_latch = m_counter = init; - m_cycle = 0; - } - - bool tick(T width = 0) - { - bool carry = ((--m_counter) <= 0); - if (carry) - { - if (!width) - m_width = m_width_latch; - else - m_width = width; // reset width - m_counter = m_width; - m_cycle = 0; - } - else - m_cycle++; - - m_edge.tick(carry); - return carry; - } - - void set_width(T width) { m_width = width; } - void set_width_latch(T width) { m_width_latch = width; } - - // Accessors - bool current_edge() { return m_edge.m_current; } - bool rising_edge() { return m_edge.m_rising; } - bool falling_edge() { return m_edge.m_rising; } - T cycle() { return m_cycle; } - - struct edge_t - { - edge_t() - : m_current(InitEdge ^ 1) - , m_previous(InitEdge) - , m_rising(0) - , m_falling(0) - , m_changed(0) - { - set(InitEdge); - } - - void tick(bool toggle) - { - u8 current = m_current; - if (toggle) - current ^= 1; - set(current); - } - - void set(u8 edge) - { - edge &= 1; - m_rising = m_falling = m_changed = 0; - if (m_current != edge) - { - m_changed = 1; - if (m_current && (!edge)) - m_falling = 1; - else if ((!m_current) && edge) - m_rising = 1; - m_current = edge; - } - m_previous = m_current; - } - - void reset() - { - m_previous = InitEdge; - m_current = InitEdge ^ 1; - set(InitEdge); - } - - u8 m_current : 1; // current edge - u8 m_previous : 1; // previous edge - u8 m_rising : 1; // rising edge - u8 m_falling : 1; // falling edge - u8 m_changed : 1; // changed flag - }; - - edge_t m_edge; - T m_width = InitWidth; // clock pulse width - T m_width_latch = InitWidth; // clock pulse width latch - T m_counter = InitWidth; // clock counter - T m_cycle = 0; // clock cycle -}; - -#endif diff --git a/src/engine/sample.h b/src/engine/sample.h index e3b7743d..3a054304 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -178,12 +178,6 @@ struct DivSample { bool resampleBlep(double rate); bool resampleSinc(double rate); - /** - * check if sample is loopable. - * @return whether it was loopable. - */ - bool isLoopable(); - /** * save this sample to a file. * @param path a path. diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 61dacf89..99b09be6 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -180,6 +180,7 @@ void FurnaceGUI::drawDebug() { ImGui::Text("loopMode: %d ()",(unsigned char)sample->loopMode); } + ImGui::Text("depth: %d",(unsigned char)sample->depth); ImGui::Text("length8: %d",sample->length8); ImGui::Text("length16: %d",sample->length16); ImGui::Text("length1: %d",sample->length1); diff --git a/src/gui/gui.h b/src/gui/gui.h index 2c2418b6..a873f843 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -907,7 +907,7 @@ struct FurnaceGUIMacroDesc { float height; const char* displayName; const char** bitfieldBits; - const char** modeName; + const char* modeName; ImVec4 color; unsigned int bitOffset; bool isBitfield, blockMode, bit30; diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index eb309a50..7ffd1ba3 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -161,9 +161,8 @@ const char* resampleStrats[DIV_RESAMPLE_MAX]={ "best possible" }; -const char* loopMode[DIV_SAMPLE_LOOPMODE_MAX]={ - "Disable", - "Foward", +const char* loopMode[DIV_SAMPLE_LOOP_MAX]={ + "Forward", "Backward", "Pingpong" }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index ce9d111a..7a1ea922 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -247,10 +247,6 @@ const char* n163UpdateBits[8]={ "now", "every waveform changed", NULL }; -const char* es5506FilterModes[4]={ - "HP/K2, HP/K2", "HP/K2, LP/K1", "LP/K2, LP/K2", "LP/K2, LP/K1", -}; - const char* suControlBits[5]={ "ring mod", "low pass", "high pass", "band pass", NULL }; @@ -263,18 +259,6 @@ const char* panBits[3]={ "right", "left", NULL }; -const char* es5506EnvelopeModes[3]={ - "k1 slowdown", "k2 slowdown", NULL -}; - -const char* es5506ControlModes[2]={ - "pause", NULL -}; - -const char* transwaveControlModes[2]={ - "slice", NULL -}; - const char* oneBit[2]={ "on", NULL }; @@ -287,6 +271,10 @@ const char* es5506ControlModes[2]={ "pause", NULL }; +const char* transwaveControlModes[2]={ + "slice", NULL +}; + const int orderedOps[4]={ 0, 2, 1, 3 }; @@ -388,21 +376,17 @@ String macroHoverES5506FilterMode(int id, float val, void* u) { String macroLFOWaves(int id, float val, void* u) { switch (((int)val)&3) { case 0: - mode="Saw"; - break; + return "Saw"; case 1: - mode="Square"; - break; + return "Square"; case 2: - mode="Sine"; - break; + return "Sine"; case 3: - mode="Random"; - break; + return "Random"; default: - break; + return "???"; } - return fmt::sprintf("%d: %s",id,mode); + return "???"; } void addAALine(ImDrawList* dl, const ImVec2& p1, const ImVec2& p2, const ImU32 color, float thickness=1.0f) { @@ -3242,10 +3226,10 @@ void FurnaceGUI::drawInsEdit() { } if (ImGui::BeginTabItem("FM Macros")) { if (ins->type==DIV_INS_OPLL) { - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DC),&ins->std.fmsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DM),&ins->std.amsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DC),&ins->std.fmsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DM),&ins->std.amsMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_ALG),&ins->std.algMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3311,10 +3295,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_WS),&ins->std.opMacros[ordi].wsMacro,0,7,64,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.opMacros[ordi].susMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SUS),&ins->std.opMacros[ordi].susMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else if (ins->type==DIV_INS_OPLL) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3324,10 +3308,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSL),&ins->std.opMacros[ordi].kslMacro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_MULT),&ins->std.opMacros[ordi].multMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_EGS),&ins->std.opMacros[ordi].egtMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_VIB),&ins->std.opMacros[ordi].vibMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_KSR),&ins->std.opMacros[ordi].ksrMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_EGS),&ins->std.opMacros[ordi].egtMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3344,7 +3328,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AM),&ins->std.opMacros[ordi].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); if (ins->type==DIV_INS_FM) { - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,ssgEnvBits)); + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_SSG),&ins->std.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,ssgEnvBits)); } } drawMacros(macroList); @@ -3826,22 +3810,22 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); ImGui::Text("%s",noteNames[60+i]); ImGui::TableNextColumn(); - if (ins->amiga.noteMap[i].ind<0 || ins->amiga.noteMap[i].ind>=e->song.sampleLen) { + if (ins->amiga.noteMap[i].map<0 || ins->amiga.noteMap[i].map>=e->song.sampleLen) { sName="-- empty --"; - ins->amiga.noteMap[i].ind=-1; + ins->amiga.noteMap[i].map=-1; } else { - sName=e->song.sample[ins->amiga.noteMap[i].ind]->name; + sName=e->song.sample[ins->amiga.noteMap[i].map]->name; } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::BeginCombo(fmt::sprintf("##SampleMap_Index_%d",i).c_str(),sName.c_str())) { String id; - if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i].ind==-1)) { PARAMETER - ins->amiga.noteMap[i].ind=-1; + if (ImGui::Selectable("-- empty --",ins->amiga.noteMap[i].map==-1)) { PARAMETER + ins->amiga.noteMap[i].map=-1; } for (int j=0; jsong.sampleLen; j++) { id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.noteMap[i].ind==j)) { PARAMETER - ins->amiga.noteMap[i].ind=j; + if (ImGui::Selectable(id.c_str(),ins->amiga.noteMap[i].map==j)) { PARAMETER + ins->amiga.noteMap[i].map=j; if (ins->amiga.noteMap[i].freq<=0) ins->amiga.noteMap[i].freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); } } @@ -4045,7 +4029,7 @@ void FurnaceGUI::drawInsEdit() { } if (ins->amiga.transWave.enable) { if (ImGui::BeginTabItem("Transwave Macros")) { - macroList.push_back(FurnaceGUIMacroDesc("Transwave control",&ins->std.fbMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,transwaveControlModes)); + macroList.push_back(FurnaceGUIMacroDesc("Transwave control",&ins->std.fbMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,transwaveControlModes)); macroList.push_back(FurnaceGUIMacroDesc("Transwave slice",&ins->std.fmsMacro,0,4095,160,uiColors[GUI_COLOR_MACRO_OTHER])); drawMacros(macroList); ImGui::EndTabItem(); @@ -4833,14 +4817,14 @@ void FurnaceGUI::drawInsEdit() { } if (!panSingleNoBit) { if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { - macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER])); } } } } - macroList.push_back(FurnaceGUIMacroDesc("Pitch",&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,true,macroRelativeMode)); + macroList.push_back(FurnaceGUIMacroDesc("Pitch",&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM || ins->type==DIV_INS_STD || @@ -4873,7 +4857,7 @@ void FurnaceGUI::drawInsEdit() { } if (ex1Max>0) { if (ins->type==DIV_INS_C64) { - macroList.push_back(FurnaceGUIMacroDesc("Filter Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,filtModeBits)); + macroList.push_back(FurnaceGUIMacroDesc("Filter Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,filtModeBits)); } else if (ins->type==DIV_INS_SAA1099) { macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,saaEnvBits)); } else if (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample) { @@ -4900,7 +4884,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_C64) { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_N163) { - macroList.push_back(FurnaceGUIMacroDesc("Wave Update",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,n163UpdateBits)); + macroList.push_back(FurnaceGUIMacroDesc("Wave Update",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,n163UpdateBits)); } else if (ins->type==DIV_INS_FDS) { macroList.push_back(FurnaceGUIMacroDesc("Mod Speed",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_SU) { @@ -4912,12 +4896,12 @@ void FurnaceGUI::drawInsEdit() { } else if (ins->type==DIV_INS_SNES) { macroList.push_back(FurnaceGUIMacroDesc("Gain Rate",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_VOLUME])); } else { - macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,ex2Bit,ayEnvBits)); + macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits)); } } if (ins->type==DIV_INS_C64) { - macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex3Macro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,c64SpecialBits)); - macroList.push_back(FurnaceGUIMacroDesc("Test/Gate",&ins->std.ex4Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex3Macro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,c64SpecialBits)); + macroList.push_back(FurnaceGUIMacroDesc("Test/Gate",&ins->std.ex4Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample)) { macroList.push_back(FurnaceGUIMacroDesc("AutoEnv Num",&ins->std.ex3Macro,0,15,160,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -4925,14 +4909,14 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_AY8930) { // oh my i am running out of macros - macroList.push_back(FurnaceGUIMacroDesc("Noise AND Mask",&ins->std.fbMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); - macroList.push_back(FurnaceGUIMacroDesc("Noise OR Mask",&ins->std.fmsMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Noise AND Mask",&ins->std.fbMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); + macroList.push_back(FurnaceGUIMacroDesc("Noise OR Mask",&ins->std.fmsMacro,0,8,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ins->type==DIV_INS_N163) { macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Wave",&ins->std.ex3Macro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Pos",&ins->std.algMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Len",&ins->std.fbMacro,0,252,160,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Trigger",&ins->std.fmsMacro,0,2,160,uiColors[GUI_COLOR_MACRO_OTHER],false,false,NULL,NULL,true,n163UpdateBits)); + macroList.push_back(FurnaceGUIMacroDesc("WaveLoad Trigger",&ins->std.fmsMacro,0,2,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,n163UpdateBits)); } if (ins->type==DIV_INS_FDS) { macroList.push_back(FurnaceGUIMacroDesc("Mod Position",&ins->std.ex3Macro,0,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 843e356f..a3e65e7c 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -116,16 +116,11 @@ void FurnaceGUI::drawSampleEdit() { sample->loopStart=-1; sample->loopEnd=sample->samples; } - if (sample->loopEnd>sample->samples) { - sample->loopEnd=sample->samples; - } - sample->loopMode=DivSampleLoopMode(mode); updateSampleTex=true; } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Length: %d",sample->samples); - bool doLoop=(sample->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT); if (doLoop) { ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -678,16 +673,11 @@ void FurnaceGUI::drawSampleEdit() { sample->loopStart=-1; sample->loopEnd=sample->samples; } - if (sample->loopEnd>sample->samples) { - sample->loopEnd=sample->samples; - } - sample->loopMode=DivSampleLoopMode(mode); updateSampleTex=true; } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Length: %d",sample->samples); - bool doLoop=(sample->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT); if (doLoop) { ImGui::TableNextRow(); ImGui::TableNextColumn();