From d44f5f0b2b91897250d8c2e750b7796a49003de8 Mon Sep 17 00:00:00 2001 From: cam900 Date: Thu, 11 Aug 2022 22:21:54 +0900 Subject: [PATCH 01/46] Prepare for backward and bi-directional loop --- src/engine/engine.cpp | 20 ++++- src/engine/engine.h | 6 +- src/engine/fileOps.cpp | 8 +- src/engine/platform/amiga.cpp | 10 +-- src/engine/platform/genesis.cpp | 12 +-- src/engine/platform/lynx.cpp | 6 +- src/engine/platform/mmc5.cpp | 8 +- src/engine/platform/nes.cpp | 8 +- src/engine/platform/pce.cpp | 8 +- src/engine/platform/pcmdac.cpp | 10 +-- src/engine/platform/qsound.cpp | 7 +- src/engine/platform/rf5c68.cpp | 4 +- src/engine/platform/segapcm.cpp | 22 ++--- src/engine/platform/su.cpp | 6 +- src/engine/platform/swan.cpp | 8 +- src/engine/platform/vera.cpp | 8 +- src/engine/platform/vrc6.cpp | 8 +- src/engine/platform/zxbeeper.cpp | 4 +- src/engine/playback.cpp | 108 ++++++++++++++++++++--- src/engine/sample.cpp | 146 +++++++++++++++++++++++++------ src/engine/sample.h | 46 +++++++++- src/engine/vgmOps.cpp | 16 ++-- src/gui/debugWindow.cpp | 7 +- src/gui/doAction.cpp | 3 + src/gui/guiConst.cpp | 6 ++ src/gui/guiConst.h | 1 + src/gui/sampleEdit.cpp | 45 ++++++++++ 27 files changed, 418 insertions(+), 123 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index bf55d9d6e..3f24d5a24 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -974,6 +974,7 @@ void DivEngine::renderSamplesP() { void DivEngine::renderSamples() { sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; // step 1: render samples for (int i=0; inotifyPlaybackStop(); } @@ -1914,9 +1918,11 @@ void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) { BUSY_BEGIN; sPreview.pBegin=pStart; sPreview.pEnd=pEnd; + sPreview.dir=false; if (sample<0 || sample>=(int)song.sample.size()) { sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; return; } @@ -1932,6 +1938,7 @@ void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) { sPreview.pos=(sPreview.pBegin>=0)?sPreview.pBegin:0; sPreview.sample=sample; sPreview.wave=-1; + sPreview.dir=false; BUSY_END; } @@ -1939,6 +1946,7 @@ void DivEngine::stopSamplePreview() { BUSY_BEGIN; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; } @@ -1947,6 +1955,7 @@ void DivEngine::previewWave(int wave, int note) { if (wave<0 || wave>=(int)song.wave.size()) { sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; return; } @@ -1962,6 +1971,7 @@ void DivEngine::previewWave(int wave, int note) { sPreview.pos=0; sPreview.sample=-1; sPreview.wave=wave; + sPreview.dir=false; BUSY_END; } @@ -1969,6 +1979,7 @@ void DivEngine::stopWavePreview() { BUSY_BEGIN; sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; BUSY_END; } @@ -2382,6 +2393,7 @@ int DivEngine::addSample() { song.sampleLen=sampleCount+1; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; saveLock.unlock(); renderSamples(); BUSY_END; @@ -2601,13 +2613,16 @@ int DivEngine::addSampleFromFile(const char* path) { inst.detune = inst.detune - 100; short pitch = ((0x3c-inst.basenote)*100) + inst.detune; sample->centerRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0)); - if(inst.loop_count && inst.loops[0].mode == SF_LOOP_FORWARD) + if(inst.loop_count && inst.loops[0].mode >= SF_LOOP_FORWARD) { + sample->loopMode=(DivSampleLoopMode)(inst.loops[0].mode-SF_LOOP_FORWARD); sample->loopStart=inst.loops[0].start; sample->loopEnd=inst.loops[0].end; if(inst.loops[0].end < (unsigned int)sampleCount) sampleCount=inst.loops[0].end; } + else + sample->loop=false; } if (sample->centerRate<4000) sample->centerRate=4000; @@ -2627,6 +2642,7 @@ void DivEngine::delSample(int index) { BUSY_BEGIN; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; saveLock.lock(); if (index>=0 && index<(int)song.sample.size()) { delete song.sample[index]; @@ -2843,6 +2859,7 @@ bool DivEngine::moveSampleUp(int which) { BUSY_BEGIN; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; DivSample* prev=song.sample[which]; saveLock.lock(); song.sample[which]=song.sample[which-1]; @@ -2882,6 +2899,7 @@ bool DivEngine::moveSampleDown(int which) { BUSY_BEGIN; sPreview.sample=-1; sPreview.pos=0; + sPreview.dir=false; DivSample* prev=song.sample[which]; saveLock.lock(); song.sample[which]=song.sample[which+1]; diff --git a/src/engine/engine.h b/src/engine/engine.h index 001ea1941..6d49d710a 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -353,14 +353,16 @@ class DivEngine { struct SamplePreview { int sample; int wave; - unsigned int pos; + int pos; int pBegin, pEnd; + bool dir; SamplePreview(): sample(-1), wave(-1), pos(0), pBegin(-1), - pEnd(-1) {} + pEnd(-1), + dir(false) {} } sPreview; short vibTable[64]; diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 8dcd55d22..76cff9df8 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1669,6 +1669,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { sample->loopStart=reader.readI(); sample->loopEnd=reader.readI(); + sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0); for (int i=0; i<4; i++) { reader.readI(); @@ -1694,6 +1695,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version>=19) { sample->loopStart=reader.readI(); + sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0); } else { reader.readI(); } @@ -1948,6 +1950,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { if (loopLen>=2) { sample->loopStart=loopStart; sample->loopEnd=loopEnd; + sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0); } sample->init(slen); ds.sample.push_back(sample); @@ -2485,6 +2488,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } s->loopStart=sample[i].loopStart*2; s->loopEnd=(sample[i].loopStart+sample[i].loopLen)*2; + s->loop=(s->loopStart>=0)&&(s->loopEnd>=0); reader.read(s->data8,sample[i].len); ds.sample.push_back(s); } @@ -3586,8 +3590,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(0); // reserved w->writeC(0); w->writeC(0); - w->writeI(sample->loopStart); - w->writeI(sample->loopEnd); + w->writeI(sample->loop?sample->loopStart:-1); + w->writeI(sample->loop?sample->loopEnd:-1); for (int i=0; i<4; i++) { w->writeI(0xffffffff); diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 1b0075307..eec6f66c7 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -110,13 +110,13 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le } } else { DivSample* s=parent->getSample(chan[i].sample); - if (s->samples>0) { - if (chan[i].audPossamples) { + if (s->getEndPosition()>0) { + if (chan[i].audPos<(unsigned int)s->getEndPosition()) { writeAudDat(s->data8[chan[i].audPos++]); } - if (s->isLoopable() && chan[i].audPos>=MIN(131071,s->getEndPosition())) { - chan[i].audPos=s->loopStart; - } else if (chan[i].audPos>=MIN(131071,s->samples)) { + if (s->isLoopable() && chan[i].audPos>=MIN(131071,(unsigned int)s->getLoopEndPosition())) { + chan[i].audPos=s->getLoopStartPosition(); + } else if (chan[i].audPos>=MIN(131071,(unsigned int)s->getEndPosition())) { chan[i].sample=-1; } } else { diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index b6dbb8d12..d3c1e6c36 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -154,9 +154,9 @@ void DivPlatformGenesis::processDAC() { if (s->samples>0) { while (chan[i].dacPeriod>=(chipClock/576)) { ++chan[i].dacPos; - if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=s->getEndPosition())) { - chan[i].dacPos=s->loopStart; - } else if (chan[i].dacPos>=s->samples) { + if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition())) { + chan[i].dacPos=s->getLoopStartPosition(); + } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { chan[i].dacSample=-1; chan[i].dacPeriod=0; break; @@ -200,9 +200,9 @@ void DivPlatformGenesis::processDAC() { } } chan[5].dacPos++; - if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=s->getEndPosition())) { - chan[5].dacPos=s->loopStart; - } else if (chan[5].dacPos>=s->samples) { + if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->getLoopEndPosition())) { + chan[5].dacPos=s->getLoopStartPosition(); + } else if (chan[5].dacPos>=(unsigned int)s->getEndPosition()) { chan[5].dacSample=-1; if (parent->song.brokenDACMode) { rWrite(0x2b,0); diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 7c349e5a5..836ce3155 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -158,9 +158,9 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len WRITE_OUTPUT(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7); } - if (s->isLoopable() && chan[i].samplePos>=(int)s->getEndPosition()) { - chan[i].samplePos=s->loopStart; - } else if (chan[i].samplePos>=(int)s->samples) { + if (s->isLoopable() && chan[i].samplePos>=s->getLoopEndPosition()) { + chan[i].samplePos=s->getLoopStartPosition(); + } else if (chan[i].samplePos>=s->getEndPosition()) { chan[i].sample=-1; } } diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 2154e855f..40e2f5c17 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -58,14 +58,14 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len dacPeriod+=dacRate; if (dacPeriod>=rate) { DivSample* s=parent->getSample(dacSample); - if (s->samples>0) { + if (s->getEndPosition()>0) { if (!isMuted[2]) { rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80)); } dacPos++; - if (s->isLoopable() && dacPos>=s->getEndPosition()) { - dacPos=s->loopStart; - } else if (dacPos>=s->samples) { + if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { + dacPos=s->getLoopStartPosition(); + } else if (dacPos>=(unsigned int)s->getEndPosition()) { dacSample=-1; } dacPeriod-=rate; diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index bd1be94a8..d835e3852 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -97,7 +97,7 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) { dacPeriod+=dacRate; \ if (dacPeriod>=rate) { \ DivSample* s=parent->getSample(dacSample); \ - if (s->samples>0) { \ + if (s->getEndPosition()>0) { \ if (!isMuted[4]) { \ unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; \ if (dacAntiClickOn && dacAntiClickisLoopable() && dacPos>=s->getEndPosition()) { \ - dacPos=s->loopStart; \ - } else if (dacPos>=s->samples) { \ + if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { \ + dacPos=s->getLoopStartPosition(); \ + } else if (dacPos>=(unsigned int)s->getEndPosition()) { \ dacSample=-1; \ } \ dacPeriod-=rate; \ diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 5d9a0de88..d71e19146 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -82,7 +82,7 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) chan[i].dacPeriod+=chan[i].dacRate; if (chan[i].dacPeriod>rate) { DivSample* s=parent->getSample(chan[i].dacSample); - if (s->samples<=0) { + if (s->getEndPosition()<=0) { chan[i].dacSample=-1; continue; } @@ -90,9 +90,9 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) chWrite(i,0x04,0xdf); chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3)); chan[i].dacPos++; - if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) { - chan[i].dacPos=s->loopStart; - } else if (chan[i].dacPos>=s->samples) { + if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) { + chan[i].dacPos=s->getLoopStartPosition(); + } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { chan[i].dacSample=-1; } chan[i].dacPeriod-=rate; diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 213cb85a3..67a533b1b 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -49,13 +49,13 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l output=(chan.ws.output[chan.audPos]^0x80)<<8; } else { DivSample* s=parent->getSample(chan.sample); - if (s->samples>0) { - if (s->isLoopable() && chan.audPos>=s->getEndPosition()) { - chan.audPos=s->loopStart; - } else if (chan.audPos>=s->samples) { + if (s->getEndPosition()>0) { + if (s->isLoopable() && chan.audPos>=(unsigned int)s->getLoopEndPosition()) { + chan.audPos=s->getLoopStartPosition(); + } else if (chan.audPos>=(unsigned int)s->getEndPosition()) { chan.sample=-1; } - if (chan.audPossamples) { + if (chan.audPos<(unsigned int)s->getEndPosition()) { output=s->data16[chan.audPos]; } } else { diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 6bc88dbf0..04696f2cf 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -301,16 +301,17 @@ void DivPlatformQSound::tick(bool sysTick) { qsound_bank = 0x8000 | (s->offQSound >> 16); qsound_addr = s->offQSound & 0xffff; - int length = s->getEndPosition(); + int loopStart=s->getLoopStartPosition(); + int length = s->getLoopEndPosition(); if (length > 65536 - 16) { length = 65536 - 16; } - if (s->loopStart == -1 || s->loopStart >= length) { + if (loopStart == -1 || loopStart >= length) { qsound_end = s->offQSound + length + 15; qsound_loop = 15; } else { qsound_end = s->offQSound + length; - qsound_loop = length - s->loopStart; + qsound_loop = length - loopStart; } } if (chan[i].std.arp.had) { diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index e4a39d44e..5b829c348 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -143,7 +143,7 @@ void DivPlatformRF5C68::tick(bool sysTick) { start=start+MIN(chan[i].audPos,s->length8); } if (s->isLoopable()) { - loop=start+s->loopStart; + loop=start+s->getLoopStartPosition(); } start=MIN(start,getSampleMemCapacity()-31); loop=MIN(loop,getSampleMemCapacity()-31); @@ -393,7 +393,7 @@ void DivPlatformRF5C68::renderSamples() { size_t memPos=0; for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; - int length=s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT); + int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT); int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length); if (actualLength>0) { s->offRF5C68=memPos; diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index d66fcce0b..6a63f823b 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -45,7 +45,7 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t for (int i=0; i<16; i++) { if (chan[i].pcm.sample>=0 && chan[i].pcm.samplesong.sampleLen) { DivSample* s=parent->getSample(chan[i].pcm.sample); - if (s->samples<=0) { + if (s->getEndPosition()<=0) { chan[i].pcm.sample=-1; oscBuf[i]->data[oscBuf[i]->needle++]=0; continue; @@ -56,9 +56,9 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR); } chan[i].pcm.pos+=chan[i].pcm.freq; - if (s->isLoopable() && chan[i].pcm.pos>=(s->getEndPosition()<<8)) { - chan[i].pcm.pos=s->loopStart<<8; - } else if (chan[i].pcm.pos>=(s->samples<<8)) { + if (s->isLoopable() && chan[i].pcm.pos>=((unsigned int)s->getLoopEndPosition()<<8)) { + chan[i].pcm.pos=s->getLoopStartPosition()<<8; + } else if (chan[i].pcm.pos>=((unsigned int)s->getEndPosition()<<8)) { chan[i].pcm.sample=-1; } } else { @@ -200,16 +200,17 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].macroInit(ins); if (dumpWrites) { // Sega PCM writes DivSample* s=parent->getSample(chan[c.chan].pcm.sample); - int actualLength=(int)(s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)); + int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); + int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); if (actualLength>0xfeff) actualLength=0xfeff; addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); - if (s->loopStart<0 || s->loopStart>=actualLength) { + if (loopStart<0 || loopStart>=actualLength) { addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); } else { - int loopPos=(s->offSegaPCM&0xffff)+s->loopStart+s->loopOffP; + int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; addWrite(0x10004+(c.chan<<3),loopPos&0xff); addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff); addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3)); @@ -233,16 +234,17 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].furnacePCM=false; if (dumpWrites) { // Sega PCM writes DivSample* s=parent->getSample(chan[c.chan].pcm.sample); - int actualLength=(int)(s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)); + int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); + int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); if (actualLength>65536) actualLength=65536; addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); - if (s->loopStart<0 || s->loopStart>=actualLength) { + if (loopStart<0 || loopStart>=actualLength) { addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); } else { - int loopPos=(s->offSegaPCM&0xffff)+s->loopStart+s->loopOffP; + int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; addWrite(0x10004+(c.chan<<3),loopPos&0xff); addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff); addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3)); diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 6c6b0b329..a212c65fe 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -220,7 +220,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) { DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU); DivSample* sample=parent->getSample(ins->amiga.getSample(chan[i].note)); if (sample!=NULL) { - unsigned int sampleEnd=sample->offSU+(sample->getEndPosition()); + unsigned int sampleEnd=sample->offSU+(sample->getLoopEndPosition()); unsigned int off=sample->offSU+chan[i].hasOffset; chan[i].hasOffset=0; if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1; @@ -229,7 +229,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) { chWrite(i,0x0c,sampleEnd&0xff); chWrite(i,0x0d,sampleEnd>>8); if (sample->isLoopable()) { - unsigned int sampleLoop=sample->offSU+sample->loopStart; + unsigned int sampleLoop=sample->offSU+sample->getLoopStartPosition(); if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1; chWrite(i,0x0e,sampleLoop&0xff); chWrite(i,0x0f,sampleLoop>>8); @@ -603,7 +603,7 @@ void DivPlatformSoundUnit::renderSamples() { for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; if (s->data8==NULL) continue; - int paddedLen=s->samples; + int paddedLen=s->getEndPosition(); if (memPos>=getSampleMemCapacity(0)) { logW("out of PCM memory for sample %d!",i); break; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index b6da23271..5110d7e15 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -78,14 +78,14 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len dacPeriod+=dacRate; while (dacPeriod>rate) { DivSample* s=parent->getSample(dacSample); - if (s->samples<=0) { + if (s->getEndPosition()<=0) { dacSample=-1; continue; } rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80); - if (s->isLoopable() && dacPos>=s->getEndPosition()) { - dacPos=s->loopStart; - } else if (dacPos>=s->samples) { + if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { + dacPos=s->getLoopStartPosition(); + } else if (dacPos>=(unsigned int)s->getEndPosition()) { dacSample=-1; } dacPeriod-=rate; diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 6376cc19e..301091bfc 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -70,7 +70,7 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len size_t pos=start; DivSample* s=parent->getSample(chan[16].pcm.sample); while (len>0) { - if (s->samples>0) { + if (s->getEndPosition()>0) { while (pcm_is_fifo_almost_empty(pcm)) { short tmp_l=0; short tmp_r=0; @@ -96,9 +96,9 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len rWritePCMData(tmp_r&0xff); } chan[16].pcm.pos++; - if (s->isLoopable() && chan[16].pcm.pos>=s->getEndPosition()) { - chan[16].pcm.pos=s->loopStart; - } else if (chan[16].pcm.pos>=s->samples) { + if (s->isLoopable() && chan[16].pcm.pos>=(unsigned int)s->getLoopEndPosition()) { + chan[16].pcm.pos=s->getLoopStartPosition(); + } else if (chan[16].pcm.pos>=(unsigned int)s->getEndPosition()) { chan[16].pcm.sample=-1; break; } diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 8a34d9252..fa81afb91 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -66,7 +66,7 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len chan[i].dacPeriod+=chan[i].dacRate; if (chan[i].dacPeriod>rate) { DivSample* s=parent->getSample(chan[i].dacSample); - if (s->samples<=0) { + if (s->getEndPosition()<=0) { chan[i].dacSample=-1; chWrite(i,0,0); continue; @@ -77,9 +77,9 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len chWrite(i,0,0x80|chan[i].dacOut); } chan[i].dacPos++; - if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) { - chan[i].dacPos=s->loopStart; - } else if (chan[i].dacPos>=s->samples) { + if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) { + chan[i].dacPos=s->getLoopStartPosition(); + } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { chan[i].dacSample=-1; chWrite(i,0,0); } diff --git a/src/engine/platform/zxbeeper.cpp b/src/engine/platform/zxbeeper.cpp index 01702dc5d..dbe21de62 100644 --- a/src/engine/platform/zxbeeper.cpp +++ b/src/engine/platform/zxbeeper.cpp @@ -46,9 +46,9 @@ void DivPlatformZXBeeper::acquire(short* bufL, short* bufR, size_t start, size_t if (curSample>=0 && curSamplesong.sampleLen) { if (--curSamplePeriod<0) { DivSample* s=parent->getSample(curSample); - if (s->samples>0) { + if (s->getEndPosition()>0) { sampleOut=(s->data8[curSamplePos++]>0); - if (curSamplePos>=s->samples) curSample=-1; + if (curSamplePos>=(unsigned int)s->getEndPosition()) curSample=-1; // 256 bits if (curSamplePos>2047) curSample=-1; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 3ba4f1417..d3fa252d6 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -760,6 +760,7 @@ void DivEngine::processRow(int i, bool afterDelay) { sPreview.sample=-1; sPreview.wave=-1; sPreview.pos=0; + sPreview.dir=false; break; } } @@ -1268,26 +1269,109 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi DivSample* s=song.sample[sPreview.sample]; for (size_t i=0; i=s->samples || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { + if (sPreview.pos>=(int)s->samples || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { samp_temp=0; } else { - samp_temp=s->data16[sPreview.pos++]; + samp_temp=s->data16[sPreview.pos]; + if (sPreview.dir) { + sPreview.pos--; + } + else { + sPreview.pos++; + } } blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); samp_prevSample=samp_temp; - if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { - if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) { - sPreview.pos=s->loopStart; + if (sPreview.dir) { // backward + if (sPreview.posgetLoopStartPosition() || (sPreview.pBegin>=0 && sPreview.posisLoopable() && sPreview.posgetLoopEndPosition()) { + switch (s->loopMode) { + case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + default: + break; + } + } + } + } else { // forward + if (sPreview.pos>=s->getLoopEndPosition() || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { + if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + switch (s->loopMode) { + case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + default: + break; + } + } } } } - - if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) { - if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) { - sPreview.pos=s->loopStart; - } else if (sPreview.pos>=s->samples) { - sPreview.sample=-1; + if (sPreview.dir) { // backward + if (sPreview.pos<=s->getLoopStartPosition() || (sPreview.pBegin>=0 && sPreview.pos<=sPreview.pBegin)) { + if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + switch (s->loopMode) { + case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + default: + break; + } + } else if (sPreview.pos<0) { + sPreview.sample=-1; + } + } + } else { // forward + if (sPreview.pos>=s->getLoopEndPosition() || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { + if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + switch (s->loopMode) { + case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: + sPreview.pos=s->getLoopStartPosition(); + sPreview.dir=false; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: + sPreview.pos=s->getLoopEndPosition()-1; + sPreview.dir=true; + break; + default: + break; + } + } else if (sPreview.pos>=s->getEndPosition()) { + sPreview.sample=-1; + } } } } else if (sPreview.wave>=0 && sPreview.wave<(int)song.wave.size()) { @@ -1298,7 +1382,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } else { samp_temp=((MIN(wave->data[sPreview.pos],wave->max)<<14)/wave->max)-8192; } - if (++sPreview.pos>=(unsigned int)wave->len) { + if (++sPreview.pos>=wave->len) { sPreview.pos=0; } blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 60eb35bb2..5697176cd 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -39,57 +39,143 @@ DivSampleHistory::~DivSampleHistory() { } bool DivSample::isLoopable() { - return (loopStart>=0 && loopStartloopStart && loopEnd<=(int)samples); + return loop && ((loopStart>=0 && loopStartloopStart && loopEnd<=(int)samples)); } -unsigned int DivSample::getEndPosition(DivSampleDepth depth) { - int end=loopEnd; - unsigned int len=samples; +int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) { + if ((length==0) || (offset==length)) { + int off=offset; + switch (depth) { + case DIV_SAMPLE_DEPTH_1BIT: + off=(offset+7)/8; + break; + case DIV_SAMPLE_DEPTH_1BIT_DPCM: + off=(offset+7)/8; + break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: + off=(offset+1)/2; + break; + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: + off=(offset+1)/2; + break; + case DIV_SAMPLE_DEPTH_ADPCM_A: + off=(offset+1)/2; + break; + case DIV_SAMPLE_DEPTH_ADPCM_B: + off=(offset+1)/2; + break; + case DIV_SAMPLE_DEPTH_8BIT: + off=offset; + break; + case DIV_SAMPLE_DEPTH_BRR: + off=9*((offset+15)/16); + break; + case DIV_SAMPLE_DEPTH_VOX: + off=(offset+1)/2; + break; + case DIV_SAMPLE_DEPTH_16BIT: + off=offset*2; + break; + default: + break; + } + return off; + } else { + int off=offset; + int len=length; + switch (depth) { + case DIV_SAMPLE_DEPTH_1BIT: + off=(offset+7)/8; + len=(length+7)/8; + break; + case DIV_SAMPLE_DEPTH_1BIT_DPCM: + off=(offset+7)/8; + len=(length+7)/8; + break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: + off=(offset+1)/2; + len=(length+1)/2; + break; + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: + off=(offset+1)/2; + len=(length+1)/2; + break; + case DIV_SAMPLE_DEPTH_ADPCM_A: + off=(offset+1)/2; + len=(length+1)/2; + break; + case DIV_SAMPLE_DEPTH_ADPCM_B: + off=(offset+1)/2; + len=(length+1)/2; + break; + case DIV_SAMPLE_DEPTH_8BIT: + off=offset; + len=length; + break; + case DIV_SAMPLE_DEPTH_BRR: + off=9*((offset+15)/16); + len=9*((length+15)/16); + break; + case DIV_SAMPLE_DEPTH_VOX: + off=(offset+1)/2; + len=(length+1)/2; + break; + case DIV_SAMPLE_DEPTH_16BIT: + off=offset*2; + len=length*2; + break; + default: + break; + } + return isLoopable()?off:len; + } +} + +int DivSample::getLoopStartPosition(DivSampleDepth depth) { + return getSampleOffset(loopStart,0,depth); +} + +int DivSample::getLoopEndPosition(DivSampleDepth depth) { + return getSampleOffset(loopEnd,samples,depth); +} + +int DivSample::getEndPosition(DivSampleDepth depth) { + int off=samples; switch (depth) { case DIV_SAMPLE_DEPTH_1BIT: - end=(loopEnd+7)/8; - len=length1; + off=length1; break; case DIV_SAMPLE_DEPTH_1BIT_DPCM: - end=(loopEnd+7)/8; - len=lengthDPCM; + off=lengthDPCM; break; case DIV_SAMPLE_DEPTH_YMZ_ADPCM: - end=(loopEnd+1)/2; - len=lengthZ; + off=lengthZ; break; case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: - end=(loopEnd+1)/2; - len=lengthQSoundA; + off=lengthQSoundA; break; case DIV_SAMPLE_DEPTH_ADPCM_A: - end=(loopEnd+1)/2; - len=lengthA; + off=lengthA; break; case DIV_SAMPLE_DEPTH_ADPCM_B: - end=(loopEnd+1)/2; - len=lengthB; + off=lengthB; break; case DIV_SAMPLE_DEPTH_8BIT: - end=loopEnd; - len=length8; + off=length8; break; case DIV_SAMPLE_DEPTH_BRR: - end=9*((loopEnd+15)/16); - len=lengthBRR; + off=lengthBRR; break; case DIV_SAMPLE_DEPTH_VOX: - end=(loopEnd+1)/2; - len=lengthVOX; + off=lengthVOX; break; case DIV_SAMPLE_DEPTH_16BIT: - end=loopEnd*2; - len=length16; + off=length16; break; default: break; } - return isLoopable()?end:len; + return off; } void DivSample::setSampleCount(unsigned int count) { @@ -138,7 +224,7 @@ bool DivSample::save(const char* path) { if(isLoopable()) { inst.loop_count = 1; - inst.loops[0].mode = SF_LOOP_FORWARD; + inst.loops[0].mode = (int)loopMode+SF_LOOP_FORWARD; inst.loops[0].start = loopStart; inst.loops[0].end = loopEnd; } @@ -895,9 +981,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { duplicate=new unsigned char[getCurBufLen()]; memcpy(duplicate,getCurBuf(),getCurBufLen()); } - h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd); + h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd,loop,loopMode); } else { - h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd); + h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,loopMode); } if (!doNotPush) { while (!redoHist.empty()) { @@ -928,7 +1014,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { rate=h->rate; \ centerRate=h->centerRate; \ loopStart=h->loopStart; \ - loopEnd=h->loopEnd; + loopEnd=h->loopEnd; \ + loop=h->loop; \ + loopMode=h->loopMode; int DivSample::undo() { diff --git a/src/engine/sample.h b/src/engine/sample.h index 103bcaa27..05c97ac83 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -25,6 +25,13 @@ #include "../ta-utils.h" #include +enum DivSampleLoopMode: unsigned char { + DIV_SAMPLE_LOOP_FORWARD=0, + DIV_SAMPLE_LOOP_BACKWARD, + DIV_SAMPLE_LOOP_PINGPONG, + DIV_SAMPLE_LOOP_MAX // boundary for loop mode +}; + enum DivSampleDepth: unsigned char { DIV_SAMPLE_DEPTH_1BIT=0, DIV_SAMPLE_DEPTH_1BIT_DPCM=1, @@ -53,8 +60,10 @@ struct DivSampleHistory { unsigned int length, samples; DivSampleDepth depth; int rate, centerRate, loopStart, loopEnd; + bool loop; + DivSampleLoopMode loopMode; bool hasSample; - DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le): + DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le, bool lp, DivSampleLoopMode lm): data((unsigned char*)d), length(l), samples(s), @@ -63,8 +72,10 @@ struct DivSampleHistory { centerRate(cr), loopStart(ls), loopEnd(le), + loop(lp), + loopMode(lm), hasSample(true) {} - DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le): + DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le, bool lp, DivSampleLoopMode lm): data(NULL), length(0), samples(0), @@ -73,6 +84,8 @@ struct DivSampleHistory { centerRate(cr), loopStart(ls), loopEnd(le), + loop(lp), + loopMode(lm), hasSample(false) {} ~DivSampleHistory(); }; @@ -92,6 +105,13 @@ struct DivSample { // - 10: VOX ADPCM // - 16: 16-bit PCM DivSampleDepth depth; + bool loop; + // valid values are: + // - 0: No loop + // - 1: Forward loop + // - 2: Backward loop + // - 3: Pingpong loop + DivSampleLoopMode loopMode; // these are the new data structures. signed char* data8; // 8 @@ -120,11 +140,29 @@ struct DivSample { */ bool isLoopable(); + /** + * get sample start position + * @return the samples start position. + */ + int getLoopStartPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); + + /** + * get sample loop end position + * @return the samples loop end position. + */ + int getLoopEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); + /** * get sample end position * @return the samples end position. */ - unsigned int getEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); + int getEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); + + /** + * get sample offset + * @return the sample offset. + */ + int getSampleOffset(int offset, int length, DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX); /** * @warning DO NOT USE - internal functions @@ -253,6 +291,8 @@ struct DivSample { loopEnd(-1), loopOffP(0), depth(DIV_SAMPLE_DEPTH_16BIT), + loop(false), + loopMode(DIV_SAMPLE_LOOP_FORWARD), data8(NULL), data16(NULL), data1(NULL), diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 15de0156f..51948f27f 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -511,7 +511,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(0x95); w->writeC(streamID); w->writeS(write.val); // sample number - w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags + w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0)|(sampleDir[streamID]?0x10:0)); // flags if (sample->isLoopable() && !sampleDir[streamID]) { loopTimer[streamID]=sample->length8; loopSample[streamID]=write.val; @@ -1549,7 +1549,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p size_t memPos=0; for (int i=0; igetEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff); + unsigned int alignedSize=(sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff); if (alignedSize>65536) alignedSize=65536; if ((memPos&0xff0000)!=((memPos+alignedSize)&0xff0000)) { memPos=(memPos+0xffff)&0xff0000; @@ -1559,9 +1559,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p sample->offSegaPCM=memPos; unsigned int readPos=0; for (unsigned int j=0; j=sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { + if (readPos>=sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { if (sample->isLoopable()) { - readPos=sample->loopStart; + readPos=sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80); } else { pcmMem[memPos++]=0x80; @@ -1572,7 +1572,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p readPos++; if (memPos>=16777216) break; } - sample->loopOffP=readPos-sample->loopStart; + sample->loopOffP=readPos-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); if (memPos>=16777216) break; } @@ -1897,12 +1897,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p if (loopSample[nextToTouch]loopStart<(int)sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { + if (sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { w->writeC(0x93); w->writeC(nextToTouch); - w->writeI(sample->off8+sample->loopStart); + w->writeI(sample->off8+sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)); w->writeC(0x81); - w->writeI(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->loopStart); + w->writeI(sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)); } } loopSample[nextToTouch]=-1; diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 6ad2ddddf..58dfac399 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -157,10 +157,11 @@ void FurnaceGUI::drawDebug() { ImGui::Text("loopStart: %d",sample->loopStart); ImGui::Text("loopEnd: %d", sample->loopEnd); ImGui::Text("loopOffP: %d",sample->loopOffP); - if (sampleDepths[sample->depth]!=NULL) { - ImGui::Text("depth: %d (%s)",(unsigned char)sample->depth,sampleDepths[sample->depth]); + ImGui::Text(sample->loop?"loop: Enabled":"loop: Disabled"); + if (sampleLoopModes[sample->loopMode]!=NULL) { + ImGui::Text("loopMode: %d (%s)",(unsigned char)sample->loopMode,sampleLoopModes[sample->loopMode]); } else { - ImGui::Text("depth: %d ()",(unsigned char)sample->depth); + ImGui::Text("loopMode: %d ()",(unsigned char)sample->loopMode); } ImGui::Text("length8: %d",sample->length8); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index ca640d627..48780dcc2 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -710,6 +710,8 @@ void FurnaceGUI::doAction(int what) { sample->name=prevSample->name; sample->loopStart=prevSample->loopStart; sample->loopEnd=prevSample->loopEnd; + sample->loop=prevSample->loop; + sample->loopMode=prevSample->loopMode; sample->depth=prevSample->depth; if (sample->init(prevSample->samples)) { if (prevSample->getCurBuf()!=NULL) { @@ -1264,6 +1266,7 @@ void FurnaceGUI::doAction(int what) { sample->loopStart=start; sample->loopEnd=end; + sample->loop=true; updateSampleTex=true; e->renderSamples(); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 59c917ae0..da86ce86a 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -116,6 +116,12 @@ const char* insTypes[DIV_INS_MAX+1]={ NULL }; +const char* sampleLoopModes[DIV_SAMPLE_LOOP_MAX]={ + "Forward", + "Backward", + "Ping pong" +}; + const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={ "1-bit PCM", "1-bit DPCM", diff --git a/src/gui/guiConst.h b/src/gui/guiConst.h index a6df68f62..d6824efb8 100644 --- a/src/gui/guiConst.h +++ b/src/gui/guiConst.h @@ -40,6 +40,7 @@ extern const char* noteNames[180]; extern const char* noteNamesG[180]; extern const char* pitchLabel[11]; extern const char* insTypes[]; +extern const char* sampleLoopModes[]; extern const char* sampleDepths[]; extern const char* resampleStrats[]; extern const int availableSystems[]; diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index e9b5cfb35..ff3072109 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -46,6 +46,12 @@ void FurnaceGUI::drawSampleEdit() { sampleType=sampleDepths[sample->depth]; } } + String loopType="Invalid"; + if (sample->loopModeloopMode]!=NULL) { + loopType=sampleLoopModes[sample->loopMode]; + } + } if (!settings.sampleLayout) { ImGui::Text("Name"); ImGui::SameLine(); @@ -96,9 +102,11 @@ void FurnaceGUI::drawSampleEdit() { bool doLoop=(sample->isLoopable()); if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED if (doLoop) { + sample->loop=true; sample->loopStart=0; sample->loopEnd=sample->samples; } else { + sample->loop=false; sample->loopStart=-1; sample->loopEnd=sample->samples; } @@ -107,6 +115,23 @@ void FurnaceGUI::drawSampleEdit() { if (doLoop) { ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::Text("Loop Mode"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##SampleLoopMode",loopType.c_str())) { + for (int i=0; iprepareUndo(true); + sample->loopMode=(DivSampleLoopMode)i; + e->renderSamplesP(); + updateSampleTex=true; + MARK_MODIFIED; + } + } + ImGui::EndCombo(); + } + ImGui::TableNextColumn(); ImGui::Text("Loop Start"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -631,15 +656,35 @@ void FurnaceGUI::drawSampleEdit() { bool doLoop=(sample->isLoopable()); if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED if (doLoop) { + sample->loop=true; sample->loopStart=0; sample->loopEnd=sample->samples; } else { + sample->loop=false; sample->loopStart=-1; sample->loopEnd=sample->samples; } updateSampleTex=true; } if (doLoop) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Loop Mode"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##SampleLoopMode",loopType.c_str())) { + for (int i=0; iprepareUndo(true); + sample->loopMode=(DivSampleLoopMode)i; + e->renderSamplesP(); + updateSampleTex=true; + MARK_MODIFIED; + } + } + ImGui::EndCombo(); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Loop Start"); From 4cc79fb49ddb24ca428a618fea7779915b9e546f Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 16:27:36 +0900 Subject: [PATCH 02/46] Prepare for split sample chip instrument (MSM6258, MSM6295, QSound, Sega PCM, ADPCM-A, ADPCM-B, YMZ280B, RF5C68) Instrument color and icons are placeholder. different volume range, hard panned/soft panned and/or independent volume per output, chip-dependent features (global volume, echo, etc) Allow use sample in instrument tab for chip with sample support Prepare to support X1-010 Seta 2 style bankswitch behavior Prepare to support AY89x0 PCM DAC Support volume for PCE sample (DAC) Fix Lynx, Y8950 sample pitch matches to sample preview Support PCM DAC with backward and pingpong loop mode Reduce some codes Add Sega PCM, AY89x0, QSound, PCM DAC, Lynx per-channel debug support --- src/engine/dispatch.h | 3 + src/engine/instrument.cpp | 4 +- src/engine/instrument.h | 80 +++- src/engine/platform/ay.cpp | 267 ++++++++--- src/engine/platform/ay.h | 76 +++- src/engine/platform/ay8930.cpp | 220 +++++++-- src/engine/platform/ay8930.h | 76 +++- src/engine/platform/lynx.cpp | 26 +- src/engine/platform/lynx.h | 4 +- src/engine/platform/msm6258.cpp | 56 ++- src/engine/platform/msm6295.cpp | 33 +- src/engine/platform/msm6295.h | 4 +- src/engine/platform/opl.cpp | 67 +-- src/engine/platform/opl.h | 4 +- src/engine/platform/pce.cpp | 36 +- src/engine/platform/pce.h | 7 +- src/engine/platform/pcmdac.cpp | 72 ++- src/engine/platform/pcmdac.h | 4 +- src/engine/platform/qsound.cpp | 58 ++- src/engine/platform/qsound.h | 14 +- src/engine/platform/rf5c68.cpp | 11 +- src/engine/platform/rf5c68.h | 4 +- src/engine/platform/segapcm.cpp | 122 ++--- src/engine/platform/segapcm.h | 12 +- src/engine/platform/su.cpp | 6 +- src/engine/platform/swan.cpp | 4 +- src/engine/platform/vrc6.cpp | 23 +- src/engine/platform/x1_010.cpp | 104 +++-- src/engine/platform/x1_010.h | 32 +- src/engine/platform/ym2608.cpp | 154 +++++-- src/engine/platform/ym2608.h | 5 +- src/engine/platform/ym2610.cpp | 507 ++++++++++----------- src/engine/platform/ym2610.h | 97 +--- src/engine/platform/ym2610Interface.cpp | 4 +- src/engine/platform/ym2610b.cpp | 421 ++++++++++-------- src/engine/platform/ym2610b.h | 69 +-- src/engine/platform/ym2610bext.cpp | 138 +++--- src/engine/platform/ym2610bext.h | 14 +- src/engine/platform/ym2610ext.cpp | 134 +++--- src/engine/platform/ym2610ext.h | 14 +- src/engine/platform/ym2610shared.h | 315 +++++++++++++ src/engine/platform/ymz280b.cpp | 16 +- src/engine/platform/ymz280b.h | 7 +- src/engine/playback.cpp | 3 + src/engine/sysDef.cpp | 50 ++- src/gui/dataList.cpp | 32 ++ src/gui/debug.cpp | 214 +++++++++ src/gui/gui.h | 8 + src/gui/guiConst.cpp | 18 +- src/gui/insEdit.cpp | 563 ++++++++++++++++++------ src/gui/intConst.cpp | 3 + src/gui/intConst.h | 3 + src/gui/settings.cpp | 11 +- 53 files changed, 2928 insertions(+), 1301 deletions(-) create mode 100644 src/engine/platform/ym2610shared.h diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index fb9be5800..496369433 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -165,6 +165,7 @@ enum DivDispatchCmds { DIV_CMD_X1_010_ENVELOPE_PERIOD, DIV_CMD_X1_010_ENVELOPE_SLIDE, DIV_CMD_X1_010_AUTO_ENVELOPE, + DIV_CMD_X1_010_SAMPLE_BANK_SLOT, DIV_CMD_WS_SWEEP_TIME, DIV_CMD_WS_SWEEP_AMOUNT, @@ -189,6 +190,8 @@ enum DivDispatchCmds { DIV_CMD_SU_SYNC_PERIOD_LOW, DIV_CMD_SU_SYNC_PERIOD_HIGH, + DIV_CMD_ADPCMA_GLOBAL_VOLUME, + DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol DIV_CMD_MAX diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 555d7d17f..d5262a622 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -529,7 +529,7 @@ void DivInstrument::putInsData(SafeWriter* w) { } // Sound Unit - w->writeC(su.useSample); + w->writeC(amiga.useSample); w->writeC(su.switchRoles); // GB hardware sequence @@ -1092,7 +1092,7 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { // Sound Unit if (version>=104) { - su.useSample=reader.readC(); + amiga.useSample=reader.readC(); su.switchRoles=reader.readC(); } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index df7a6b361..bab20ddf4 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -60,6 +60,14 @@ enum DivInstrumentType: unsigned short { DIV_INS_SU=30, DIV_INS_NAMCO=31, DIV_INS_OPL_DRUMS=32, + DIV_INS_MSM6258=33, + DIV_INS_MSM6295=34, + DIV_INS_ADPCMA=35, + DIV_INS_ADPCMB=36, + DIV_INS_SEGAPCM=37, + DIV_INS_QSOUND=38, + DIV_INS_YMZ280B=39, + DIV_INS_RF5C68=40, DIV_INS_MAX, DIV_INS_NULL }; @@ -335,6 +343,7 @@ struct DivInstrumentAmiga { }; short initSample; bool useNoteMap; + bool useSample; bool useWave; unsigned char waveLen; SampleMap noteMap[120]; @@ -368,6 +377,7 @@ struct DivInstrumentAmiga { DivInstrumentAmiga(): initSample(0), useNoteMap(false), + useSample(false), useWave(false), waveLen(31) { for (SampleMap& elem: noteMap) { @@ -376,6 +386,13 @@ struct DivInstrumentAmiga { } }; +struct DivInstrumentX1_010 { + int bankSlot; + + DivInstrumentX1_010(): + bankSlot(0) {} +}; + struct DivInstrumentN163 { int wave, wavePos, waveLen; unsigned char waveMode; @@ -458,13 +475,69 @@ struct DivInstrumentWaveSynth { }; struct DivInstrumentSoundUnit { - bool useSample; bool switchRoles; DivInstrumentSoundUnit(): - useSample(false), switchRoles(false) {} }; +struct DivInstrumentES5506 { + struct Filter { + enum FilterMode: unsigned char { // filter mode for pole 4,3 + FILTER_MODE_HPK2_HPK2=0, + FILTER_MODE_HPK2_LPK1, + FILTER_MODE_LPK2_LPK2, + FILTER_MODE_LPK2_LPK1, + }; + FilterMode mode; + unsigned short k1, k2; + Filter(): + mode(FILTER_MODE_LPK2_LPK1), + k1(0xffff), + k2(0xffff) {} + }; + struct Envelope { + unsigned short ecount; + signed char lVRamp, rVRamp; + signed char k1Ramp, k2Ramp; + bool k1Slow, k2Slow; + Envelope(): + ecount(0), + lVRamp(0), + rVRamp(0), + k1Ramp(0), + k2Ramp(0), + k1Slow(false), + k2Slow(false) {} + }; + Filter filter; + Envelope envelope; + DivInstrumentES5506(): + filter(Filter()), + envelope(Envelope()) {} +}; + +struct DivInstrumentSNES { + enum GainMode: unsigned char { + GAIN_MODE_DIRECT=0, + GAIN_MODE_DEC_LINEAR=4, + GAIN_MODE_DEC_LOG=5, + GAIN_MODE_INC_LINEAR=6, + GAIN_MODE_INC_INVLOG=7 + }; + bool useEnv; + GainMode gainMode; + unsigned char gain; + unsigned char a, d, s, r; + DivInstrumentSNES(): + useEnv(true), + gainMode(GAIN_MODE_DIRECT), + gain(127), + a(15), + d(7), + s(7), + r(0) {} +}; + struct DivInstrument { String name; bool mode; @@ -474,11 +547,14 @@ struct DivInstrument { DivInstrumentGB gb; DivInstrumentC64 c64; DivInstrumentAmiga amiga; + DivInstrumentX1_010 x1_010; DivInstrumentN163 n163; DivInstrumentFDS fds; DivInstrumentMultiPCM multipcm; DivInstrumentWaveSynth ws; DivInstrumentSoundUnit su; + DivInstrumentES5506 es5506; + DivInstrumentSNES snes; /** * save the instrument to a SafeWriter. diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 8df5bd4ce..c9d059722 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -117,6 +117,46 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l ayBuf[i]=new short[ayBufLen]; } } + // PCM part + for (int i=0; i<3; i++) { + if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { + chan[i].dac.period+=chan[i].dac.rate; + bool end=false; + bool changed=false; + int prev_out = chan[i].dac.out; + while (chan[i].dac.period>rate && !end) { + DivSample* s=parent->getSample(chan[i].dac.sample); + if (s->getEndPosition()<=0) { + chan[i].dac.sample=-1; + rWrite(0x08+i,0); + end=true; + break; + } + unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>4); + chan[i].dac.out=MAX(0,MIN(15,(dacData*chan[i].outVol)/15)); + if (prev_out!=chan[i].dac.out) { + prev_out=chan[i].dac.out; + changed=true; + } + chan[i].dac.pos++; + if (s->isLoopable() && chan[i].dac.pos>=s->getLoopEndPosition()) { + chan[i].dac.pos=s->getLoopStartPosition(); + } else if (chan[i].dac.pos>=s->getEndPosition()) { + chan[i].dac.sample=-1; + rWrite(0x08+i,0); + end=true; + break; + } + chan[i].dac.period-=rate; + } + if (changed && !end) { + if (!isMuted[i]) { + rWrite(0x08+i,chan[i].dac.out); + } + } + } + } + while (!writes.empty()) { QueuedWrite w=writes.front(); if (intellivision) { @@ -157,22 +197,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l void DivPlatformAY8910::updateOutSel(bool immediate) { if (immediate) { immWrite(0x07, - ~((chan[0].psgMode&1)| - ((chan[1].psgMode&1)<<1)| - ((chan[2].psgMode&1)<<2)| - ((chan[0].psgMode&2)<<2)| - ((chan[1].psgMode&2)<<3)| - ((chan[2].psgMode&2)<<4)| + ~((chan[0].psgMode.getTone())| + ((chan[1].psgMode.getTone())<<1)| + ((chan[2].psgMode.getTone())<<2)| + ((chan[0].psgMode.getNoise())<<2)| + ((chan[1].psgMode.getNoise())<<3)| + ((chan[2].psgMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } else { rWrite(0x07, - ~((chan[0].psgMode&1)| - ((chan[1].psgMode&1)<<1)| - ((chan[2].psgMode&1)<<2)| - ((chan[0].psgMode&2)<<2)| - ((chan[1].psgMode&2)<<3)| - ((chan[2].psgMode&2)<<4)| + ~((chan[0].psgMode.getTone())| + ((chan[1].psgMode.getTone())<<1)| + ((chan[2].psgMode.getTone())<<2)| + ((chan[0].psgMode.getNoise())<<2)| + ((chan[1].psgMode.getNoise())<<3)| + ((chan[2].psgMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } @@ -185,12 +225,14 @@ void DivPlatformAY8910::tick(bool sysTick) { if (chan[i].std.vol.had) { chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); if (chan[i].outVol<0) chan[i].outVol=0; - if (isMuted[i]) { - rWrite(0x08+i,0); - } else if (intellivision && (chan[i].psgMode&4)) { - rWrite(0x08+i,(chan[i].outVol&0xc)<<2); - } else { - rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2)); + if (!chan[i].psgMode.dac) { + if (isMuted[i]) { + rWrite(0x08+i,0); + } else if (intellivision && (chan[i].psgMode.getEnvelope())) { + rWrite(0x08+i,(chan[i].outVol&0xc)<<2); + } else { + rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode.getEnvelope())<<2)); + } } } if (chan[i].std.arp.had) { @@ -212,13 +254,15 @@ void DivPlatformAY8910::tick(bool sysTick) { rWrite(0x06,31-chan[i].std.duty.val); } if (chan[i].std.wave.had) { - chan[i].psgMode=(chan[i].std.wave.val+1)&7; - if (isMuted[i]) { - rWrite(0x08+i,0); - } else if (intellivision && (chan[i].psgMode&4)) { - rWrite(0x08+i,(chan[i].outVol&0xc)<<2); - } else { - rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2)); + if (!chan[i].psgMode.dac) { + chan[i].psgMode=(chan[i].std.wave.val+1)&7; + if (isMuted[i]) { + rWrite(0x08+i,0); + } else if (intellivision && (chan[i].psgMode.getEnvelope())) { + rWrite(0x08+i,(chan[i].outVol&0xc)<<2); + } else { + rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode.getEnvelope())<<2)); + } } } if (chan[i].std.pitch.had) { @@ -232,6 +276,20 @@ void DivPlatformAY8910::tick(bool sysTick) { } if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { + if (chan[i].psgMode.dac) { + if (dumpWrites) addWrite(0xffff0002+(i<<8),0); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AY); + chan[i].dac.sample=ins->amiga.getSample(chan[i].note); + if (chan[i].dac.sample<0 || chan[i].dac.sample>=parent->song.sampleLen) { + if (dumpWrites) { + rWrite(0x08+i,0); + addWrite(0xffff0000+(i<<8),chan[i].dac.sample); + } + chan[i].dac.pos=0; + chan[i].dac.period=0; + chan[i].keyOn=true; + } + } oldWrites[0x08+i]=-1; oldWrites[0x0d]=-1; } @@ -252,6 +310,19 @@ void DivPlatformAY8910::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); + if (chan[i].dac.furnaceDAC) { + double off=1.0; + if (chan[i].dac.sample>=0 && chan[i].dac.samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[i].dac.sample); + if (s->centerRate<1) { + off=1.0; + } else { + off=8363.0/(double)s->centerRate; + } + } + chan[i].dac.rate=((double)chipClock*4096.0)/(double)(MAX(1,off*chan[i].freq)); + if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate); + } if (chan[i].freq>4095) chan[i].freq=4095; if (chan[i].keyOn) { //rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); @@ -307,6 +378,62 @@ int DivPlatformAY8910::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY); + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + chan[c.chan].psgMode.dac=true; + } else if (chan[c.chan].dac.furnaceDAC) { + chan[c.chan].psgMode.dac=false; + } + if (chan[c.chan].psgMode.dac) { + if (skipRegisterWrites) break; + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + chan[c.chan].dac.sample=ins->amiga.getSample(c.value); + if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) { + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; + } else { + if (dumpWrites) { + rWrite(0x08+c.chan,0); + addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); + } + } + chan[c.chan].dac.pos=0; + chan[c.chan].dac.period=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].macroInit(ins); + if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + //chan[c.chan].keyOn=true; + chan[c.chan].dac.furnaceDAC=true; + } else { + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + } + chan[c.chan].dac.sample=12*sampleBank+chan[c.chan].note%12; + if (chan[c.chan].dac.sample>=parent->song.sampleLen) { + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; + } else { + if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); + } + chan[c.chan].dac.pos=0; + chan[c.chan].dac.period=0; + chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate; + if (dumpWrites) { + rWrite(0x08+c.chan,0); + addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate); + } + chan[c.chan].dac.furnaceDAC=false; + } + break; + } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; @@ -318,16 +445,21 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else if (intellivision && (chan[c.chan].psgMode&4)) { - rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); - } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2)); + if (!chan[c.chan].psgMode.dac) { + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { + rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); + } else { + rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); + } } break; } case DIV_CMD_NOTE_OFF: + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + chan[c.chan].psgMode.dac=false; chan[c.chan].keyOff=true; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); @@ -341,14 +473,16 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else { - if (chan[c.chan].active) { - if (intellivision && (chan[c.chan].psgMode&4)) { - rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); - } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2)); + if (!chan[c.chan].psgMode.dac) { + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else { + if (chan[c.chan].active) { + if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { + rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); + } else { + rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); + } } } } @@ -398,15 +532,17 @@ int DivPlatformAY8910::dispatch(DivCommand c) { break; } case DIV_CMD_STD_NOISE_MODE: - if (c.value<16) { - chan[c.chan].psgMode=(c.value+1)&7; - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else if (chan[c.chan].active) { - if (intellivision && (chan[c.chan].psgMode&4)) { - rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2); - } else { - rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode&4)<<2)); + if (!chan[c.chan].psgMode.dac) { + if (c.value<16) { + chan[c.chan].psgMode=(c.value+1)&7; + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else if (chan[c.chan].active) { + if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { + rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2); + } else { + rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); + } } } } @@ -418,16 +554,16 @@ int DivPlatformAY8910::dispatch(DivCommand c) { ayEnvMode=c.value>>4; rWrite(0x0d,ayEnvMode); if (c.value&15) { - chan[c.chan].psgMode|=4; + chan[c.chan].psgMode.envelope|=1; } else { - chan[c.chan].psgMode&=~4; + chan[c.chan].psgMode.envelope&=~1; } if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); - } else if (intellivision && (chan[c.chan].psgMode&4)) { + } else if (intellivision && (chan[c.chan].psgMode.getEnvelope())) { rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2); } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2)); + rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2)); } break; case DIV_CMD_AY_ENVELOPE_LOW: @@ -464,6 +600,15 @@ int DivPlatformAY8910::dispatch(DivCommand c) { updateOutSel(true); immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); break; + case DIV_CMD_SAMPLE_MODE: + chan[c.chan].psgMode.dac=(c.value>0)?1:0; + break; + case DIV_CMD_SAMPLE_BANK: + sampleBank=c.value; + if (sampleBank>(parent->song.sample.size()/12)) { + sampleBank=parent->song.sample.size()/12; + } + break; case DIV_ALWAYS_SET_VOLUME: return 0; break; @@ -492,10 +637,14 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) { isMuted[ch]=mute; if (isMuted[ch]) { rWrite(0x08+ch,0); - } else if (intellivision && (chan[ch].psgMode&4) && chan[ch].active) { - rWrite(0x08+ch,(chan[ch].vol&0xc)<<2); - } else if (chan[ch].active) { - rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode&4)<<2)); + } else if (chan[ch].active && chan[ch].psgMode.dac) { + rWrite(0x08+ch,chan[ch].dac.out); + } else { + if (intellivision && (chan[ch].psgMode.getEnvelope()) && chan[ch].active) { + rWrite(0x08+ch,(chan[ch].vol&0xc)<<2); + } else if (chan[ch].active) { + rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode.getEnvelope())<<2)); + } } } @@ -554,12 +703,6 @@ void DivPlatformAY8910::reset() { pendingWrites[i]=-1; } - lastBusy=60; - dacMode=0; - dacPeriod=0; - dacPos=0; - dacRate=0; - dacSample=-1; sampleBank=0; ayEnvPeriod=0; ayEnvMode=0; diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index f67a2ad97..2ef8d702b 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -31,20 +31,83 @@ class DivPlatformAY8910: public DivDispatch { }; inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; } struct Channel { - unsigned char freqH, freqL; + struct PSGMode { + unsigned char tone: 1; + unsigned char noise: 1; + unsigned char envelope: 1; + unsigned char dac: 1; + + unsigned char getTone() { + return dac?0:(tone<<0); + } + + unsigned char getNoise() { + return dac?0:(noise<<1); + } + + unsigned char getEnvelope() { + return dac?0:(envelope<<2); + } + + PSGMode& operator=(unsigned char s) { + tone=(s>>0)&1; + noise=(s>>1)&1; + envelope=(s>>2)&1; + dac=(s>>3)&1; + return *this; + } + + PSGMode(): + tone(1), + noise(0), + envelope(0), + dac(0) {} + } psgMode; + + struct DAC { + int sample, rate, period, pos, out; + unsigned char furnaceDAC: 1; + + DAC(): + sample(-1), + rate(0), + period(0), + pos(0), + out(0), + furnaceDAC(0) {} + } dac; + int freq, baseFreq, note, pitch, pitch2; int ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; + unsigned char autoEnvNum, autoEnvDen; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; int vol, outVol; - unsigned char pan; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; } - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), pitch2(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {} + Channel(): + psgMode(PSGMode()), + dac(DAC()), + freq(0), + baseFreq(0), + note(0), + pitch(0), + pitch2(0), + ins(-1), + autoEnvNum(0), + autoEnvDen(0), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + vol(0), + outVol(15) {} }; Channel chan[3]; bool isMuted[3]; @@ -60,11 +123,6 @@ class DivPlatformAY8910: public DivDispatch { unsigned char regPool[16]; unsigned char lastBusy; - bool dacMode; - int dacPeriod; - int dacRate; - int dacPos; - int dacSample; unsigned char sampleBank; int delay; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 581ebb9e8..f60d36c74 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -133,6 +133,46 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l ayBuf[i]=new short[ayBufLen]; } } + // PCM part + for (int i=0; i<3; i++) { + if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { + chan[i].dac.period+=chan[i].dac.rate; + bool end=false; + bool changed=false; + int prev_out = chan[i].dac.out; + while (chan[i].dac.period>rate && !end) { + DivSample* s=parent->getSample(chan[i].dac.sample); + if (s->getEndPosition()<=0) { + chan[i].dac.sample=-1; + rWrite(0x08+i,0); + end=true; + break; + } + unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>3); + chan[i].dac.out=MAX(0,MIN(31,(dacData*chan[i].outVol)/31)); + if (prev_out!=chan[i].dac.out) { + prev_out=chan[i].dac.out; + changed=true; + } + chan[i].dac.pos++; + if (s->isLoopable() && chan[i].dac.pos>=s->getLoopEndPosition()) { + chan[i].dac.pos=s->getLoopStartPosition(); + } else if (chan[i].dac.pos>=s->getEndPosition()) { + chan[i].dac.sample=-1; + rWrite(0x08+i,0); + end=true; + break; + } + chan[i].dac.period-=rate; + } + if (changed && !end) { + if (!isMuted[i]) { + rWrite(0x08+i,chan[i].dac.out); + } + } + } + } + while (!writes.empty()) { QueuedWrite w=writes.front(); ay->address_w(w.addr); @@ -167,22 +207,22 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l void DivPlatformAY8930::updateOutSel(bool immediate) { if (immediate) { immWrite(0x07, - ~((chan[0].psgMode&1)| - ((chan[1].psgMode&1)<<1)| - ((chan[2].psgMode&1)<<2)| - ((chan[0].psgMode&2)<<2)| - ((chan[1].psgMode&2)<<3)| - ((chan[2].psgMode&2)<<4)| + ~((chan[0].psgMode.getTone())| + ((chan[1].psgMode.getTone())<<1)| + ((chan[2].psgMode.getTone())<<2)| + ((chan[0].psgMode.getNoise())<<2)| + ((chan[1].psgMode.getNoise())<<3)| + ((chan[2].psgMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } else { rWrite(0x07, - ~((chan[0].psgMode&1)| - ((chan[1].psgMode&1)<<1)| - ((chan[2].psgMode&1)<<2)| - ((chan[0].psgMode&2)<<2)| - ((chan[1].psgMode&2)<<3)| - ((chan[2].psgMode&2)<<4)| + ~((chan[0].psgMode.getTone())| + ((chan[1].psgMode.getTone())<<1)| + ((chan[2].psgMode.getTone())<<2)| + ((chan[0].psgMode.getNoise())<<2)| + ((chan[1].psgMode.getNoise())<<3)| + ((chan[2].psgMode.getNoise())<<4)| ((!ioPortA)<<6)| ((!ioPortB)<<7))); } @@ -207,10 +247,12 @@ void DivPlatformAY8930::tick(bool sysTick) { if (chan[i].std.vol.had) { chan[i].outVol=MIN(31,chan[i].std.vol.val)-(31-(chan[i].vol&31)); if (chan[i].outVol<0) chan[i].outVol=0; - if (isMuted[i]) { - rWrite(0x08+i,0); - } else { - rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3)); + if (!chan[i].psgMode.dac) { + if (isMuted[i]) { + rWrite(0x08+i,0); + } else { + rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode.getEnvelope())<<3)); + } } } if (chan[i].std.arp.had) { @@ -232,11 +274,13 @@ void DivPlatformAY8930::tick(bool sysTick) { rWrite(0x06,chan[i].std.duty.val); } if (chan[i].std.wave.had) { + if (!chan[i].psgMode.dac) { chan[i].psgMode=(chan[i].std.wave.val+1)&7; if (isMuted[i]) { rWrite(0x08+i,0); } else { - rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3)); + rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode.getEnvelope())<<3)); + } } } if (chan[i].std.pitch.had) { @@ -250,6 +294,20 @@ void DivPlatformAY8930::tick(bool sysTick) { } if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { + if (chan[i].psgMode.dac) { + if (dumpWrites) addWrite(0xffff0002+(i<<8),0); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AY8930); + chan[i].dac.sample=ins->amiga.getSample(chan[i].note); + if (chan[i].dac.sample<0 || chan[i].dac.sample>=parent->song.sampleLen) { + if (dumpWrites) { + rWrite(0x08+i,0); + addWrite(0xffff0000+(i<<8),chan[i].dac.sample); + } + chan[i].dac.pos=0; + chan[i].dac.period=0; + chan[i].keyOn=true; + } + } oldWrites[0x08+i]=-1; oldWrites[regMode[i]]=-1; } @@ -281,6 +339,19 @@ void DivPlatformAY8930::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER); + if (chan[i].dac.furnaceDAC) { + double off=1.0; + if (chan[i].dac.sample>=0 && chan[i].dac.samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[i].dac.sample); + if (s->centerRate<1) { + off=1.0; + } else { + off=8363.0/(double)s->centerRate; + } + } + chan[i].dac.rate=((double)chipClock*16384.0)/(double)(MAX(1,off*chan[i].freq)); + if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate); + } if (chan[i].freq>65535) chan[i].freq=65535; if (chan[i].keyOn) { if (chan[i].insChanged) { @@ -338,6 +409,62 @@ int DivPlatformAY8930::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY8930); + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + chan[c.chan].psgMode.dac=true; + } else if (chan[c.chan].dac.furnaceDAC) { + chan[c.chan].psgMode.dac=false; + } + if (chan[c.chan].psgMode.dac) { + if (skipRegisterWrites) break; + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + chan[c.chan].dac.sample=ins->amiga.getSample(c.value); + if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) { + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; + } else { + if (dumpWrites) { + rWrite(0x08+c.chan,0); + addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); + } + } + chan[c.chan].dac.pos=0; + chan[c.chan].dac.period=0; + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; + } + chan[c.chan].active=true; + chan[c.chan].macroInit(ins); + if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + //chan[c.chan].keyOn=true; + chan[c.chan].dac.furnaceDAC=true; + } else { + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + } + chan[c.chan].dac.sample=12*sampleBank+chan[c.chan].note%12; + if (chan[c.chan].dac.sample>=parent->song.sampleLen) { + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + break; + } else { + if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample); + } + chan[c.chan].dac.pos=0; + chan[c.chan].dac.period=0; + chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate; + if (dumpWrites) { + rWrite(0x08+c.chan,0); + addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate); + } + chan[c.chan].dac.furnaceDAC=false; + } + break; + } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; @@ -349,14 +476,19 @@ int DivPlatformAY8930::dispatch(DivCommand c) { if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3)); + if (!chan[c.chan].psgMode.dac) { + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else { + rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); + } } break; } case DIV_CMD_NOTE_OFF: + chan[c.chan].dac.sample=-1; + if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0); + chan[c.chan].psgMode.dac=false; chan[c.chan].keyOff=true; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); @@ -370,13 +502,15 @@ int DivPlatformAY8930::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else { - if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3)); + if (!chan[c.chan].psgMode.dac) { + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else { + if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); + } + break; } break; - break; } case DIV_CMD_GET_VOLUME: { return chan[c.chan].vol; @@ -423,11 +557,13 @@ int DivPlatformAY8930::dispatch(DivCommand c) { } case DIV_CMD_STD_NOISE_MODE: if (c.value<0x10) { - chan[c.chan].psgMode=(c.value+1)&7; - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else if (chan[c.chan].active) { - rWrite(0x08+c.chan,(chan[c.chan].outVol&31)|((chan[c.chan].psgMode&4)<<3)); + if (!chan[c.chan].psgMode.dac) { + chan[c.chan].psgMode=(c.value+1)&7; + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else if (chan[c.chan].active) { + rWrite(0x08+c.chan,(chan[c.chan].outVol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); + } } } else { chan[c.chan].duty=c.value&15; @@ -441,14 +577,14 @@ int DivPlatformAY8930::dispatch(DivCommand c) { chan[c.chan].envelope.mode=c.value>>4; rWrite(regMode[c.chan],chan[c.chan].envelope.mode); if (c.value&15) { - chan[c.chan].psgMode|=4; + chan[c.chan].psgMode.envelope|=1; } else { - chan[c.chan].psgMode&=~4; + chan[c.chan].psgMode.envelope&=~1; } if (isMuted[c.chan]) { rWrite(0x08+c.chan,0); } else { - rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3)); + rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3)); } break; case DIV_CMD_AY_ENVELOPE_LOW: @@ -496,6 +632,15 @@ int DivPlatformAY8930::dispatch(DivCommand c) { updateOutSel(true); immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); break; + case DIV_CMD_SAMPLE_MODE: + chan[c.chan].psgMode.dac=(c.value>0)?1:0; + break; + case DIV_CMD_SAMPLE_BANK: + sampleBank=c.value; + if (sampleBank>(parent->song.sample.size()/12)) { + sampleBank=parent->song.sample.size()/12; + } + break; case DIV_ALWAYS_SET_VOLUME: return 0; break; @@ -523,7 +668,11 @@ void DivPlatformAY8930::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(0x08+ch,0); } else if (chan[ch].active) { - rWrite(0x08+ch,(chan[ch].outVol&31)|((chan[ch].psgMode&4)<<3)); + if (chan[ch].psgMode.dac) { + rWrite(0x08+ch,chan[ch].dac.out&31); + } else { + rWrite(0x08+ch,(chan[ch].outVol&31)|((chan[ch].psgMode.getEnvelope())<<3)); + } } } @@ -578,6 +727,7 @@ void DivPlatformAY8930::reset() { pendingWrites[i]=-1; } + sampleBank=0; ayNoiseAnd=2; ayNoiseOr=0; delay=0; diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 10ac7736b..61d793dd3 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -38,20 +38,86 @@ class DivPlatformAY8930: public DivDispatch { slideLow(0), slide(0) {} } envelope; - unsigned char freqH, freqL; + + struct PSGMode { + unsigned char tone: 1; + unsigned char noise: 1; + unsigned char envelope: 1; + unsigned char dac: 1; + + unsigned char getTone() { + return dac?0:(tone<<0); + } + + unsigned char getNoise() { + return dac?0:(noise<<1); + } + + unsigned char getEnvelope() { + return dac?0:(envelope<<2); + } + + PSGMode& operator=(unsigned char s) { + tone=(s>>0)&1; + noise=(s>>1)&1; + envelope=(s>>2)&1; + dac=(s>>3)&1; + return *this; + } + + PSGMode(): + tone(1), + noise(0), + envelope(0), + dac(0) {} + } psgMode; + + struct DAC { + int sample, rate, period, pos, out; + unsigned char furnaceDAC: 1; + + DAC(): + sample(-1), + rate(0), + period(0), + pos(0), + out(0), + furnaceDAC(0) {} + } dac; + int freq, baseFreq, note, pitch, pitch2; int ins; - unsigned char psgMode, autoEnvNum, autoEnvDen, duty; + unsigned char autoEnvNum, autoEnvDen, duty; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; int vol, outVol; - unsigned char pan; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; } - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), pitch2(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), duty(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(31), pan(3) {} + Channel(): + envelope(Envelope()), + psgMode(PSGMode()), + dac(DAC()), + freq(0), + baseFreq(0), + note(0), + pitch(0), + pitch2(0), + ins(-1), + autoEnvNum(0), + autoEnvDen(0), + duty(4), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + vol(0), + outVol(31) {} }; Channel chan[3]; bool isMuted[3]; @@ -68,6 +134,8 @@ class DivPlatformAY8930: public DivDispatch { unsigned char ayNoiseAnd, ayNoiseOr; bool bank; + unsigned char sampleBank; + int delay; bool extMode, stereo, clockSel; diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 836ce3155..9bfea2963 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -34,6 +34,7 @@ #define WRITE_STEREO(v) rWrite(0x50,(v)) #define CHIP_DIVIDER 64 +#define CHIP_FREQBASE 4000000 #if defined( _MSC_VER ) @@ -155,7 +156,7 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len WRITE_OUTPUT(i,0); chan[i].samplePos++; } else { - WRITE_OUTPUT(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7); + WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos++]*chan[i].outVol)>>7,-128,127)); } if (s->isLoopable() && chan[i].samplePos>=s->getLoopEndPosition()) { @@ -177,7 +178,7 @@ void DivPlatformLynx::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { if (chan[i].pcm) { - chan[i].outVol=((chan[i].vol&127)*MIN(64,chan[i].std.vol.val))>>6; + chan[i].outVol=((chan[i].vol&127)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; } else { chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7; } @@ -187,11 +188,11 @@ void DivPlatformLynx::tick(bool sysTick) { if (!chan[i].inPorta) { if (chan[i].std.arp.mode) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); - if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].std.arp.val,false); + if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); chan[i].actualNote=chan[i].std.arp.val; } else { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); - if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].note+chan[i].std.arp.val,false); + if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val); chan[i].actualNote=chan[i].note+chan[i].std.arp.val; } chan[i].freqChanged=true; @@ -199,7 +200,7 @@ void DivPlatformLynx::tick(bool sysTick) { } else { if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); - if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].note,false); + if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].actualNote=chan[i].note; chan[i].freqChanged=true; } @@ -231,6 +232,10 @@ void DivPlatformLynx::tick(bool sysTick) { if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { + if (chan[i].pcm && chan[i].sample>=0 && chan[i].samplesong.sampleLen) { + chan[i].sampleAccum=0; + chan[i].samplePos=0; + } WRITE_LFSR(i, 0); WRITE_OTHER(i, 0); } @@ -247,7 +252,7 @@ void DivPlatformLynx::tick(bool sysTick) { off=(double)s->centerRate/8363.0; } } - chan[i].sampleFreq=off*parent->calcFreq(chan[i].sampleBaseFreq,chan[i].pitch,false,2,chan[i].pitch2,1,1); + chan[i].sampleFreq=off*parent->calcFreq(chan[i].sampleBaseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE); } else { if (chan[i].lfsr >= 0) { WRITE_LFSR(i, (chan[i].lfsr&0xff)); @@ -277,11 +282,12 @@ int DivPlatformLynx::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY); - chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA); + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:127; + chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); if (chan[c.chan].pcm) { - chan[c.chan].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,c.value,false); + chan[c.chan].sampleBaseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].sample=ins->amiga.getSample(c.value); chan[c.chan].sampleAccum=0; chan[c.chan].samplePos=0; @@ -294,7 +300,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { } chan[c.chan].active=true; WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127))); - chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); + chan[c.chan].macroInit(ins); if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } @@ -374,7 +380,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { int whatAMess=c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)); chan[c.chan].baseFreq=NOTE_PERIODIC(whatAMess); if (chan[c.chan].pcm) { - chan[c.chan].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,whatAMess,false); + chan[c.chan].sampleBaseFreq=NOTE_FREQUENCY(whatAMess); } chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; diff --git a/src/engine/platform/lynx.h b/src/engine/platform/lynx.h index 849c3182b..b977a67d7 100644 --- a/src/engine/platform/lynx.h +++ b/src/engine/platform/lynx.h @@ -48,6 +48,7 @@ class DivPlatformLynx: public DivDispatch { unsigned char pan; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, pcm; signed char vol, outVol; + int macroVolMul; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; @@ -77,7 +78,8 @@ class DivPlatformLynx: public DivDispatch { inPorta(false), pcm(false), vol(127), - outVol(127) {} + outVol(127), + macroVolMul(127) {} }; Channel chan[4]; DivDispatchOscBuffer* oscBuf[4]; diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index dc81950ef..1fdbc3000 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -102,14 +102,54 @@ void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t } void DivPlatformMSM6258::tick(bool sysTick) { - // nothing + for (int i=0; i<1; i++) { + chan[i].std.next(); + if (chan[i].std.duty.had) { + if (rateSel!=(chan[i].std.duty.val&3)) { + rateSel=chan[i].std.duty.val&3; + rWrite(12,rateSel); + } + } + if (chan[i].std.panL.had) { + if (chan[i].pan!=(chan[i].std.panL.val&3)) { + chan[i].pan=chan[i].std.panL.val&3; + rWrite(2,chan[i].pan); + } + } + if (chan[i].std.ex1.had) { + if (clockSel!=(chan[i].std.ex1.val&1)) { + clockSel=chan[i].std.ex1.val&1; + rWrite(8,clockSel); + } + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active) { + chan[i].keyOn=true; + } + } + if (chan[i].keyOn || chan[i].keyOff) { + samplePos=0; + rWrite(0,1); // turn off + if (chan[i].active && !chan[i].keyOff) { + if (sample>=0 && samplesong.sampleLen) { + rWrite(0,2); + } else { + sample=-1; + } + } else { + sample=-1; + } + chan[i].keyOn=false; + chan[i].keyOff=false; + } + } } int DivPlatformMSM6258::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_MSM6258 || ins->type==DIV_INS_AMIGA) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -130,8 +170,6 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - rWrite(0,1); - rWrite(0,2); } else { break; } @@ -145,8 +183,8 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { //DivSample* s=parent->getSample(12*sampleBank+c.value%12); sample=12*sampleBank+c.value%12; samplePos=0; - rWrite(0,1); - rWrite(0,2); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } break; } @@ -154,18 +192,12 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; - rWrite(0,1); // turn off - sample=-1; - samplePos=0; chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; - rWrite(0,1); // turn off - sample=-1; - samplePos=0; chan[c.chan].std.release(); break; case DIV_CMD_ENV_RELEASE: diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index fc5f9ea30..b0059d1a9 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -95,7 +95,38 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t } void DivPlatformMSM6295::tick(bool sysTick) { - // nothing + for (int i=0; i<4; i++) { + chan[i].std.next(); + if (chan[i].std.vol.had) { + chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,8); + } + if (chan[i].std.duty.had) { + if (rateSel!=(chan[i].std.duty.val&1)) { + rateSel=chan[i].std.duty.val&1; + rWrite(12,!rateSel); + } + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active) { + chan[i].keyOn=true; + } + } + if (chan[i].keyOn || chan[i].keyOff) { + rWriteDelay(0,(8<=0 && chan[i].samplesong.sampleLen) { + rWrite(0,0x80|chan[i].sample); // set phrase + rWrite(0,(16<=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - return parent->calcBaseFreq((double)chipClock/144,off,note,false); + return parent->calcBaseFreq((double)chipClock/((oplType==3)?288:72),off,note,false); } return 0; } @@ -577,7 +577,7 @@ void DivPlatformOPL::tick(bool sysTick) { chan[adpcmChan].std.next(); if (chan[adpcmChan].std.vol.had) { - chan[adpcmChan].outVol=(chan[adpcmChan].vol*MIN(64,chan[adpcmChan].std.vol.val))/64; + chan[adpcmChan].outVol=(chan[adpcmChan].vol*MIN(chan[adpcmChan].macroVolMul,chan[adpcmChan].std.vol.val))/chan[adpcmChan].macroVolMul; immWrite(18,chan[adpcmChan].outVol); } @@ -596,16 +596,32 @@ void DivPlatformOPL::tick(bool sysTick) { chan[adpcmChan].freqChanged=true; } } + if (chan[adpcmChan].std.phaseReset.had) { + if ((chan[adpcmChan].std.phaseReset.val==1) && chan[adpcmChan].active) { + chan[adpcmChan].keyOn=true; + } + } } - if (chan[adpcmChan].freqChanged) { + if (chan[adpcmChan].freqChanged || chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/144,off); + chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/((oplType==3)?288:72),off); } else { chan[adpcmChan].freq=0; } immWrite(16,chan[adpcmChan].freq&0xff); immWrite(17,(chan[adpcmChan].freq>>8)&0xff); + if (chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { + immWrite(7,0x01); // reset + if (chan[adpcmChan].active && chan[adpcmChan].keyOn && !chan[adpcmChan].keyOff) { + if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[adpcmChan].sample); + immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat + } + } + chan[adpcmChan].keyOn=false; + chan[adpcmChan].keyOff=false; + } chan[adpcmChan].freqChanged=false; } } @@ -749,7 +765,8 @@ int DivPlatformOPL::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { if (c.chan==adpcmChan) { // ADPCM DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -765,13 +782,11 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { DivSample* s=parent->getSample(chan[c.chan].sample); immWrite(8,0); - immWrite(7,0x01); // reset immWrite(9,(s->offB>>2)&0xff); immWrite(10,(s->offB>>10)&0xff); int end=s->offB+s->lengthB-1; immWrite(11,(end>>2)&0xff); immWrite(12,(end>>10)&0xff); - immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -792,25 +807,29 @@ int DivPlatformOPL::dispatch(DivCommand c) { chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { + break; + } + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(12*sampleBank+c.value%12); + immWrite(8,0); + immWrite(9,(s->offB>>2)&0xff); + immWrite(10,(s->offB>>10)&0xff); + int end=s->offB+s->lengthB-1; + immWrite(11,(end>>2)&0xff); + immWrite(12,(end>>10)&0xff); + int freq=(65536.0*(double)s->rate)/(double)chipRateBase; + immWrite(16,freq&0xff); + immWrite(17,(freq>>8)&0xff); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { immWrite(7,0x01); // reset immWrite(9,0); immWrite(10,0); immWrite(11,0); immWrite(12,0); - break; } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(8,0); - immWrite(7,0x01); // reset - immWrite(9,(s->offB>>2)&0xff); - immWrite(10,(s->offB>>10)&0xff); - int end=s->offB+s->lengthB-1; - immWrite(11,(end>>2)&0xff); - immWrite(12,(end>>10)&0xff); - immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat - int freq=(65536.0*(double)s->rate)/(double)chipRateBase; - immWrite(16,freq&0xff); - immWrite(17,(freq>>8)&0xff); } break; } @@ -955,19 +974,11 @@ int DivPlatformOPL::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_OFF: - if (c.chan==adpcmChan) { - immWrite(7,0x01); // reset - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; break; case DIV_CMD_NOTE_OFF_ENV: - if (c.chan==adpcmChan) { - immWrite(7,0x01); // reset - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 3d6497367..4c8a943f1 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -44,6 +44,7 @@ class DivPlatformOPL: public DivDispatch { bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnacePCM, inPorta, fourOp, hardReset; int vol, outVol; unsigned char pan; + int macroVolMul; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; @@ -70,7 +71,8 @@ class DivPlatformOPL: public DivDispatch { fourOp(false), hardReset(false), vol(0), - pan(3) { + pan(3), + macroVolMul(64) { state.ops=2; } }; diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index ee479f5b4..b36d5d133 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -87,8 +87,15 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) continue; } chWrite(i,0x07,0); - chWrite(i,0x04,0xdf); - chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3)); + signed char dacData=((signed char)((unsigned char)s->data8[chan[i].dacPos]^0x80))>>3; + chan[i].dacOut=CLAMP(dacData,-16,15); + if (!isMuted[i]) { + chWrite(i,0x04,0xc0|chan[i].outVol); + chWrite(i,0x06,chan[i].dacOut&0x1f); + } else { + chWrite(i,0x04,0xc0); + chWrite(i,0x06,0x10); + } chan[i].dacPos++; if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) { chan[i].dacPos=s->getLoopStartPosition(); @@ -234,6 +241,15 @@ void DivPlatformPCE::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) { + if (chan[i].furnaceDac && chan[i].pcm) { + if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { + chan[i].dacPos=0; + chan[i].dacPeriod=0; + chWrite(i,0x04,0xc0|chan[i].vol); + addWrite(0xffff0000+(i<<8),chan[i].dacSample); + chan[i].keyOn=true; + } + } chan[i].antiClickWavePos=0; chan[i].antiClickPeriodCount=0; } @@ -279,13 +295,14 @@ int DivPlatformPCE::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE); - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:31; + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].pcm=true; } else if (chan[c.chan].furnaceDac) { chan[c.chan].pcm=false; } if (chan[c.chan].pcm) { - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].furnaceDac=true; if (skipRegisterWrites) break; chan[c.chan].dacSample=ins->amiga.getSample(c.value); @@ -295,7 +312,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; } else { if (dumpWrites) { - chWrite(c.chan,0x04,0xdf); + chWrite(c.chan,0x04,0xc0|chan[c.chan].vol); addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); } } @@ -308,6 +325,9 @@ int DivPlatformPCE::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].macroInit(ins); + if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } //chan[c.chan].keyOn=true; } else { chan[c.chan].furnaceDac=false; @@ -327,7 +347,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].dacPeriod=0; chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate; if (dumpWrites) { - chWrite(c.chan,0x04,0xdf); + chWrite(c.chan,0x04,0xc0|chan[c.chan].vol); addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate); } } @@ -480,6 +500,10 @@ int DivPlatformPCE::dispatch(DivCommand c) { void DivPlatformPCE::muteChannel(int ch, bool mute) { isMuted[ch]=mute; chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan); + if (!isMuted[ch] && (chan[ch].pcm && chan[ch].dacSample!=-1)) { + chWrite(ch,0x04,0xc0|chan[ch].outVol); + chWrite(ch,0x06,chan[ch].dacOut&0x1f); + } } void DivPlatformPCE::forceIns() { diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 17e191d44..02ee861f7 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -29,12 +29,13 @@ class DivPlatformPCE: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2, note, antiClickPeriodCount, antiClickWavePos; - int dacPeriod, dacRate; + int dacPeriod, dacRate, dacOut; unsigned int dacPos; int dacSample, ins; unsigned char pan; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, furnaceDac, deferredWaveUpdate; signed char vol, outVol, wave; + int macroVolMul; DivMacroInt std; DivWaveSynth ws; void macroInit(DivInstrument* which) { @@ -51,6 +52,7 @@ class DivPlatformPCE: public DivDispatch { antiClickWavePos(0), dacPeriod(0), dacRate(0), + dacOut(0), dacPos(0), dacSample(-1), ins(-1), @@ -67,7 +69,8 @@ class DivPlatformPCE: public DivDispatch { deferredWaveUpdate(false), vol(31), outVol(31), - wave(-1) {} + wave(-1), + macroVolMul(31) {} }; Channel chan[6]; DivDispatchOscBuffer* oscBuf[6]; diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 67a533b1b..4d83bd7d1 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -36,26 +36,71 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l continue; } if (chan.useWave || (chan.sample>=0 && chan.samplesong.sampleLen)) { - chan.audPos+=chan.freq>>16; + chan.audPos+=((!chan.useWave) && chan.audDir)?-(chan.freq>>16):(chan.freq>>16); chan.audSub+=(chan.freq&0xffff); if (chan.audSub>=0x10000) { chan.audSub-=0x10000; - chan.audPos+=1; + chan.audPos+=((!chan.useWave) && chan.audDir)?-1:1; } if (chan.useWave) { - if (chan.audPos>=(unsigned int)(chan.audLen<<1)) { - chan.audPos=0; + if (chan.audPos>=(int)chan.audLen) { + chan.audPos%=chan.audLen; + chan.audDir=false; } output=(chan.ws.output[chan.audPos]^0x80)<<8; } else { DivSample* s=parent->getSample(chan.sample); if (s->getEndPosition()>0) { - if (s->isLoopable() && chan.audPos>=(unsigned int)s->getLoopEndPosition()) { - chan.audPos=s->getLoopStartPosition(); - } else if (chan.audPos>=(unsigned int)s->getEndPosition()) { - chan.sample=-1; + if (chan.audDir) { + if (s->isLoopable()) { + switch (s->loopMode) { + case DIV_SAMPLE_LOOP_FORWARD: + case DIV_SAMPLE_LOOP_PINGPONG: + if (chan.audPosgetLoopStartPosition()) { + chan.audPos=s->getLoopStartPosition()+(s->getLoopStartPosition()-chan.audPos); + chan.audDir=false; + } + break; + case DIV_SAMPLE_LOOP_BACKWARD: + if (chan.audPosgetLoopStartPosition()) { + chan.audPos=s->getLoopEndPosition()-1-(s->getLoopStartPosition()-chan.audPos); + chan.audDir=true; + } + default: + if (chan.audPos<0) { + chan.sample=-1; + } + break; + } + } else if (chan.audPos>=s->getEndPosition()) { + chan.sample=-1; + } + } else { + if (s->isLoopable()) { + switch (s->loopMode) { + case DIV_SAMPLE_LOOP_FORWARD: + if (chan.audPos>=s->getLoopEndPosition()) { + chan.audPos=(chan.audPos+s->getLoopStartPosition())-s->getLoopEndPosition(); + chan.audDir=false; + } + break; + case DIV_SAMPLE_LOOP_BACKWARD: + case DIV_SAMPLE_LOOP_PINGPONG: + if (chan.audPos>=s->getLoopEndPosition()) { + chan.audPos=s->getLoopEndPosition()-1-(s->getLoopEndPosition()-1-chan.audPos); + chan.audDir=true; + } + default: + if (chan.audPos>=s->getEndPosition()) { + chan.sample=-1; + } + break; + } + } else if (chan.audPos>=s->getEndPosition()) { + chan.sample=-1; + } } - if (chan.audPos<(unsigned int)s->getEndPosition()) { + if (chan.audPos>=0 && chan.audPosgetEndPosition()) { output=s->data16[chan.audPos]; } } else { @@ -125,6 +170,7 @@ void DivPlatformPCMDAC::tick(bool sysTick) { } if (chan.std.phaseReset.had) { if (chan.std.phaseReset.val==1) { + chan.audDir=false; chan.audPos=0; } } @@ -156,11 +202,11 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_AMIGA); if (ins->amiga.useWave) { chan.useWave=true; - chan.audLen=(ins->amiga.waveLen+1)>>1; + chan.audLen=ins->amiga.waveLen; if (chan.insChanged) { if (chan.wave<0) { chan.wave=0; - chan.ws.setWidth(chan.audLen<<1); + chan.ws.setWidth(chan.audLen); chan.ws.changeWave1(chan.wave); } } @@ -177,6 +223,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) { if (chan.setPos) { chan.setPos=false; } else { + chan.audDir=false; chan.audPos=0; } chan.audSub=0; @@ -191,7 +238,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) { chan.envVol=64; } if (chan.useWave) { - chan.ws.init(ins,chan.audLen<<1,255,chan.insChanged); + chan.ws.init(ins,chan.audLen,255,chan.insChanged); } chan.insChanged=false; break; @@ -298,6 +345,7 @@ void DivPlatformPCMDAC::muteChannel(int ch, bool mute) { void DivPlatformPCMDAC::forceIns() { chan.insChanged=true; chan.freqChanged=true; + chan.audDir=false; chan.audPos=0; chan.sample=-1; } diff --git a/src/engine/platform/pcmdac.h b/src/engine/platform/pcmdac.h index 60d2a6fc0..127d39aae 100644 --- a/src/engine/platform/pcmdac.h +++ b/src/engine/platform/pcmdac.h @@ -28,9 +28,10 @@ class DivPlatformPCMDAC: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2; + bool audDir; unsigned int audLoc; unsigned short audLen; - unsigned int audPos; + int audPos; int audSub; int sample, wave, ins; int note; @@ -48,6 +49,7 @@ class DivPlatformPCMDAC: public DivDispatch { baseFreq(0), pitch(0), pitch2(0), + audDir(false), audLoc(0), audLen(0), audPos(0), diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 64daed60a..d28d724c1 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -286,10 +286,16 @@ void DivPlatformQSound::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6; + if (chan[i].isNewQSound) { + chan[i].outVol=((chan[i].vol&0xff)*MIN(16383,chan[i].std.vol.val))/16383; + chan[i].resVol=((chan[i].vol&0xff)*MIN(16383,chan[i].std.vol.val))/255; + } else { + chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6; + chan[i].resVol=chan[i].outVol<<4; + } // Check if enabled and write volume if (chan[i].active) { - rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 4); + rWrite(q1_reg_map[Q1V_VOL][i],chan[i].resVol); } } uint16_t qsound_bank = 0; @@ -329,6 +335,16 @@ void DivPlatformQSound::tick(bool sysTick) { chan[i].freqChanged=true; } } + if (chan[i].std.duty.had) { + chan[i].echo=CLAMP(chan[i].std.duty.val,0,32767); + immWrite(Q1_ECHO+i,chan[i].echo&0x7fff); + } + if (chan[i].std.ex1.had) { + immWrite(Q1_ECHO_FEEDBACK,chan[i].std.ex1.val&0x3fff); + } + if (chan[i].std.ex2.had) { + immWrite(Q1_ECHO_LENGTH,0xfff-(2725-CLAMP(chan[i].std.ex2.val&0xfff,0,2725))); + } if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { chan[i].pitch2+=chan[i].std.pitch.val; @@ -347,6 +363,11 @@ void DivPlatformQSound::tick(bool sysTick) { if (chan[i].std.panL.had || chan[i].std.panR.had) { immWrite(Q1_PAN+i,chan[i].panning+0x110+(chan[i].surround?0:0x30)); } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val==1 && chan[i].active && (chan[i].sample>=0 && chan[i].samplesong.sampleLen)) { + chan[i].keyOn=true; + } + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA); double off=1.0; @@ -366,19 +387,24 @@ void DivPlatformQSound::tick(bool sysTick) { rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop); rWrite(q1_reg_map[Q1V_START][i], qsound_addr); rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000); - logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); + //logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); // Write sample address. Enable volume if (!chan[i].std.vol.had) { - rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 4); + if (chan[i].isNewQSound) { + chan[i].resVol=(chan[i].vol*16383)/255; + } else { + chan[i].resVol=chan[i].vol<<4; + } + rWrite(q1_reg_map[Q1V_VOL][i],chan[i].resVol); } } if (chan[i].keyOff) { // Disable volume - rWrite(q1_reg_map[Q1V_VOL][i], 0); - rWrite(q1_reg_map[Q1V_FREQ][i], 0); + rWrite(q1_reg_map[Q1V_VOL][i],0); + rWrite(q1_reg_map[Q1V_FREQ][i],0); } else if (chan[i].active) { //logV("ch %d frequency set to %04x, off=%f, note=%d, %04x!",i,chan[i].freq,off,chan[i].note,QS_NOTE_FREQUENCY(chan[i].note)); - rWrite(q1_reg_map[Q1V_FREQ][i], chan[i].freq); + rWrite(q1_reg_map[Q1V_FREQ][i],chan[i].freq); } if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; @@ -391,6 +417,7 @@ int DivPlatformQSound::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); + chan[c.chan].isNewQSound=(ins->type==DIV_INS_QSOUND); chan[c.chan].sample=ins->amiga.getSample(c.value); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(c.value); @@ -407,6 +434,11 @@ int DivPlatformQSound::dispatch(DivCommand c) { chan[c.chan].macroInit(ins); if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; + if (chan[c.chan].isNewQSound) { + chan[c.chan].resVol=(chan[c.chan].outVol*16383)/255; + } else { + chan[c.chan].resVol=chan[c.chan].outVol<<4; + } } break; } @@ -431,8 +463,13 @@ int DivPlatformQSound::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { // Check if enabled and write volume chan[c.chan].outVol=c.value; - if (chan[c.chan].active && c.chan < 16) { - rWrite(q1_reg_map[Q1V_VOL][c.chan], chan[c.chan].outVol << 4); + if (chan[c.chan].isNewQSound) { + chan[c.chan].resVol=(chan[c.chan].outVol*16383)/255; + } else { + chan[c.chan].resVol=chan[c.chan].outVol<<4; + } + if (chan[c.chan].active && c.chan<16) { + rWrite(q1_reg_map[Q1V_VOL][c.chan],chan[c.chan].resVol); } } } @@ -448,7 +485,8 @@ int DivPlatformQSound::dispatch(DivCommand c) { immWrite(Q1_PAN+c.chan,chan[c.chan].panning+0x110+(chan[c.chan].surround?0:0x30)); break; case DIV_CMD_QSOUND_ECHO_LEVEL: - immWrite(Q1_ECHO+c.chan, c.value << 7); + chan[c.chan].echo=c.value<<7; + immWrite(Q1_ECHO+c.chan,chan[c.chan].echo&0x7fff); break; case DIV_CMD_QSOUND_ECHO_FEEDBACK: immWrite(Q1_ECHO_FEEDBACK, c.value << 6); diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index 285760138..553560559 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -28,13 +28,12 @@ class DivPlatformQSound: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2; - unsigned short audLen; - unsigned int audPos; int sample, wave, ins; int note; int panning; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, surround; - int vol, outVol; + int echo; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, surround, isNewQSound; + int vol, outVol, resVol; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -45,12 +44,11 @@ class DivPlatformQSound: public DivDispatch { baseFreq(0), pitch(0), pitch2(0), - audLen(0), - audPos(0), sample(-1), ins(-1), note(0), panning(0x10), + echo(0), active(false), insChanged(true), freqChanged(false), @@ -59,8 +57,10 @@ class DivPlatformQSound: public DivDispatch { inPorta(false), useWave(false), surround(true), + isNewQSound(false), vol(255), - outVol(255) {} + outVol(255), + resVol(4096) {} }; Channel chan[19]; DivDispatchOscBuffer* oscBuf[19]; diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index 5b829c348..456b2b128 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -83,7 +83,7 @@ void DivPlatformRF5C68::tick(bool sysTick) { for (int i=0; i<8; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6; + chan[i].outVol=((chan[i].vol&0xff)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; chWrite(i,0,chan[i].outVol); } if (chan[i].std.arp.had) { @@ -120,7 +120,13 @@ void DivPlatformRF5C68::tick(bool sysTick) { chan[i].panning|=(chan[i].std.panR.val&15)<<4; } if (chan[i].std.panL.had || chan[i].std.panR.had) { - chWrite(i,0x05,isMuted[i]?0:chan[i].panning); + chWrite(i,1,isMuted[i]?0:chan[i].panning); + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val==1 && chan[i].active) { + chan[i].audPos=0; + chan[i].setPos=true; + } } if (chan[i].setPos) { // force keyon @@ -175,6 +181,7 @@ int DivPlatformRF5C68::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255; chan[c.chan].sample=ins->amiga.getSample(c.value); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); diff --git a/src/engine/platform/rf5c68.h b/src/engine/platform/rf5c68.h index 6946b4900..94aca4fea 100644 --- a/src/engine/platform/rf5c68.h +++ b/src/engine/platform/rf5c68.h @@ -34,6 +34,7 @@ class DivPlatformRF5C68: public DivDispatch { int panning; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos; int vol, outVol; + int macroVolMul; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -57,7 +58,8 @@ class DivPlatformRF5C68: public DivDispatch { inPorta(false), setPos(false), vol(255), - outVol(255) {} + outVol(255), + macroVolMul(64) {} }; Channel chan[8]; DivDispatchOscBuffer* oscBuf[8]; diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 6a63f823b..3ad775c51 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -83,9 +83,9 @@ void DivPlatformSegaPCM::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); - if (parent->song.newSegaPCM) { + if (chan[i].isNewSegaPCM) { if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(64,chan[i].std.vol.val))>>6; + chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127; if (dumpWrites) { @@ -112,7 +112,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } if (chan[i].std.panL.had) { - if (parent->song.newSegaPCM) { + if (chan[i].isNewSegaPCM) { chan[i].chPanL=chan[i].std.panL.val&127; chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; } else { @@ -124,7 +124,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } if (chan[i].std.panR.had) { - if (parent->song.newSegaPCM) { + if (chan[i].isNewSegaPCM) { chan[i].chPanR=chan[i].std.panR.val&127; chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127; } else { @@ -144,13 +144,14 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } chan[i].freqChanged=true; } - /*if (chan[i].keyOn || chan[i].keyOff) { - chan[i].keyOff=false; - }*/ - } - for (int i=0; i<16; i++) { - if (chan[i].freqChanged) { + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val==1 && chan[i].active) { + chan[i].keyOn=true; + } + } + + if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64; if (chan[i].furnacePCM) { double off=1.0; @@ -164,6 +165,56 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } } chan[i].freqChanged=false; + if (chan[i].keyOn || chan[i].keyOff) { + if (chan[i].keyOn && !chan[i].keyOff) { + if (dumpWrites) { + addWrite(0x10086+(i<<3),3); + } + chan[i].pcm.pos=0; + if (chan[i].furnacePCM) { + if (dumpWrites) { // Sega PCM writes + DivSample* s=parent->getSample(chan[i].pcm.sample); + int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); + int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); + if (actualLength>0xfeff) actualLength=0xfeff; + addWrite(0x10086+(i<<3),3+((s->offSegaPCM>>16)<<3)); + addWrite(0x10084+(i<<3),(s->offSegaPCM)&0xff); + addWrite(0x10085+(i<<3),(s->offSegaPCM>>8)&0xff); + addWrite(0x10006+(i<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); + if (loopStart<0 || loopStart>=actualLength) { + addWrite(0x10086+(i<<3),2+((s->offSegaPCM>>16)<<3)); + } else { + int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; + addWrite(0x10004+(i<<3),loopPos&0xff); + addWrite(0x10005+(i<<3),(loopPos>>8)&0xff); + addWrite(0x10086+(i<<3),((s->offSegaPCM>>16)<<3)); + } + } + } else { + if (dumpWrites) { // Sega PCM writes + DivSample* s=parent->getSample(chan[i].pcm.sample); + int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); + int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); + if (actualLength>65536) actualLength=65536; + addWrite(0x10086+(i<<3),3+((s->offSegaPCM>>16)<<3)); + addWrite(0x10084+(i<<3),(s->offSegaPCM)&0xff); + addWrite(0x10085+(i<<3),(s->offSegaPCM>>8)&0xff); + addWrite(0x10006+(i<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); + if (loopStart<0 || loopStart>=actualLength) { + addWrite(0x10086+(i<<3),2+((s->offSegaPCM>>16)<<3)); + } else { + int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; + addWrite(0x10004+(i<<3),loopPos&0xff); + addWrite(0x10005+(i<<3),(loopPos>>8)&0xff); + addWrite(0x10086+(i<<3),((s->offSegaPCM>>16)<<3)); + } + addWrite(0x10007+(i<<3),chan[i].pcm.freq); + } + } + } + chan[i].keyOn=false; + chan[i].keyOff=false; + } } } } @@ -177,7 +228,9 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); if (skipRegisterWrites) break; - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SEGAPCM) { + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:127; + chan[c.chan].isNewSegaPCM=(ins->type==DIV_INS_SEGAPCM || parent->song.newSegaPCM); chan[c.chan].pcm.sample=ins->amiga.getSample(c.value); if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) { chan[c.chan].pcm.sample=-1; @@ -190,7 +243,6 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { } break; } - chan[c.chan].pcm.pos=0; if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=(c.value<<6); @@ -198,24 +250,8 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { } chan[c.chan].furnacePCM=true; chan[c.chan].macroInit(ins); - if (dumpWrites) { // Sega PCM writes - DivSample* s=parent->getSample(chan[c.chan].pcm.sample); - int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); - int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); - if (actualLength>0xfeff) actualLength=0xfeff; - addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); - addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); - addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); - addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); - if (loopStart<0 || loopStart>=actualLength) { - addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); - } else { - int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; - addWrite(0x10004+(c.chan<<3),loopPos&0xff); - addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff); - addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3)); - } - } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } else { chan[c.chan].macroInit(NULL); if (c.value!=DIV_NOTE_NULL) { @@ -229,28 +265,10 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { } break; } - chan[c.chan].pcm.pos=0; chan[c.chan].pcm.freq=MIN(255,(parent->getSample(chan[c.chan].pcm.sample)->rate*255)/31250); chan[c.chan].furnacePCM=false; - if (dumpWrites) { // Sega PCM writes - DivSample* s=parent->getSample(chan[c.chan].pcm.sample); - int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); - int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)); - if (actualLength>65536) actualLength=65536; - addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); - addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff); - addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff); - addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8)); - if (loopStart<0 || loopStart>=actualLength) { - addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3)); - } else { - int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP; - addWrite(0x10004+(c.chan<<3),loopPos&0xff); - addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff); - addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3)); - } - addWrite(0x10007+(c.chan<<3),chan[c.chan].pcm.freq); - } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; } break; } @@ -278,7 +296,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (parent->song.newSegaPCM) { + if (chan[c.chan].isNewSegaPCM) { chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127; chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127; } else { @@ -302,7 +320,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].ins=c.value; break; case DIV_CMD_PANNING: { - if (parent->song.newSegaPCM) { + if (chan[c.chan].isNewSegaPCM) { chan[c.chan].chPanL=c.value>>1; chan[c.chan].chPanR=c.value2>>1; chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127; diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 6edc85302..4b91a70bb 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -28,13 +28,12 @@ class DivPlatformSegaPCM: public DivDispatch { protected: struct Channel { DivMacroInt std; - unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, note, ins; - signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, isNewSegaPCM; int vol, outVol; unsigned char chVolL, chVolR; unsigned char chPanL, chPanR; + int macroVolMul; struct PCMChannel { int sample; @@ -48,8 +47,6 @@ class DivPlatformSegaPCM: public DivDispatch { pitch2=0; } Channel(): - freqH(0), - freqL(0), freq(0), baseFreq(0), pitch(0), @@ -64,12 +61,15 @@ class DivPlatformSegaPCM: public DivDispatch { inPorta(false), portaPause(false), furnacePCM(false), + isNewSegaPCM(false), vol(0), outVol(0), chVolL(127), chVolR(127), chPanL(127), - chPanR(127) {} + chPanR(127), + macroVolMul(64), + pcm(PCMChannel()) {} }; Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index a212c65fe..af088fb57 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -256,12 +256,12 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SU); - if (chan[c.chan].pcm && !(ins->type==DIV_INS_AMIGA || ins->su.useSample)) { - chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->su.useSample); + if (chan[c.chan].pcm && !(ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) { + chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample); writeControl(c.chan); writeControlUpper(c.chan); } - chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->su.useSample); + chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].freqChanged=true; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 5110d7e15..924e4cabd 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -251,7 +251,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SWAN); if (c.chan==1) { - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { pcm=true; } else if (furnaceDac) { pcm=false; @@ -260,7 +260,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { if (skipRegisterWrites) break; dacPos=0; dacPeriod=0; - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { dacSample=ins->amiga.getSample(c.value); if (dacSample<0 || dacSample>=parent->song.sampleLen) { dacSample=-1; diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index fa81afb91..60379d416 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -193,6 +193,25 @@ void DivPlatformVRC6::tick(bool sysTick) { } chan[i].freqChanged=true; } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active) { + if ((i!=2) && (!chan[i].pcm)) { + if (dumpWrites) addWrite(0xffff0002+(i<<8),0); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_VRC6); + chan[i].dacSample=ins->amiga.getSample(chan[i].note); + if (chan[i].dacSample<0 || chan[i].dacSample>=parent->song.sampleLen) { + if (dumpWrites) { + chWrite(i,2,0x80); + chWrite(i,0,isMuted[i]?0:0x80); + addWrite(0xffff0000+(i<<8),chan[i].dacSample); + } + chan[i].dacPos=0; + chan[i].dacPeriod=0; + chan[i].keyOn=true; + } + } + } + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { if (i==2) { // sawtooth chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,14)-1; @@ -233,14 +252,14 @@ int DivPlatformVRC6::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: if (c.chan!=2) { // pulse wave DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_VRC6); - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].pcm=true; } else if (chan[c.chan].furnaceDac) { chan[c.chan].pcm=false; } if (chan[c.chan].pcm) { if (skipRegisterWrites) break; - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].dacSample=ins->amiga.getSample(c.value); if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) { chan[c.chan].dacSample=-1; diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index e2e360b1b..ebb9d6d07 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -23,9 +23,9 @@ #include //#define rWrite(a,v) pendingWrites[a]=v; -#define rWrite(a,v) if (!skipRegisterWrites) { x1_010->ram_w(a,v); if (dumpWrites) { addWrite(a,v); } } +#define rWrite(a,v) if (!skipRegisterWrites) { x1_010.ram_w(a,v); if (dumpWrites) { addWrite(a,v); } } -#define chRead(c,a) x1_010->ram_r((c<<3)|(a&7)) +#define chRead(c,a) x1_010.ram_r((c<<3)|(a&7)) #define chWrite(c,a,v) rWrite((c<<3)|(a&7),v) #define waveWrite(c,a,v) rWrite(0x1000|(chan[c].waveBank<<11)|(c<<7)|(a&0x7f),(v-128)&0xff) #define envFill(c,a) rWrite(0x800|(c<<7)|(a&0x7f),(chan[c].lvol<<4)|chan[c].rvol) @@ -240,10 +240,10 @@ const char* DivPlatformX1_010::getEffectName(unsigned char effect) { void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t h=start; htick(); + x1_010.tick(); - signed int tempL=x1_010->output(0); - signed int tempR=x1_010->output(1); + signed int tempL=x1_010.output(0); + signed int tempR=x1_010.output(1); if (tempL<-32768) tempL=-32768; if (tempL>32767) tempL=32767; @@ -255,11 +255,23 @@ void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t l bufR[h]=stereo?tempR:bufL[h]; for (int i=0; i<16; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=x1_010->chan_out(i); + oscBuf[i]->data[oscBuf[i]->needle++]=x1_010.chan_out(i); } } } +u8 DivPlatformX1_010::read_byte(u32 address) { + if ((sampleMem!=NULL) && (address>17)&7]<<17)|(address&0x1ffff))&0xffffff; + } else { + address&=0xfffff; + } + return sampleMem[address]; + } + return 0; +} + double DivPlatformX1_010::NoteX1_010(int ch, int note) { if (chan[ch].pcm) { // PCM note double off=8192.0; @@ -345,7 +357,7 @@ void DivPlatformX1_010::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { - signed char macroVol=((chan[i].vol&15)*MIN(chan[i].furnacePCM?64:15,chan[i].std.vol.val))/(chan[i].furnacePCM?64:15); + signed char macroVol=((chan[i].vol&15)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/(chan[i].macroVolMul); if ((!isMuted[i]) && (macroVol!=chan[i].outVol)) { chan[i].outVol=macroVol; chan[i].envChanged=true; @@ -475,6 +487,12 @@ void DivPlatformX1_010::tick(bool sysTick) { if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1; } } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active && chan[i].pcm) { + chWrite(i,0,0); + refreshControl(i); + } + } if (chan[i].active) { if (chan[i].ws.tick()) { updateWave(i); @@ -549,8 +567,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { chWrite(c.chan,0,0); // reset previous note DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_X1_010); - if ((ins->type==DIV_INS_AMIGA) || chan[c.chan].pcm) { - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:15; + if ((ins->type==DIV_INS_AMIGA || ins->amiga.useSample) || chan[c.chan].pcm) { + if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -562,9 +581,18 @@ int DivPlatformX1_010::dispatch(DivCommand c) { chan[c.chan].sample=ins->amiga.getSample(c.value); if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { DivSample* s=parent->getSample(chan[c.chan].sample); - chWrite(c.chan,4,(s->offX1_010>>12)&0xff); - int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded - chWrite(c.chan,5,(0x100-(end>>12))&0xff); + if (isBanked) { + chan[c.chan].bankSlot=ins->x1_010.bankSlot; + bankSlot[chan[c.chan].bankSlot]=s->offX1_010>>17; + unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(s->offX1_010&0x1ffff); + chWrite(c.chan,4,(bankedOffs>>12)&0xff); + int end=(bankedOffs+MIN(s->length8,0x1ffff)+0xfff)&~0xfff; // padded + chWrite(c.chan,5,(0x100-(end>>12))&0xff); + } else { + chWrite(c.chan,4,(s->offX1_010>>12)&0xff); + int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded + chWrite(c.chan,5,(0x100-(end>>12))&0xff); + } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note); @@ -594,9 +622,17 @@ int DivPlatformX1_010::dispatch(DivCommand c) { break; } DivSample* s=parent->getSample(12*sampleBank+c.value%12); - chWrite(c.chan,4,(s->offX1_010>>12)&0xff); - int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded - chWrite(c.chan,5,(0x100-(end>>12))&0xff); + if (isBanked) { + bankSlot[chan[c.chan].bankSlot]=s->offX1_010>>17; + unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(s->offX1_010&0x1ffff); + chWrite(c.chan,4,(bankedOffs>>12)&0xff); + int end=(bankedOffs+MIN(s->length8,0x1ffff)+0xfff)&~0xfff; // padded + chWrite(c.chan,5,(0x100-(end>>12))&0xff); + } else { + chWrite(c.chan,4,(s->offX1_010>>12)&0xff); + int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded + chWrite(c.chan,5,(0x100-(end>>12))&0xff); + } chan[c.chan].baseFreq=(((unsigned int)s->rate)<<4)/(chipClock/512); chan[c.chan].freqChanged=true; } @@ -813,6 +849,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) { chan[c.chan].autoEnvDen=c.value&15; chan[c.chan].freqChanged=true; break; + case DIV_CMD_X1_010_SAMPLE_BANK_SLOT: + chan[c.chan].bankSlot=c.value&7; + break; case DIV_CMD_GET_VOLMAX: return 15; break; @@ -853,7 +892,7 @@ DivDispatchOscBuffer* DivPlatformX1_010::getOscBuffer(int ch) { unsigned char* DivPlatformX1_010::getRegisterPool() { for (int i=0; i<0x2000; i++) { - regPool[i]=x1_010->ram_r(i); + regPool[i]=x1_010.ram_r(i); } return regPool; } @@ -871,12 +910,16 @@ void DivPlatformX1_010::reset() { chan[i].ws.setEngine(parent); chan[i].ws.init(NULL,128,255,false); } - x1_010->reset(); + x1_010.reset(); sampleBank=0; // set per-channel initial panning for (int i=0; i<16; i++) { chWrite(i,0,0); } + // set initial bank + for (int b=0; b<8; b++) { + bankSlot[b]=b; + } } bool DivPlatformX1_010::isStereo() { @@ -931,15 +974,15 @@ void DivPlatformX1_010::poke(std::vector& wlist) { } const void* DivPlatformX1_010::getSampleMem(int index) { - return index == 0 ? sampleMem : 0; + return index >= 0 ? sampleMem : 0; } size_t DivPlatformX1_010::getSampleMemCapacity(int index) { - return index == 0 ? 1048576 : 0; + return index == 0 ? (isBanked?16777216:1048576):0; } size_t DivPlatformX1_010::getSampleMemUsage(int index) { - return index == 0 ? sampleMemLen : 0; + return index >= 0 ? sampleMemLen : 0; } void DivPlatformX1_010::renderSamples() { @@ -949,12 +992,14 @@ void DivPlatformX1_010::renderSamples() { for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; int paddedLen=(s->length8+4095)&(~0xfff); + if (isBanked) { // fit sample bank size to 128KB for Seta 2 external bankswitching logic (not emulated yet!) - if (paddedLen>131072) { - paddedLen=131072; - } - if ((memPos&0xfe0000)!=((memPos+paddedLen)&0xfe0000)) { - memPos=(memPos+0x1ffff)&0xfe0000; + if (paddedLen>131072) { + paddedLen=131072; + } + if ((memPos&0xfe0000)!=((memPos+paddedLen)&0xfe0000)) { + memPos=(memPos+0x1ffff)&0xfe0000; + } } if (memPos>=getSampleMemCapacity()) { logW("out of X1-010 memory for sample %d!",i); @@ -972,6 +1017,10 @@ void DivPlatformX1_010::renderSamples() { sampleMemLen=memPos+256; } +void DivPlatformX1_010::setBanked(bool banked) { + isBanked=banked; +} + int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { parent=p; dumpWrites=false; @@ -984,9 +1033,7 @@ int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned in setFlags(flags); sampleMem=new unsigned char[getSampleMemCapacity()]; sampleMemLen=0; - intf.memory=sampleMem; - x1_010=new x1_010_core(intf); - x1_010->reset(); + x1_010.reset(); reset(); return 16; } @@ -995,7 +1042,6 @@ void DivPlatformX1_010::quit() { for (int i=0; i<16; i++) { delete oscBuf[i]; } - delete x1_010; delete[] sampleMem; } diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index 7a85b6336..e75c79495 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -26,18 +26,7 @@ #include "../waveSynth.h" #include "sound/x1_010/x1_010.hpp" -class DivX1_010Interface: public x1_010_mem_intf { - public: - unsigned char* memory; - int sampleBank; - virtual u8 read_byte(u32 address) override { - if (memory==NULL) return 0; - return memory[address & 0xfffff]; - } - DivX1_010Interface(): memory(NULL), sampleBank(0) {} -}; - -class DivPlatformX1_010: public DivDispatch { +class DivPlatformX1_010: public DivDispatch, public x1_010_mem_intf { struct Channel { struct Envelope { struct EnvFlag { @@ -84,7 +73,9 @@ class DivPlatformX1_010: public DivDispatch { unsigned char pan, autoEnvNum, autoEnvDen; bool active, insChanged, envChanged, freqChanged, keyOn, keyOff, inPorta, furnacePCM, pcm; int vol, outVol, lvol, rvol; + int macroVolMul; unsigned char waveBank; + unsigned int bankSlot; Envelope env; DivMacroInt std; DivWaveSynth ws; @@ -109,7 +100,9 @@ class DivPlatformX1_010: public DivDispatch { pan(255), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), envChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), furnacePCM(false), pcm(false), vol(15), outVol(15), lvol(15), rvol(15), - waveBank(0) {} + macroVolMul(15), + waveBank(0), + bankSlot(0) {} }; Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; @@ -118,14 +111,18 @@ class DivPlatformX1_010: public DivDispatch { unsigned char* sampleMem; size_t sampleMemLen; unsigned char sampleBank; - DivX1_010Interface intf; - x1_010_core* x1_010; + x1_010_core x1_010; + + bool isBanked=false; + unsigned int bankSlot[8]; + unsigned char regPool[0x2000]; double NoteX1_010(int ch, int note); void updateWave(int ch); void updateEnvelope(int ch); friend void putDispatchChan(void*,int,int); public: + u8 read_byte(u32 address); void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); @@ -150,8 +147,13 @@ class DivPlatformX1_010: public DivDispatch { void renderSamples(); const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); + void setBanked(bool banked); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformX1_010(): + DivDispatch(), + x1_010_mem_intf(), + x1_010(*this) {} ~DivPlatformX1_010(); }; diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index c3cf52a06..cfac0f6e1 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -647,12 +647,46 @@ void DivPlatformYM2608::tick(bool sysTick) { chan[i].keyOff=false; } } + // RSS + for (int i=9; i<15; i++) { + if (chan[i].furnacePCM) { + chan[i].std.next(); + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; + } + if (chan[i].std.duty.had) { + if (globalRSSVolume!=(chan[i].std.duty.val&0x3f)) { + globalRSSVolume=chan[i].std.duty.val&0x3f; + immWrite(0x11,globalRSSVolume); + } + } + if (chan[i].std.panL.had) { + chan[i].pan=chan[i].std.panL.val&3; + } + if (chan[i].std.phaseReset.had) { + if ((chan[i].std.phaseReset.val==1) && chan[i].active) { + chan[i].keyOn=true; + } + } + if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) { + immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); + } + if (chan[i].keyOff) { + writeRSSOff|=(1<<(i-9)); + chan[i].keyOff=false; + } + if (chan[i].keyOn) { + writeRSSOn|=(1<<(i-9)); + chan[i].keyOn=false; + } + } + } // ADPCM-B if (chan[15].furnacePCM) { chan[15].std.next(); if (chan[15].std.vol.had) { - chan[15].outVol=(chan[15].vol*MIN(64,chan[15].std.vol.val))/64; + chan[15].outVol=(chan[15].vol*MIN(chan[15].macroVolMul,chan[15].std.vol.val))/chan[15].macroVolMul; immWrite(0x10b,chan[15].outVol); } @@ -671,16 +705,42 @@ void DivPlatformYM2608::tick(bool sysTick) { chan[15].freqChanged=true; } } + if (chan[15].std.panL.had) { + if (chan[15].pan!=(chan[15].std.panL.val&3)) { + chan[15].pan=chan[15].std.panL.val&3; + if (!isMuted[15]) { + immWrite(0x101,(isMuted[15]?0:(chan[15].pan<<6))|2); + } + } + } + if (chan[15].std.phaseReset.had) { + if ((chan[15].std.phaseReset.val==1) && chan[15].active) { + chan[15].keyOn=true; + } + } } - if (chan[15].freqChanged) { - if (chan[15].sample>=0 && chan[15].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0; - chan[15].freq=parent->calcFreq(chan[15].baseFreq,chan[15].pitch,false,4,chan[15].pitch2,(double)chipClock/144,off); - } else { - chan[15].freq=0; + if (chan[15].freqChanged || chan[15].keyOn || chan[15].keyOff) { + if (chan[15].furnacePCM) { + if (chan[15].sample>=0 && chan[15].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0; + chan[15].freq=parent->calcFreq(chan[15].baseFreq,chan[15].pitch,false,4,chan[15].pitch2,(double)chipClock/144,off); + } else { + chan[15].freq=0; + } } immWrite(0x109,chan[15].freq&0xff); immWrite(0x10a,(chan[15].freq>>8)&0xff); + if (chan[15].keyOn || chan[15].keyOff) { + immWrite(0x100,0x01); // reset + if (chan[15].active && chan[15].keyOn && !chan[15].keyOff) { + if (chan[15].sample>=0 && chan[15].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[15].sample); + immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat + } + } + chan[15].keyOn=false; + chan[15].keyOff=false; + } chan[15].freqChanged=false; } @@ -740,7 +800,8 @@ int DivPlatformYM2608::dispatch(DivCommand c) { case DIV_CMD_NOTE_ON: { if (c.chan>14) { // ADPCM-B DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -761,7 +822,6 @@ int DivPlatformYM2608::dispatch(DivCommand c) { immWrite(0x104,(end>>5)&0xff); immWrite(0x105,(end>>13)&0xff); immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2); - immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -782,6 +842,24 @@ int DivPlatformYM2608::dispatch(DivCommand c) { chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { + break; + } + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x102,(s->offB>>5)&0xff); + immWrite(0x103,(s->offB>>13)&0xff); + int end=s->offB+s->lengthB-1; + immWrite(0x104,(end>>5)&0xff); + immWrite(0x105,(end>>13)&0xff); + immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2); + int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); + immWrite(0x109,freq&0xff); + immWrite(0x10a,(freq>>8)&0xff); + immWrite(0x10b,chan[c.chan].outVol); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { immWrite(0x100,0x01); // reset immWrite(0x102,0); immWrite(0x103,0); @@ -789,26 +867,31 @@ int DivPlatformYM2608::dispatch(DivCommand c) { immWrite(0x105,0); break; } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x102,(s->offB>>5)&0xff); - immWrite(0x103,(s->offB>>13)&0xff); - int end=s->offB+s->lengthB-1; - immWrite(0x104,(end>>5)&0xff); - immWrite(0x105,(end>>13)&0xff); - immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2); - immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat - int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); - immWrite(0x109,freq&0xff); - immWrite(0x10a,(freq>>8)&0xff); } break; } if (c.chan>8) { // RSS - if (skipRegisterWrites) break; - if (!isMuted[c.chan]) { - writeRSSOn|=(1<<(c.chan-9)); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { + chan[c.chan].furnacePCM=true; + } else { + chan[c.chan].furnacePCM=false; } - immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + if (skipRegisterWrites) break; + if (chan[c.chan].furnacePCM) { + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + } + } else { + chan[c.chan].macroInit(NULL); + chan[c.chan].outVol=chan[c.chan].vol; + immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); @@ -861,28 +944,12 @@ int DivPlatformYM2608::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_OFF: - if (c.chan>14) { - immWrite(0x100,0x01); // reset - break; - } - if (c.chan>8) { - writeRSSOff|=1<<(c.chan-9); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: - if (c.chan>14) { - immWrite(0x100,0x01); // reset - break; - } - if (c.chan>8) { - writeRSSOff|=1<<(c.chan-9); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; @@ -901,7 +968,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { break; } if (c.chan>8) { // ADPCM-A - immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } for (int i=0; i<4; i++) { @@ -936,7 +1003,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { break; } if (c.chan>8) { - immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); @@ -1205,7 +1272,7 @@ void DivPlatformYM2608::muteChannel(int ch, bool mute) { immWrite(0x101,(isMuted[ch]?0:(chan[ch].pan<<6))|2); } if (ch>8) { // ADPCM-A - immWrite(0x18+(ch-9),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol)); + immWrite(0x18+(ch-9),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].outVol)); return; } if (ch>5) { // PSG @@ -1313,6 +1380,7 @@ void DivPlatformYM2608::reset() { sampleBank=0; writeRSSOff=0; writeRSSOn=0; + globalRSSVolume=0x3f; delay=0; diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index ac38a8c08..3a75f863c 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -54,6 +54,7 @@ class DivPlatformYM2608: public DivPlatformOPN { int vol, outVol; int sample; unsigned char pan; + int macroVolMul; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -84,7 +85,8 @@ class DivPlatformYM2608: public DivPlatformOPN { vol(0), outVol(15), sample(-1), - pan(3) {} + pan(3), + macroVolMul(255) {} }; Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; @@ -99,6 +101,7 @@ class DivPlatformYM2608: public DivPlatformOPN { DivPlatformAY8910* ay; unsigned char sampleBank; unsigned char writeRSSOff, writeRSSOn; + int globalRSSVolume; bool extMode; unsigned char prescale; diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 4e01b005c..66bdd8e54 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -18,15 +18,8 @@ */ #include "ym2610.h" -#include "sound/ymfm/ymfm.h" -#include "../engine.h" -#include "../../ta-log.h" -#include #include -#define CHIP_FREQBASE fmFreqBase -#define CHIP_DIVIDER fmDivBase - const char* regCheatSheetYM2610[]={ // SSG "SSG_FreqL_A", "000", @@ -235,85 +228,6 @@ const char* regCheatSheetYM2610[]={ NULL }; -const void* DivPlatformYM2610Base::getSampleMem(int index) { - return index == 0 ? adpcmAMem : index == 1 ? adpcmBMem : NULL; -} - -size_t DivPlatformYM2610Base::getSampleMemCapacity(int index) { - return index == 0 ? 16777216 : index == 1 ? 16777216 : 0; -} - -size_t DivPlatformYM2610Base::getSampleMemUsage(int index) { - return index == 0 ? adpcmAMemLen : index == 1 ? adpcmBMemLen : 0; -} - -void DivPlatformYM2610Base::renderSamples() { - memset(adpcmAMem,0,getSampleMemCapacity(0)); - - size_t memPos=0; - for (int i=0; isong.sampleLen; i++) { - DivSample* s=parent->song.sample[i]; - int paddedLen=(s->lengthA+255)&(~0xff); - if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) { - memPos=(memPos+0xfffff)&0xf00000; - } - if (memPos>=getSampleMemCapacity(0)) { - logW("out of ADPCM-A memory for sample %d!",i); - break; - } - if (memPos+paddedLen>=getSampleMemCapacity(0)) { - memcpy(adpcmAMem+memPos,s->dataA,getSampleMemCapacity(0)-memPos); - logW("out of ADPCM-A memory for sample %d!",i); - } else { - memcpy(adpcmAMem+memPos,s->dataA,paddedLen); - } - s->offA=memPos; - memPos+=paddedLen; - } - adpcmAMemLen=memPos+256; - - memset(adpcmBMem,0,getSampleMemCapacity(1)); - - memPos=0; - for (int i=0; isong.sampleLen; i++) { - DivSample* s=parent->song.sample[i]; - int paddedLen=(s->lengthB+255)&(~0xff); - if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) { - memPos=(memPos+0xfffff)&0xf00000; - } - if (memPos>=getSampleMemCapacity(1)) { - logW("out of ADPCM-B memory for sample %d!",i); - break; - } - if (memPos+paddedLen>=getSampleMemCapacity(1)) { - memcpy(adpcmBMem+memPos,s->dataB,getSampleMemCapacity(1)-memPos); - logW("out of ADPCM-B memory for sample %d!",i); - } else { - memcpy(adpcmBMem+memPos,s->dataB,paddedLen); - } - s->offB=memPos; - memPos+=paddedLen; - } - adpcmBMemLen=memPos+256; -} - -int DivPlatformYM2610Base::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { - parent=p; - adpcmAMem=new unsigned char[getSampleMemCapacity(0)]; - adpcmAMemLen=0; - adpcmBMem=new unsigned char[getSampleMemCapacity(1)]; - adpcmBMemLen=0; - iface.adpcmAMem=adpcmAMem; - iface.adpcmBMem=adpcmBMem; - iface.sampleBank=0; - return 0; -} - -void DivPlatformYM2610Base::quit() { - delete[] adpcmAMem; - delete[] adpcmBMem; -} - const char** DivPlatformYM2610::getRegisterSheet() { return regCheatSheetYM2610; } @@ -438,24 +352,6 @@ const char* DivPlatformYM2610::getEffectName(unsigned char effect) { return NULL; } -double DivPlatformYM2610::NOTE_OPNB(int ch, int note) { - if (ch>6) { // ADPCM - return NOTE_ADPCMB(note); - } else if (ch>3) { // PSG - return NOTE_PERIODIC(note); - } - // FM - return NOTE_FNUM_BLOCK(note,11); -} - -double DivPlatformYM2610::NOTE_ADPCMB(int note) { - if (chan[13].sample>=0 && chan[13].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[13].sample)->centerRate)/8363.0; - return parent->calcBaseFreq((double)chipClock/144,off,note,false); - } - return 0; -} - void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; @@ -501,20 +397,20 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l bufL[h]=os[0]; bufR[h]=os[1]; - for (int i=0; i<4; i++) { + for (int i=0; idata[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1)); } ssge->get_last_out(ssgOut); - for (int i=4; i<7; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-4]; + for (int i=psgChanOffs; idata[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]; } - for (int i=7; i<13; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-7]->get_last_out(0)+adpcmAChan[i-7]->get_last_out(1); + for (int i=adpcmAChanOffs; idata[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1); } - oscBuf[13]->data[oscBuf[13]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); + oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); } } @@ -528,7 +424,7 @@ void DivPlatformYM2610::tick(bool sysTick) { ay->getRegisterWrites().clear(); // FM - for (int i=0; i<4; i++) { + for (int i=0; i=0 && chan[i].samplesong.sampleLen) { + writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); + } + chan[i].keyOn=false; } } } - if (chan[13].freqChanged) { - if (chan[13].sample>=0 && chan[13].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[13].sample)->centerRate)/8363.0; - chan[13].freq=parent->calcFreq(chan[13].baseFreq,chan[13].pitch,false,4,chan[13].pitch2,(double)chipClock/144,off); - } else { - chan[13].freq=0; + // ADPCM-B + if (chan[adpcmBChanOffs].furnacePCM) { + chan[adpcmBChanOffs].std.next(); + + if (chan[adpcmBChanOffs].std.vol.had) { + chan[adpcmBChanOffs].outVol=(chan[adpcmBChanOffs].vol*MIN(chan[adpcmBChanOffs].macroVolMul,chan[adpcmBChanOffs].std.vol.val))/chan[adpcmBChanOffs].macroVolMul; + immWrite(0x1b,chan[adpcmBChanOffs].outVol); } - immWrite(0x19,chan[13].freq&0xff); - immWrite(0x1a,(chan[13].freq>>8)&0xff); - chan[13].freqChanged=false; + + if (chan[adpcmBChanOffs].std.arp.had) { + if (!chan[adpcmBChanOffs].inPorta) { + if (chan[adpcmBChanOffs].std.arp.mode) { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].std.arp.val); + } else { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note+(signed char)chan[adpcmBChanOffs].std.arp.val); + } + } + chan[adpcmBChanOffs].freqChanged=true; + } else { + if (chan[adpcmBChanOffs].std.arp.mode && chan[adpcmBChanOffs].std.arp.finished) { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note); + chan[adpcmBChanOffs].freqChanged=true; + } + } + if (chan[adpcmBChanOffs].std.panL.had) { + if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) { + chan[adpcmBChanOffs].pan=chan[adpcmBChanOffs].std.panL.val&3; + if (!isMuted[adpcmBChanOffs]) { + immWrite(0x11,(isMuted[adpcmBChanOffs]?0:(chan[adpcmBChanOffs].pan<<6))); + } + } + } + if (chan[adpcmBChanOffs].std.phaseReset.had) { + if ((chan[adpcmBChanOffs].std.phaseReset.val==1) && chan[adpcmBChanOffs].active) { + chan[adpcmBChanOffs].keyOn=true; + } + } + } + if (chan[adpcmBChanOffs].freqChanged || chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { + if (chan[adpcmBChanOffs].furnacePCM) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/8363.0; + chan[adpcmBChanOffs].freq=parent->calcFreq(chan[adpcmBChanOffs].baseFreq,chan[adpcmBChanOffs].pitch,false,4,chan[adpcmBChanOffs].pitch2,(double)chipClock/144,off); + } else { + chan[adpcmBChanOffs].freq=0; + } + immWrite(0x19,chan[adpcmBChanOffs].freq&0xff); + immWrite(0x1a,(chan[adpcmBChanOffs].freq>>8)&0xff); + } + if (chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { + immWrite(0x10,0x01); // reset + if (chan[adpcmBChanOffs].active && chan[adpcmBChanOffs].keyOn && !chan[adpcmBChanOffs].keyOff) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[adpcmBChanOffs].sample); + immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat + } + } + chan[adpcmBChanOffs].keyOn=false; + chan[adpcmBChanOffs].keyOff=false; + } + chan[adpcmBChanOffs].freqChanged=false; + } + + if (writeADPCMAOff) { + immWrite(0x100,0x80|writeADPCMAOff); + writeADPCMAOff=0; } for (int i=16; i<512; i++) { @@ -733,7 +696,7 @@ void DivPlatformYM2610::tick(bool sysTick) { } } - for (int i=0; i<4; i++) { + for (int i=0; isong.linearPitch==2) { @@ -761,18 +724,24 @@ void DivPlatformYM2610::tick(bool sysTick) { chan[i].keyOn=false; } } + + if (writeADPCMAOn) { + immWrite(0x100,writeADPCMAOn); + writeADPCMAOn=0; + } } int DivPlatformYM2610::dispatch(DivCommand c) { - if (c.chan>3 && c.chan<7) { - c.chan-=4; + if (c.chan>=psgChanOffs && c.chan<7) { + c.chan-=psgChanOffs; return ay->dispatch(c); } switch (c.cmd) { case DIV_CMD_NOTE_ON: { - if (c.chan>12) { // ADPCM-B + if (c.chan>=adpcmBChanOffs) { // ADPCM-B DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -793,7 +762,6 @@ int DivPlatformYM2610::dispatch(DivCommand c) { immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -814,50 +782,104 @@ int DivPlatformYM2610::dispatch(DivCommand c) { chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - immWrite(0x10,0x01); // reset - immWrite(0x12,0); - immWrite(0x13,0); - immWrite(0x14,0); - immWrite(0x15,0); break; } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x12,(s->offB>>8)&0xff); - immWrite(0x13,s->offB>>16); - int end=s->offB+s->lengthB-1; - immWrite(0x14,(end>>8)&0xff); - immWrite(0x15,end>>16); - immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat - int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); - immWrite(0x19,freq&0xff); - immWrite(0x1a,(freq>>8)&0xff); + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(12*sampleBank+c.value%12); + immWrite(0x12,(s->offB>>8)&0xff); + immWrite(0x13,s->offB>>16); + int end=s->offB+s->lengthB-1; + immWrite(0x14,(end>>8)&0xff); + immWrite(0x15,end>>16); + immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); + int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); + immWrite(0x19,freq&0xff); + immWrite(0x1a,(freq>>8)&0xff); + immWrite(0x1b,chan[c.chan].outVol); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + immWrite(0x10,0x01); // reset + immWrite(0x12,0); + immWrite(0x13,0); + immWrite(0x14,0); + immWrite(0x15,0); + break; + } } break; } - if (c.chan>6) { // ADPCM-A - if (skipRegisterWrites) break; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - immWrite(0x100,0x80|(1<<(c.chan-7))); - immWrite(0x110+c.chan-7,0); - immWrite(0x118+c.chan-7,0); - immWrite(0x120+c.chan-7,0); - immWrite(0x128+c.chan-7,0); - break; + if (c.chan>=adpcmAChanOffs) { // ADPCM-A + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { + chan[c.chan].furnacePCM=true; + } else { + chan[c.chan].furnacePCM=false; + } + if (skipRegisterWrites) break; + if (chan[c.chan].furnacePCM) { + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + chan[c.chan].sample=ins->amiga.getSample(c.value); + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff); + immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16); + int end=s->offA+s->lengthA-1; + immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); + immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); + immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); + immWrite(0x110+c.chan-adpcmAChanOffs,0); + immWrite(0x118+c.chan-adpcmAChanOffs,0); + immWrite(0x120+c.chan-adpcmAChanOffs,0); + immWrite(0x128+c.chan-adpcmAChanOffs,0); + break; + } + } else { + chan[c.chan].sample=-1; + chan[c.chan].macroInit(NULL); + chan[c.chan].outVol=chan[c.chan].vol; + if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { + break; + } + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(12*sampleBank+c.value%12); + immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff); + immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16); + int end=s->offA+s->lengthA-1; + immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); + immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); + immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); + immWrite(0x110+c.chan-adpcmAChanOffs,0); + immWrite(0x118+c.chan-adpcmAChanOffs,0); + immWrite(0x120+c.chan-adpcmAChanOffs,0); + immWrite(0x128+c.chan-adpcmAChanOffs,0); + break; + } } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x110+c.chan-7,(s->offA>>8)&0xff); - immWrite(0x118+c.chan-7,s->offA>>16); - int end=s->offA+s->lengthA-1; - immWrite(0x120+c.chan-7,(end>>8)&0xff); - immWrite(0x128+c.chan-7,end>>16); - immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); - immWrite(0x100,0x00|(1<<(c.chan-7))); break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroInit(ins); - if (c.chan<4) { + if (c.chan12) { - immWrite(0x10,0x01); // reset - break; - } - if (c.chan>6) { - immWrite(0x100,0x80|(1<<(c.chan-7))); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: - if (c.chan>12) { - immWrite(0x10,0x01); // reset - break; - } - if (c.chan>6) { - immWrite(0x100,0x80|(1<<(c.chan-7))); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; @@ -940,12 +946,12 @@ int DivPlatformYM2610::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (c.chan>12) { // ADPCM-B + if (c.chan>=adpcmBChanOffs) { // ADPCM-B immWrite(0x1b,chan[c.chan].outVol); break; } - if (c.chan>6) { // ADPCM-A - immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + if (c.chan>=adpcmAChanOffs) { // ADPCM-A + immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } for (int i=0; i<4; i++) { @@ -959,6 +965,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) { } break; } + case DIV_CMD_ADPCMA_GLOBAL_VOLUME: { + if (globalADPCMAVolume!=(c.value&0x3f)) { + globalADPCMAVolume=c.value&0x3f; + immWrite(0x101,globalADPCMAVolume&0x3f); + } + break; + } case DIV_CMD_GET_VOLUME: { return chan[c.chan].vol; break; @@ -975,25 +988,25 @@ int DivPlatformYM2610::dispatch(DivCommand c) { } else { chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1); } - if (c.chan>12) { + if (c.chan>=adpcmBChanOffs) { immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); break; } - if (c.chan>6) { - immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + if (c.chan>=adpcmAChanOffs) { + immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); break; } case DIV_CMD_PITCH: { - if (c.chan==13 && !chan[c.chan].furnacePCM) break; + if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; } case DIV_CMD_NOTE_PORTA: { - if (c.chan>3 || parent->song.linearPitch==2) { // PSG, ADPCM-B + if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B int destFreq=NOTE_OPNB(c.chan,c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { @@ -1027,7 +1040,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { iface.sampleBank=sampleBank; break; case DIV_CMD_LEGATO: { - if (c.chan==13 && !chan[c.chan].furnacePCM) break; + if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value); chan[c.chan].freqChanged=true; break; @@ -1044,13 +1057,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } case DIV_CMD_FM_FB: { - if (c.chan>3) break; + if (c.chan>=psgChanOffs) break; chan[c.chan].state.fb=c.value&7; rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); break; } case DIV_CMD_FM_MULT: { - if (c.chan>3) break; + if (c.chan>=psgChanOffs) break; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.mult=c.value2&15; @@ -1058,7 +1071,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } case DIV_CMD_FM_TL: { - if (c.chan>3) break; + if (c.chan>=psgChanOffs) break; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; @@ -1070,7 +1083,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; } case DIV_CMD_FM_AR: { - if (c.chan>3) break; + if (c.chan>=psgChanOffs) break; if (c.value<0) { for (int i=0; i<4; i++) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; @@ -1221,13 +1234,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) { return 0; break; case DIV_CMD_GET_VOLMAX: - if (c.chan>12) return 255; - if (c.chan>6) return 31; - if (c.chan>3) return 15; + if (c.chan>=adpcmBChanOffs) return 255; + if (c.chan>=adpcmAChanOffs) return 31; + if (c.chan>=psgChanOffs) return 15; return 127; break; case DIV_CMD_PRE_PORTA: - if (c.chan>3) { + if (c.chan>=psgChanOffs) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); } @@ -1245,15 +1258,8 @@ int DivPlatformYM2610::dispatch(DivCommand c) { void DivPlatformYM2610::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - if (ch>12) { // ADPCM-B - immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6)); - } - if (ch>6) { // ADPCM-A - immWrite(0x108+(ch-7),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol)); - return; - } - if (ch>3) { // PSG - ay->muteChannel(ch-4,mute); + if (ch>=psgChanOffs) { // PSG + DivPlatformYM2610Base::muteChannel(ch,mute); return; } // FM @@ -1261,7 +1267,7 @@ void DivPlatformYM2610::muteChannel(int ch, bool mute) { } void DivPlatformYM2610::forceIns() { - for (int i=0; i<4; i++) { + for (int i=0; i=4 && ch<7) return ay->getChanMacroInt(ch-4); + if (ch>=psgChanOffs && chgetChanMacroInt(ch-psgChanOffs); return &chan[ch].std; } @@ -1336,17 +1342,20 @@ void DivPlatformYM2610::reset() { chan[i]=DivPlatformYM2610::Channel(); chan[i].std.setEngine(parent); } - for (int i=0; i<4; i++) { + for (int i=0; ireset(); - ay->getRegisterWrites().clear(); - ay->flushWrites(); } bool DivPlatformYM2610::isStereo() { @@ -1377,7 +1383,7 @@ bool DivPlatformYM2610::isStereo() { } bool DivPlatformYM2610::keyOffAffectsArp(int ch) { - return (ch>3); + return (ch>=psgChanOffs); } void DivPlatformYM2610::notifyInsChange(int ins) { @@ -1398,46 +1404,13 @@ void DivPlatformYM2610::setSkipRegisterWrites(bool value) { ay->setSkipRegisterWrites(value); } -void DivPlatformYM2610::setFlags(unsigned int flags) { - switch (flags&0xff) { - default: - case 0x00: - chipClock=8000000.0; - break; - case 0x01: - chipClock=24167829/3; - break; - } - rate=chipClock/16; - for (int i=0; i<14; i++) { - oscBuf[i]->rate=rate; - } -} - int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { DivPlatformYM2610Base::init(p, channels, sugRate, flags); - dumpWrites=false; - skipRegisterWrites=false; - for (int i=0; i<14; i++) { - isMuted[i]=false; - oscBuf[i]=new DivDispatchOscBuffer; - } - fm=new ymfm::ym2610(iface); - setFlags(flags); - // YM2149, 2MHz - ay=new DivPlatformAY8910(true,chipClock,32); - ay->init(p,3,sugRate,16); - ay->toggleRegisterDump(true); reset(); return 14; } void DivPlatformYM2610::quit() { - for (int i=0; i<14; i++) { - delete oscBuf[i]; - } - ay->quit(); - delete ay; delete fm; DivPlatformYM2610Base::quit(); } diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index dde7ed105..a1a8f154f 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -19,41 +19,9 @@ #ifndef _YM2610_H #define _YM2610_H -#include "fmshared_OPN.h" -#include "../macroInt.h" -#include "ay.h" -#include "sound/ymfm/ymfm_opn.h" +#include "ym2610shared.h" -class DivYM2610Interface: public ymfm::ymfm_interface { - public: - unsigned char* adpcmAMem; - unsigned char* adpcmBMem; - int sampleBank; - uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address); - void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data); - DivYM2610Interface(): adpcmAMem(NULL), adpcmBMem(NULL), sampleBank(0) {} -}; - -class DivPlatformYM2610Base: public DivPlatformOPN { - protected: - unsigned char* adpcmAMem; - size_t adpcmAMemLen; - unsigned char* adpcmBMem; - size_t adpcmBMemLen; - DivYM2610Interface iface; - - public: - const void* getSampleMem(int index); - size_t getSampleMemCapacity(int index); - size_t getSampleMemUsage(int index); - void renderSamples(); - int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); - void quit(); - DivPlatformYM2610Base(): - DivPlatformOPN(9440540.0, 72, 32) {} -}; - -class DivPlatformYM2610: public DivPlatformYM2610Base { +class DivPlatformYM2610: public DivPlatformYM2610Base<14> { protected: const unsigned short chanOffs[4]={ 0x01, 0x02, 0x101, 0x102 @@ -67,64 +35,8 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { 1, 2, 4, 5 }; - struct Channel { - DivInstrumentFM state; - unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; - signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; - int vol, outVol; - int sample; - unsigned char pan; - DivMacroInt std; - void macroInit(DivInstrument* which) { - std.init(which); - pitch2=0; - } - Channel(): - freqH(0), - freqL(0), - freq(0), - baseFreq(0), - pitch(0), - pitch2(0), - portaPauseFreq(0), - note(0), - ins(-1), - psgMode(1), - autoEnvNum(0), - autoEnvDen(0), - active(false), - insChanged(true), - freqChanged(false), - keyOn(false), - keyOff(false), - portaPause(false), - inPorta(false), - furnacePCM(false), - hardReset(false), - vol(0), - outVol(15), - sample(-1), - pan(3) {} - }; - Channel chan[14]; - DivDispatchOscBuffer* oscBuf[14]; - bool isMuted[14]; - ymfm::ym2610* fm; - ymfm::ym2610::output_data fmout; - - DivPlatformAY8910* ay; - - unsigned char sampleBank; - - bool extMode; - - double NOTE_OPNB(int ch, int note); - double NOTE_ADPCMB(int note); friend void putDispatchChan(void*,int,int); - + public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); @@ -146,9 +58,10 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { void poke(std::vector& wlist); const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); - void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformYM2610(): + DivPlatformYM2610Base<14>(1,4,7,13) {} ~DivPlatformYM2610(); }; #endif diff --git a/src/engine/platform/ym2610Interface.cpp b/src/engine/platform/ym2610Interface.cpp index d442ce347..1b13b3743 100644 --- a/src/engine/platform/ym2610Interface.cpp +++ b/src/engine/platform/ym2610Interface.cpp @@ -17,9 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "sound/ymfm/ymfm.h" -#include "ym2610.h" -#include "../engine.h" +#include "ym2610shared.h" uint8_t DivYM2610Interface::ymfm_external_read(ymfm::access_class type, uint32_t address) { switch (type) { diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 1a1f7f0ae..8315e3948 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -18,14 +18,8 @@ */ #include "ym2610b.h" -#include "sound/ymfm/ymfm.h" -#include "../engine.h" -#include #include -#define CHIP_FREQBASE fmFreqBase -#define CHIP_DIVIDER fmDivBase - const char* regCheatSheetYM2610B[]={ // SSG "SSG_FreqL_A", "000", @@ -422,24 +416,6 @@ const char* DivPlatformYM2610B::getEffectName(unsigned char effect) { return NULL; } -double DivPlatformYM2610B::NOTE_OPNB(int ch, int note) { - if (ch>8) { // ADPCM-B - return NOTE_ADPCMB(note); - } else if (ch>5) { // PSG - return NOTE_PERIODIC(note); - } - // FM - return NOTE_FNUM_BLOCK(note,11); -} - -double DivPlatformYM2610B::NOTE_ADPCMB(int note) { - if (chan[15].sample>=0 && chan[15].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0; - return parent->calcBaseFreq((double)chipClock/144,off,note,false); - } - return 0; -} - void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; @@ -484,20 +460,20 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t bufR[h]=os[1]; - for (int i=0; i<6; i++) { + for (int i=0; idata[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1)); } ssge->get_last_out(ssgOut); - for (int i=6; i<9; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-6]; + for (int i=psgChanOffs; idata[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]; } - for (int i=9; i<15; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-9]->get_last_out(0)+adpcmAChan[i-9]->get_last_out(1); + for (int i=adpcmAChanOffs; idata[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1); } - oscBuf[15]->data[oscBuf[15]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); + oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); } } @@ -511,7 +487,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { ay->getRegisterWrites().clear(); // FM - for (int i=0; i<6; i++) { + for (int i=0; i=0 && chan[i].samplesong.sampleLen) { + writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); + } + chan[i].keyOn=false; } } } - if (chan[15].freqChanged) { - if (chan[15].sample>=0 && chan[15].samplesong.sampleLen) { - double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0; - chan[15].freq=parent->calcFreq(chan[15].baseFreq,chan[15].pitch,false,4,chan[15].pitch2,(double)chipClock/144,off); - } else { - chan[15].freq=0; + // ADPCM-B + if (chan[adpcmBChanOffs].furnacePCM) { + chan[adpcmBChanOffs].std.next(); + + if (chan[adpcmBChanOffs].std.vol.had) { + chan[adpcmBChanOffs].outVol=(chan[adpcmBChanOffs].vol*MIN(chan[adpcmBChanOffs].macroVolMul,chan[adpcmBChanOffs].std.vol.val))/chan[adpcmBChanOffs].macroVolMul; + immWrite(0x1b,chan[adpcmBChanOffs].outVol); } - immWrite(0x19,chan[15].freq&0xff); - immWrite(0x1a,(chan[15].freq>>8)&0xff); - chan[15].freqChanged=false; + + if (chan[adpcmBChanOffs].std.arp.had) { + if (!chan[adpcmBChanOffs].inPorta) { + if (chan[adpcmBChanOffs].std.arp.mode) { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].std.arp.val); + } else { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note+(signed char)chan[adpcmBChanOffs].std.arp.val); + } + } + chan[adpcmBChanOffs].freqChanged=true; + } else { + if (chan[adpcmBChanOffs].std.arp.mode && chan[adpcmBChanOffs].std.arp.finished) { + chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note); + chan[adpcmBChanOffs].freqChanged=true; + } + } + if (chan[adpcmBChanOffs].std.panL.had) { + if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) { + chan[adpcmBChanOffs].pan=chan[adpcmBChanOffs].std.panL.val&3; + if (!isMuted[adpcmBChanOffs]) { + immWrite(0x11,(isMuted[adpcmBChanOffs]?0:(chan[adpcmBChanOffs].pan<<6))); + } + } + } + if (chan[adpcmBChanOffs].std.phaseReset.had) { + if ((chan[adpcmBChanOffs].std.phaseReset.val==1) && chan[adpcmBChanOffs].active) { + chan[adpcmBChanOffs].keyOn=true; + } + } + } + if (chan[adpcmBChanOffs].freqChanged || chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { + if (chan[adpcmBChanOffs].furnacePCM) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/8363.0; + chan[adpcmBChanOffs].freq=parent->calcFreq(chan[adpcmBChanOffs].baseFreq,chan[adpcmBChanOffs].pitch,false,4,chan[adpcmBChanOffs].pitch2,(double)chipClock/144,off); + } else { + chan[adpcmBChanOffs].freq=0; + } + immWrite(0x19,chan[adpcmBChanOffs].freq&0xff); + immWrite(0x1a,(chan[adpcmBChanOffs].freq>>8)&0xff); + } + if (chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) { + immWrite(0x10,0x01); // reset + if (chan[adpcmBChanOffs].active && chan[adpcmBChanOffs].keyOn && !chan[adpcmBChanOffs].keyOff) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[adpcmBChanOffs].sample); + immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat + } + } + chan[adpcmBChanOffs].keyOn=false; + chan[adpcmBChanOffs].keyOff=false; + } + chan[adpcmBChanOffs].freqChanged=false; + } + + if (writeADPCMAOff) { + immWrite(0x100,0x80|writeADPCMAOff); + writeADPCMAOff=0; } for (int i=16; i<512; i++) { @@ -715,7 +758,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { } } - for (int i=0; i<6; i++) { + for (int i=0; isong.linearPitch==2) { @@ -743,18 +786,24 @@ void DivPlatformYM2610B::tick(bool sysTick) { chan[i].keyOn=false; } } + + if (writeADPCMAOn) { + immWrite(0x100,writeADPCMAOn); + writeADPCMAOn=0; + } } int DivPlatformYM2610B::dispatch(DivCommand c) { - if (c.chan>5 && c.chan<9) { - c.chan-=6; + if (c.chan>=psgChanOffs && c.chandispatch(c); } switch (c.cmd) { case DIV_CMD_NOTE_ON: { - if (c.chan>14) { // ADPCM-B + if (c.chan>=adpcmBChanOffs) { // ADPCM-B DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; @@ -775,7 +824,6 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { immWrite(0x14,(end>>8)&0xff); immWrite(0x15,end>>16); immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); @@ -796,45 +844,99 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { chan[c.chan].macroInit(NULL); chan[c.chan].outVol=chan[c.chan].vol; if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - immWrite(0x10,0x01); // reset - immWrite(0x12,0); - immWrite(0x13,0); - immWrite(0x14,0); - immWrite(0x15,0); break; } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x12,(s->offB>>8)&0xff); - immWrite(0x13,s->offB>>16); - int end=s->offB+s->lengthB-1; - immWrite(0x14,(end>>8)&0xff); - immWrite(0x15,end>>16); - immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); - immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat - int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); - immWrite(0x19,freq&0xff); - immWrite(0x1a,(freq>>8)&0xff); + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(12*sampleBank+c.value%12); + immWrite(0x12,(s->offB>>8)&0xff); + immWrite(0x13,s->offB>>16); + int end=s->offB+s->lengthB-1; + immWrite(0x14,(end>>8)&0xff); + immWrite(0x15,end>>16); + immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); + int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0); + immWrite(0x19,freq&0xff); + immWrite(0x1a,(freq>>8)&0xff); + immWrite(0x1b,chan[c.chan].outVol); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + immWrite(0x10,0x01); // reset + immWrite(0x12,0); + immWrite(0x13,0); + immWrite(0x14,0); + immWrite(0x15,0); + break; + } } break; } - if (c.chan>8) { // ADPCM-A - if (skipRegisterWrites) break; - if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { - immWrite(0x100,0x80|(1<<(c.chan-9))); - immWrite(0x110+c.chan-9,0); - immWrite(0x118+c.chan-9,0); - immWrite(0x120+c.chan-9,0); - immWrite(0x128+c.chan-9,0); - break; + if (c.chan>=adpcmAChanOffs) { // ADPCM-A + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); + chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; + if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { + chan[c.chan].furnacePCM=true; + } else { + chan[c.chan].furnacePCM=false; + } + if (skipRegisterWrites) break; + if (chan[c.chan].furnacePCM) { + chan[c.chan].macroInit(ins); + if (!chan[c.chan].std.vol.will) { + chan[c.chan].outVol=chan[c.chan].vol; + } + chan[c.chan].sample=ins->amiga.getSample(c.value); + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[c.chan].sample); + immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff); + immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16); + int end=s->offA+s->lengthA-1; + immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); + immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); + immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; + chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note); + chan[c.chan].freqChanged=true; + } + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); + immWrite(0x110+c.chan-adpcmAChanOffs,0); + immWrite(0x118+c.chan-adpcmAChanOffs,0); + immWrite(0x120+c.chan-adpcmAChanOffs,0); + immWrite(0x128+c.chan-adpcmAChanOffs,0); + break; + } + } else { + chan[c.chan].sample=-1; + chan[c.chan].macroInit(NULL); + chan[c.chan].outVol=chan[c.chan].vol; + if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) { + break; + } + chan[c.chan].sample=12*sampleBank+c.value%12; + if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { + DivSample* s=parent->getSample(12*sampleBank+c.value%12); + immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff); + immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16); + int end=s->offA+s->lengthA-1; + immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff); + immWrite(0x128+c.chan-adpcmAChanOffs,end>>16); + immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + } else { + writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs)); + immWrite(0x110+c.chan-adpcmAChanOffs,0); + immWrite(0x118+c.chan-adpcmAChanOffs,0); + immWrite(0x120+c.chan-adpcmAChanOffs,0); + immWrite(0x128+c.chan-adpcmAChanOffs,0); + break; + } } - DivSample* s=parent->getSample(12*sampleBank+c.value%12); - immWrite(0x110+c.chan-9,(s->offA>>8)&0xff); - immWrite(0x118+c.chan-9,s->offA>>16); - int end=s->offA+s->lengthA-1; - immWrite(0x120+c.chan-9,(end>>8)&0xff); - immWrite(0x128+c.chan-9,end>>16); - immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); - immWrite(0x100,0x00|(1<<(c.chan-9))); break; } DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); @@ -887,28 +989,12 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_OFF: - if (c.chan>14) { - immWrite(0x10,0x01); // reset - break; - } - if (c.chan>8) { - immWrite(0x100,0x80|(1<<(c.chan-9))); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: - if (c.chan>14) { - immWrite(0x10,0x01); // reset - break; - } - if (c.chan>8) { - immWrite(0x100,0x80|(1<<(c.chan-9))); - break; - } chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; @@ -922,12 +1008,12 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (c.chan>14) { // ADPCM-B + if (c.chan>=adpcmBChanOffs) { // ADPCM-B immWrite(0x1b,chan[c.chan].outVol); break; } - if (c.chan>8) { // ADPCM-A - immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + if (c.chan>=adpcmAChanOffs) { // ADPCM-A + immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } for (int i=0; i<4; i++) { @@ -941,6 +1027,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { } break; } + case DIV_CMD_ADPCMA_GLOBAL_VOLUME: { + if (globalADPCMAVolume!=(c.value&0x3f)) { + globalADPCMAVolume=c.value&0x3f; + immWrite(0x101,globalADPCMAVolume&0x3f); + } + break; + } case DIV_CMD_GET_VOLUME: { return chan[c.chan].vol; break; @@ -957,25 +1050,25 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { } else { chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1); } - if (c.chan>14) { + if (c.chan>=adpcmBChanOffs) { immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6)); break; } - if (c.chan>8) { - immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol)); + if (c.chan>=adpcmAChanOffs) { + immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); break; } case DIV_CMD_PITCH: { - if (c.chan==15 && !chan[c.chan].furnacePCM) break; + if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; } case DIV_CMD_NOTE_PORTA: { - if (c.chan>5 || parent->song.linearPitch==2) { // PSG, ADPCM-B + if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B int destFreq=NOTE_OPNB(c.chan,c.value2); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { @@ -1009,7 +1102,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { iface.sampleBank=sampleBank; break; case DIV_CMD_LEGATO: { - if (c.chan==15 && !chan[c.chan].furnacePCM) break; + if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value); chan[c.chan].freqChanged=true; break; @@ -1026,13 +1119,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_FM_FB: { - if (c.chan>5) break; + if (c.chan>=psgChanOffs) break; chan[c.chan].state.fb=c.value&7; rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); break; } case DIV_CMD_FM_MULT: { - if (c.chan>5) break; + if (c.chan>=psgChanOffs) break; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.mult=c.value2&15; @@ -1040,7 +1133,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_FM_TL: { - if (c.chan>5) break; + if (c.chan>=psgChanOffs) break; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; @@ -1052,7 +1145,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_FM_AR: { - if (c.chan>5) break; + if (c.chan>=psgChanOffs) break; if (c.value<0) { for (int i=0; i<4; i++) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; @@ -1203,13 +1296,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { return 0; break; case DIV_CMD_GET_VOLMAX: - if (c.chan>14) return 255; - if (c.chan>8) return 31; - if (c.chan>5) return 15; + if (c.chan>=adpcmBChanOffs) return 255; + if (c.chan>=adpcmAChanOffs) return 31; + if (c.chan>=psgChanOffs) return 15; return 127; break; case DIV_CMD_PRE_PORTA: - if (c.chan>5) { + if (c.chan>=psgChanOffs) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); } @@ -1227,15 +1320,8 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { void DivPlatformYM2610B::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - if (ch>14) { // ADPCM-B - immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6)); - } - if (ch>8) { // ADPCM-A - immWrite(0x108+(ch-9),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol)); - return; - } - if (ch>5) { // PSG - ay->muteChannel(ch-6,mute); + if (ch>=psgChanOffs) { // PSG + DivPlatformYM2610Base::muteChannel(ch,mute); return; } // FM @@ -1243,7 +1329,7 @@ void DivPlatformYM2610B::muteChannel(int ch, bool mute) { } void DivPlatformYM2610B::forceIns() { - for (int i=0; i<6; i++) { + for (int i=0; i=6 && ch<9) return ay->getChanMacroInt(ch-6); + if (ch>=psgChanOffs && chgetChanMacroInt(ch-psgChanOffs); return &chan[ch].std; } @@ -1318,17 +1404,20 @@ void DivPlatformYM2610B::reset() { chan[i]=DivPlatformYM2610B::Channel(); chan[i].std.setEngine(parent); } - for (int i=0; i<6; i++) { + for (int i=0; i5); + return (ch>=psgChanOffs); } void DivPlatformYM2610B::notifyInsChange(int ins) { @@ -1380,46 +1470,13 @@ void DivPlatformYM2610B::setSkipRegisterWrites(bool value) { ay->setSkipRegisterWrites(value); } -void DivPlatformYM2610B::setFlags(unsigned int flags) { - switch (flags&0xff) { - default: - case 0x00: - chipClock=8000000.0; - break; - case 0x01: - chipClock=24167829/3; - break; - } - rate=chipClock/16; - for (int i=0; i<16; i++) { - oscBuf[i]->rate=rate; - } -} - int DivPlatformYM2610B::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { DivPlatformYM2610Base::init(p, channels, sugRate, flags); - dumpWrites=false; - skipRegisterWrites=false; - for (int i=0; i<16; i++) { - isMuted[i]=false; - oscBuf[i]=new DivDispatchOscBuffer; - } - fm=new ymfm::ym2610b(iface); - setFlags(flags); - // YM2149, 2MHz - ay=new DivPlatformAY8910(true,chipClock,32); - ay->init(p,3,sugRate,16); - ay->toggleRegisterDump(true); reset(); return 16; } void DivPlatformYM2610B::quit() { - for (int i=0; i<16; i++) { - delete oscBuf[i]; - } - ay->quit(); - delete ay; delete fm; DivPlatformYM2610Base::quit(); } diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index fefb06929..38eaa4e3c 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -19,12 +19,9 @@ #ifndef _YM2610B_H #define _YM2610B_H -#include "ym2610.h" -#include "../macroInt.h" -#include "sound/ymfm/ymfm_opn.h" +#include "ym2610shared.h" - -class DivPlatformYM2610B: public DivPlatformYM2610Base { +class DivPlatformYM2610B: public DivPlatformYM2610Base<16> { protected: const unsigned short chanOffs[6]={ 0x00, 0x01, 0x02, 0x100, 0x101, 0x102 @@ -34,65 +31,8 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { 0, 1, 2, 4, 5, 6 }; - struct Channel { - DivInstrumentFM state; - unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; - signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; - int vol, outVol; - int sample; - unsigned char pan; - DivMacroInt std; - void macroInit(DivInstrument* which) { - std.init(which); - pitch2=0; - } - Channel(): - freqH(0), - freqL(0), - freq(0), - baseFreq(0), - pitch(0), - pitch2(0), - portaPauseFreq(0), - note(0), - ins(-1), - psgMode(1), - autoEnvNum(0), - autoEnvDen(0), - active(false), - insChanged(true), - freqChanged(false), - keyOn(false), - keyOff(false), - portaPause(false), - inPorta(false), - furnacePCM(false), - hardReset(false), - vol(0), - outVol(15), - sample(-1), - pan(3) {} - }; - Channel chan[16]; - DivDispatchOscBuffer* oscBuf[16]; - bool isMuted[16]; - ymfm::ym2610b* fm; - ymfm::ym2610b::output_data fmout; - - DivPlatformAY8910* ay; - unsigned char sampleBank; - - bool extMode; - double fmFreqBase=9440540; - unsigned char ayDiv=32; - - double NOTE_OPNB(int ch, int note); - double NOTE_ADPCMB(int note); friend void putDispatchChan(void*,int,int); - + public: void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); @@ -114,9 +54,10 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { void poke(std::vector& wlist); const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); - void setFlags(unsigned int flags); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); void quit(); + DivPlatformYM2610B(): + DivPlatformYM2610Base<16>(2,6,9,15) {} ~DivPlatformYM2610B(); }; #endif diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 7c8247ff8..9f6e528f8 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -18,31 +18,27 @@ */ #include "ym2610bext.h" -#include "../engine.h" #include -#define CHIP_FREQBASE fmFreqBase -#define CHIP_DIVIDER fmDivBase - int DivPlatformYM2610BExt::dispatch(DivCommand c) { - if (c.chan<2) { + if (c.chan5) { + if (c.chan>(extChanOffs+3)) { c.chan-=3; return DivPlatformYM2610B::dispatch(c); } - int ch=c.chan-2; + int ch=c.chan-extChanOffs; int ordch=orderedOps[ch]; if (!extMode) { - c.chan=2; + c.chan=extChanOffs; return DivPlatformYM2610B::dispatch(c); } switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; // TODO: how does this work?! if (isOpMuted[ch]) { @@ -61,8 +57,8 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { rWrite(baseAddr+0x90,op.ssgEnv&15); } if (opChan[ch].insChanged) { // TODO how does this work? - rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[extChanOffs]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); + rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); } opChan[ch].insChanged=false; @@ -83,7 +79,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_VOLUME: { opChan[ch].vol=c.value; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); @@ -115,7 +111,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { opChan[i].pan=opChan[ch].pan; } } - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); break; } case DIV_CMD_PITCH: { @@ -165,19 +161,19 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { break; } case DIV_CMD_FM_FB: { - chan[2].state.fb=c.value&7; - rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); + chan[extChanOffs].state.fb=c.value&7; + rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3)); break; } case DIV_CMD_FM_MULT: { // TODO - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]]; rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4)); break; } case DIV_CMD_FM_TL: { // TODO - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (isOutput[ins->fm.alg][c.value]) { rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127)); @@ -189,15 +185,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_AR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.ar=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); } } else { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.ar=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); } break; @@ -205,15 +201,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_RS: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.rs=c.value2&3; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.rs=c.value2&3; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } break; @@ -221,15 +217,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_AM: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.am=c.value2&1; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.am=c.value2&1; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } break; @@ -237,15 +233,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_DR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.dr=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.dr=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } break; @@ -253,15 +249,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_SL: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.sl=c.value2&15; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.sl=c.value2&15; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } break; @@ -269,15 +265,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_RR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.rr=c.value2&15; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.rr=c.value2&15; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } break; @@ -285,15 +281,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_D2R: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.d2r=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.d2r=c.value2&31; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } break; @@ -301,15 +297,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_DT: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.dt=c.value&7; - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.dt=c.value2&7; - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } break; @@ -317,15 +313,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { case DIV_CMD_FM_SSG: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[2].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.ssgEnv=8^(c.value2&15); - unsigned short baseAddr=chanOffs[2]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.ssgEnv=8^(c.value2&15); - unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } break; @@ -408,31 +404,31 @@ void DivPlatformYM2610BExt::tick(bool sysTick) { } void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) { - if (ch<2) { + if (ch5) { + if (ch>(extChanOffs+3)) { DivPlatformYM2610B::muteChannel(ch-3,mute); return; } - isOpMuted[ch-2]=mute; + isOpMuted[ch-extChanOffs]=mute; - int ordch=orderedOps[ch-2]; - DivInstrument* ins=parent->getIns(opChan[ch-2].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; + int ordch=orderedOps[ch-extChanOffs]; + DivInstrument* ins=parent->getIns(opChan[ch-extChanOffs].ins,DIV_INS_FM); + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; - if (isOpMuted[ch-2]) { + if (isOpMuted[ch-extChanOffs]) { rWrite(baseAddr+0x40,127); } else if (isOutput[ins->fm.alg][ordch]) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-extChanOffs].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } } void DivPlatformYM2610BExt::forceIns() { - for (int i=0; i<6; i++) { + for (int i=0; iforceIns(); @@ -488,21 +484,21 @@ void DivPlatformYM2610BExt::forceIns() { } void* DivPlatformYM2610BExt::getChanState(int ch) { - if (ch>=6) return &chan[ch-3]; - if (ch>=2) return &opChan[ch-2]; + if (ch>=(extChanOffs+4)) return &chan[ch-3]; + if (ch>=extChanOffs) return &opChan[ch-extChanOffs]; return &chan[ch]; } DivMacroInt* DivPlatformYM2610BExt::getChanMacroInt(int ch) { - if (ch>=9 && ch<12) return ay->getChanMacroInt(ch-9); - if (ch>=6) return &chan[ch-3].std; - if (ch>=2) return NULL; // currently not implemented + if (ch>=(psgChanOffs+3) && ch<(adpcmAChanOffs+3)) return ay->getChanMacroInt(ch-psgChanOffs-3); + if (ch>=(extChanOffs+4)) return &chan[ch-3].std; + if (ch>=extChanOffs) return NULL; // currently not implemented return &chan[ch].std; } DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) { - if (ch>=6) return oscBuf[ch-3]; - if (ch<3) return oscBuf[ch]; + if (ch>=(extChanOffs+4)) return oscBuf[ch-3]; + if (ch<(extChanOffs+1)) return oscBuf[ch]; return NULL; } @@ -520,7 +516,7 @@ void DivPlatformYM2610BExt::reset() { } bool DivPlatformYM2610BExt::keyOffAffectsArp(int ch) { - return (ch>8); + return (ch>=(psgChanOffs+3)); } void DivPlatformYM2610BExt::notifyInsChange(int ins) { diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index 732678fe5..c54586d36 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -22,19 +22,7 @@ #include "ym2610b.h" class DivPlatformYM2610BExt: public DivPlatformYM2610B { - struct OpChannel { - DivMacroInt std; - unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; - signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; - int vol; - unsigned char pan; - // UGLY - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), vol(0), pan(3) {} - }; - OpChannel opChan[4]; + DivPlatformYM2610Base::OpChannel opChan[4]; bool isOpMuted[4]; friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index b2bd06a8c..ca385f3dc 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -18,31 +18,27 @@ */ #include "ym2610ext.h" -#include "../engine.h" #include -#define CHIP_FREQBASE fmFreqBase -#define CHIP_DIVIDER fmDivBase - int DivPlatformYM2610Ext::dispatch(DivCommand c) { - if (c.chan<1) { + if (c.chan4) { + if (c.chan>(extChanOffs+3)) { c.chan-=3; return DivPlatformYM2610::dispatch(c); } - int ch=c.chan-1; + int ch=c.chan-extChanOffs; int ordch=orderedOps[ch]; if (!extMode) { - c.chan=2; + c.chan=extChanOffs; return DivPlatformYM2610::dispatch(c); } switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[1]|opOffs[ordch]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; // TODO: how does this work?! if (isOpMuted[ch]) { @@ -61,8 +57,8 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { rWrite(baseAddr+0x90,op.ssgEnv&15); } if (opChan[ch].insChanged) { // TODO how does this work? - rWrite(chanOffs[1]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); - rWrite(chanOffs[1]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[extChanOffs]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); + rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); } opChan[ch].insChanged=false; @@ -83,7 +79,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_VOLUME: { opChan[ch].vol=c.value; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[1]|opOffs[ordch]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); @@ -115,7 +111,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { opChan[i].pan=opChan[ch].pan; } } - rWrite(chanOffs[1]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); + rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); break; } case DIV_CMD_PITCH: { @@ -165,19 +161,19 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { break; } case DIV_CMD_FM_FB: { - chan[1].state.fb=c.value&7; - rWrite(chanOffs[1]+ADDR_FB_ALG,(chan[1].state.alg&7)|(chan[1].state.fb<<3)); + chan[extChanOffs].state.fb=c.value&7; + rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3)); break; } case DIV_CMD_FM_MULT: { // TODO - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]]; rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4)); break; } case DIV_CMD_FM_TL: { // TODO - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (isOutput[ins->fm.alg][c.value]) { rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127)); @@ -189,15 +185,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_AR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.ar=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); } } else { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.ar=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); } break; @@ -205,15 +201,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_RS: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.rs=c.value2&3; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.rs=c.value2&3; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } break; @@ -221,15 +217,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_AM: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.am=c.value2&1; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.am=c.value2&1; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } break; @@ -237,15 +233,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_DR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.dr=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.dr=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } break; @@ -253,15 +249,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_SL: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.sl=c.value2&15; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.sl=c.value2&15; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } break; @@ -269,15 +265,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_RR: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.rr=c.value2&15; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.rr=c.value2&15; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } break; @@ -285,15 +281,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_D2R: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.d2r=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.d2r=c.value2&31; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } break; @@ -301,15 +297,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_DT: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.dt=c.value&7; - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.dt=c.value2&7; - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } break; @@ -317,15 +313,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { case DIV_CMD_FM_SSG: { if (c.value<0) { for (int i=0; i<4; i++) { - DivInstrumentFM::Operator& op=chan[1].state.op[i]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; op.ssgEnv=8^(c.value2&15); - unsigned short baseAddr=chanOffs[1]|opOffs[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } } else if (c.value<4) { - DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]]; + DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]]; op.ssgEnv=8^(c.value2&15); - unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } break; @@ -408,31 +404,31 @@ void DivPlatformYM2610Ext::tick(bool sysTick) { } void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) { - if (ch<1) { + if (ch4) { + if (ch>(extChanOffs+3)) { DivPlatformYM2610::muteChannel(ch-3,mute); return; } - isOpMuted[ch-1]=mute; + isOpMuted[ch-extChanOffs]=mute; - int ordch=orderedOps[ch-1]; + int ordch=orderedOps[ch-extChanOffs]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - unsigned short baseAddr=chanOffs[1]|opOffs[ordch]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else if (isOutput[ins->fm.alg][ordch]) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-extChanOffs].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } } void DivPlatformYM2610Ext::forceIns() { - for (int i=0; i<4; i++) { + for (int i=0; iforceIns(); @@ -488,21 +484,21 @@ void DivPlatformYM2610Ext::forceIns() { } void* DivPlatformYM2610Ext::getChanState(int ch) { - if (ch>=5) return &chan[ch-3]; - if (ch>=1) return &opChan[ch-1]; + if (ch>=(extChanOffs+4)) return &chan[ch-3]; + if (ch>=extChanOffs) return &opChan[ch-extChanOffs]; return &chan[ch]; } DivMacroInt* DivPlatformYM2610Ext::getChanMacroInt(int ch) { - if (ch>=7 && ch<10) return ay->getChanMacroInt(ch-7); - if (ch>=5) return &chan[ch-3].std; - if (ch>=1) return NULL; // currently not implemented + if (ch>=(psgChanOffs+3) && ch<(adpcmAChanOffs+3)) return ay->getChanMacroInt(ch-psgChanOffs-3); + if (ch>=(extChanOffs+4)) return &chan[ch-3].std; + if (ch>=extChanOffs) return NULL; // currently not implemented return &chan[ch].std; } DivDispatchOscBuffer* DivPlatformYM2610Ext::getOscBuffer(int ch) { - if (ch>=5) return oscBuf[ch-3]; - if (ch<2) return oscBuf[ch]; + if (ch>=(extChanOffs+4)) return oscBuf[ch-3]; + if (ch<(extChanOffs+1)) return oscBuf[ch]; return NULL; } @@ -520,7 +516,7 @@ void DivPlatformYM2610Ext::reset() { } bool DivPlatformYM2610Ext::keyOffAffectsArp(int ch) { - return (ch>7); + return (ch>=(psgChanOffs+3)); } void DivPlatformYM2610Ext::notifyInsChange(int ins) { diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index 119d63569..ab7c060ff 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -22,19 +22,7 @@ #include "ym2610.h" class DivPlatformYM2610Ext: public DivPlatformYM2610 { - struct OpChannel { - DivMacroInt std; - unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; - signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; - int vol; - unsigned char pan; - // UGLY - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), vol(0), pan(3) {} - }; - OpChannel opChan[4]; + DivPlatformYM2610Base::OpChannel opChan[4]; bool isOpMuted[4]; friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h new file mode 100644 index 000000000..7fc445d35 --- /dev/null +++ b/src/engine/platform/ym2610shared.h @@ -0,0 +1,315 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _YM2610SHARED_H +#define _YM2610SHARED_H +#include "fmshared_OPN.h" +#include "../macroInt.h" +#include "../engine.h" +#include "../../ta-log.h" +#include "ay.h" +#include "sound/ymfm/ymfm.h" +#include "sound/ymfm/ymfm_opn.h" +#include + +#define CHIP_FREQBASE fmFreqBase +#define CHIP_DIVIDER fmDivBase + +class DivYM2610Interface: public ymfm::ymfm_interface { + public: + unsigned char* adpcmAMem; + unsigned char* adpcmBMem; + int sampleBank; + uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address); + void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data); + DivYM2610Interface(): + adpcmAMem(NULL), + adpcmBMem(NULL), + sampleBank(0) {} +}; + +template +class DivPlatformYM2610Base: public DivPlatformOPN { + protected: + struct Channel { + DivInstrumentFM state; + unsigned char freqH, freqL; + int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; + unsigned char psgMode, autoEnvNum, autoEnvDen; + signed char konCycles; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; + int vol, outVol; + int sample; + unsigned char pan; + int macroVolMul; + DivMacroInt std; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } + Channel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + portaPauseFreq(0), + note(0), + ins(-1), + psgMode(1), + autoEnvNum(0), + autoEnvDen(0), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + furnacePCM(false), + hardReset(false), + vol(0), + outVol(15), + sample(-1), + pan(3), + macroVolMul(255) {} + }; + + struct OpChannel { + DivMacroInt std; + unsigned char freqH, freqL; + int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; + signed char konCycles; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta; + int vol; + unsigned char pan; + // UGLY + OpChannel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + portaPauseFreq(0), + ins(-1), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + vol(0), + pan(3) {} + }; + Channel chan[ChanNum]; + DivDispatchOscBuffer* oscBuf[ChanNum]; + bool isMuted[ChanNum]; + + ymfm::ym2610b* fm; + ymfm::ym2610b::output_data fmout; + DivPlatformAY8910* ay; + + unsigned char* adpcmAMem; + size_t adpcmAMemLen; + unsigned char* adpcmBMem; + size_t adpcmBMemLen; + DivYM2610Interface iface; + + unsigned char sampleBank; + + bool extMode; + + unsigned char writeADPCMAOff, writeADPCMAOn; + int globalADPCMAVolume; + + const int extChanOffs, psgChanOffs, adpcmAChanOffs, adpcmBChanOffs; + const int chanNum=ChanNum; + + double NOTE_OPNB(int ch, int note) { + if (ch>=adpcmBChanOffs) { // ADPCM + return NOTE_ADPCMB(note); + } else if (ch>=psgChanOffs) { // PSG + return NOTE_PERIODIC(note); + } + // FM + return NOTE_FNUM_BLOCK(note,11); + } + double NOTE_ADPCMB(int note) { + if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/8363.0; + return parent->calcBaseFreq((double)chipClock/144,off,note,false); + } + return 0; + } + + public: + void reset() { + writeADPCMAOff=0; + writeADPCMAOn=0; + globalADPCMAVolume=0x3f; + + ay->reset(); + ay->getRegisterWrites().clear(); + ay->flushWrites(); + } + + void muteChannel(int ch, bool mute) { + isMuted[ch]=mute; + if (ch>=adpcmBChanOffs) { // ADPCM-B + immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6)); + } + if (ch>=adpcmAChanOffs) { // ADPCM-A + immWrite(0x108+(ch-adpcmAChanOffs),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].outVol)); + return; + } + if (ch>=psgChanOffs) { // PSG + ay->muteChannel(ch-psgChanOffs,mute); + return; + } + } + + bool isStereo() { + return true; + } + + const void* getSampleMem(int index) { + return index == 0 ? adpcmAMem : index == 1 ? adpcmBMem : NULL; + } + + size_t getSampleMemCapacity(int index) { + return index == 0 ? 16777216 : index == 1 ? 16777216 : 0; + } + + size_t getSampleMemUsage(int index) { + return index == 0 ? adpcmAMemLen : index == 1 ? adpcmBMemLen : 0; + } + + void renderSamples() { + memset(adpcmAMem,0,getSampleMemCapacity(0)); + + size_t memPos=0; + for (int i=0; isong.sampleLen; i++) { + DivSample* s=parent->song.sample[i]; + int paddedLen=(s->lengthA+255)&(~0xff); + if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) { + memPos=(memPos+0xfffff)&0xf00000; + } + if (memPos>=getSampleMemCapacity(0)) { + logW("out of ADPCM-A memory for sample %d!",i); + break; + } + if (memPos+paddedLen>=getSampleMemCapacity(0)) { + memcpy(adpcmAMem+memPos,s->dataA,getSampleMemCapacity(0)-memPos); + logW("out of ADPCM-A memory for sample %d!",i); + } else { + memcpy(adpcmAMem+memPos,s->dataA,paddedLen); + } + s->offA=memPos; + memPos+=paddedLen; + } + adpcmAMemLen=memPos+256; + + memset(adpcmBMem,0,getSampleMemCapacity(1)); + + memPos=0; + for (int i=0; isong.sampleLen; i++) { + DivSample* s=parent->song.sample[i]; + int paddedLen=(s->lengthB+255)&(~0xff); + if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) { + memPos=(memPos+0xfffff)&0xf00000; + } + if (memPos>=getSampleMemCapacity(1)) { + logW("out of ADPCM-B memory for sample %d!",i); + break; + } + if (memPos+paddedLen>=getSampleMemCapacity(1)) { + memcpy(adpcmBMem+memPos,s->dataB,getSampleMemCapacity(1)-memPos); + logW("out of ADPCM-B memory for sample %d!",i); + } else { + memcpy(adpcmBMem+memPos,s->dataB,paddedLen); + } + s->offB=memPos; + memPos+=paddedLen; + } + adpcmBMemLen=memPos+256; + } + + void setFlags(unsigned int flags) { + switch (flags&0xff) { + default: + case 0x00: + chipClock=8000000.0; + break; + case 0x01: + chipClock=24167829/3; + break; + } + rate=fm->sample_rate(chipClock); + for (int i=0; irate=rate; + } + } + + int init(DivEngine* p, int channels, int sugRate, unsigned int flags) { + parent=p; + dumpWrites=false; + skipRegisterWrites=false; + for (int i=0; iset_fidelity(ymfm::OPN_FIDELITY_MIN); + setFlags(flags); + // YM2149, 2MHz + ay=new DivPlatformAY8910(true,chipClock,32); + ay->init(p,3,sugRate,16); + ay->toggleRegisterDump(true); + return 0; + } + + void quit() { + for (int i=0; iquit(); + delete ay; + delete[] adpcmAMem; + delete[] adpcmBMem; + } + + DivPlatformYM2610Base(int ext, int psg, int adpcmA, int adpcmB): + DivPlatformOPN(9440540.0, 72, 32), + extChanOffs(ext), + psgChanOffs(psg), + adpcmAChanOffs(adpcmA), + adpcmBChanOffs(adpcmB) {} +}; + +#endif diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index b690d30cb..5003041d3 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -94,7 +94,7 @@ void DivPlatformYMZ280B::tick(bool sysTick) { for (int i=0; i<8; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6; + chan[i].outVol=((chan[i].vol&0xff)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; writeOutVol(i); } if (chan[i].std.arp.had) { @@ -122,9 +122,19 @@ void DivPlatformYMZ280B::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].std.panL.had) { // panning - chan[i].panning=MIN((chan[i].std.panL.val*15/16+15)/2+1,15); + if (chan[i].isNewYMZ) { + chan[i].panning=8+chan[i].std.panL.val; + } else { + chan[i].panning=MIN((chan[i].std.panL.val*15/16+15)/2+1,15); + } rWrite(0x03+i*4,chan[i].panning); } + if (chan[i].std.phaseReset.had) { + if ((chan[i].std.phaseReset.val==1) && chan[i].active) { + chan[i].audPos=0; + chan[i].setPos=true; + } + } if (chan[i].setPos) { // force keyon chan[i].keyOn=true; @@ -207,6 +217,8 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); + chan[c.chan].isNewYMZ=ins->type==DIV_INS_YMZ280B; + chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255; chan[c.chan].sample=ins->amiga.getSample(c.value); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); diff --git a/src/engine/platform/ymz280b.h b/src/engine/platform/ymz280b.h index 0d254c088..5ef362ed1 100644 --- a/src/engine/platform/ymz280b.h +++ b/src/engine/platform/ymz280b.h @@ -32,8 +32,9 @@ class DivPlatformYMZ280B: public DivDispatch { int sample, wave, ins; int note; int panning; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos, isNewYMZ; int vol, outVol; + int macroVolMul; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -56,8 +57,10 @@ class DivPlatformYMZ280B: public DivDispatch { keyOff(false), inPorta(false), setPos(false), + isNewYMZ(false), vol(255), - outVol(255) {} + outVol(255), + macroVolMul(64) {} }; Channel chan[8]; DivDispatchOscBuffer* oscBuf[8]; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index d3fa252d6..6903c0f04 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -165,6 +165,7 @@ const char* cmdName[]={ "X1_010_ENVELOPE_PERIOD", "X1_010_ENVELOPE_SLIDE", "X1_010_AUTO_ENVELOPE", + "X1_010_SAMPLE_BANK_SLOT", "WS_SWEEP_TIME", "WS_SWEEP_AMOUNT", @@ -189,6 +190,8 @@ const char* cmdName[]={ "DIV_CMD_SU_SYNC_PERIOD_LOW", "DIV_CMD_SU_SYNC_PERIOD_HIGH", + "ADPCMA_GLOBAL_VOLUME", + "ALWAYS_SET_VOLUME" }; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index c5541baa3..759ca4ccb 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -944,8 +944,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6"}, {"F1", "F2", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -956,8 +956,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2 OP1", "FM 2 OP2", "FM 2 OP3", "FM 2 OP4", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6"}, {"F1", "O1", "O2", "O3", "O4", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6"}, {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1331,8 +1331,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1343,8 +1343,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1418,6 +1418,7 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"}, {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, + {DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} ); @@ -1489,8 +1490,8 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, + {DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, [](int,unsigned char,unsigned char) -> bool {return false;}, segaPCMPostEffectHandler ); @@ -1522,8 +1523,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1630,8 +1631,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1642,8 +1643,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2 OP1", "FM 2 OP2", "FM 2 OP3", "FM 2 OP4", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "O1", "O2", "O3", "O4", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1685,8 +1686,8 @@ void DivEngine::registerSystems() { {"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "ADPCM 1", "ADPCM 2", "ADPCM 3"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "A1", "A2", "A3"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, + {DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { switch (effect) { case 0x10: // echo feedback @@ -1739,8 +1740,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, fmHardResetEffectHandler, fmPostEffectHandler ); @@ -1751,8 +1752,8 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5"}, {"P1", "P2", "P3", "P4", "P5"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, + {DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, [](int,unsigned char,unsigned char) -> bool {return false;}, segaPCMPostEffectHandler ); @@ -1840,7 +1841,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_ES5506]=new DivSysDef( "Ensoniq ES5506", NULL, 0xb1, 0, 32, false, true, 0, false, - "a sample chip used in the Gravis Ultrasound, popular in the PC (DOS) demoscene.", + "a sample chip used in the Ensoniq's unique TransWave synthesizers, and SoundScape series PC ISA soundcards (which are yet another (partially) Sound Blaster compatible ones with emulated OPL3 and MIDI ROMpler).", {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28", "Channel 29", "Channel 30", "Channel 31", "Channel 32"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, @@ -1853,8 +1854,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "ADPCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM}, + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_ADPCMB}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}, - {}, oplEffectHandler, fmOPLPostEffectHandler ); @@ -1866,7 +1867,7 @@ void DivEngine::registerSystems() { {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_AMIGA}, - {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_NULL}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}, oplEffectHandler, fmOPLPostEffectHandler ); @@ -1966,8 +1967,8 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4"}, {"CH1", "CH2", "CH3", "CH4"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, + {DIV_INS_MSM6295, DIV_INS_MSM6295, DIV_INS_MSM6295, DIV_INS_MSM6295}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - {}, [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { switch (effect) { case 0x20: // select rate @@ -1986,8 +1987,8 @@ void DivEngine::registerSystems() { {"Sample"}, {"PCM"}, {DIV_CH_PCM}, + {DIV_INS_MSM6258}, {DIV_INS_AMIGA}, - {}, [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { switch (effect) { case 0x20: // select rate @@ -2009,6 +2010,7 @@ void DivEngine::registerSystems() { {"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8"}, {"1", "2", "3", "4", "5", "6", "7", "8"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, + {DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B}, {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} ); diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 3a536951f..d6951ffb8 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -318,6 +318,38 @@ void FurnaceGUI::drawInsList() { ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPL_DRUMS]); name=fmt::sprintf(ICON_FA_COFFEE " %.2X: %s##_INS%d",i,ins->name,i); break; + case DIV_INS_MSM6258: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MSM6258]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_MSM6295: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MSM6295]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_ADPCMA: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_ADPCMA]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_ADPCMB: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_ADPCMB]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_SEGAPCM: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SEGAPCM]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_QSOUND: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_QSOUND]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_YMZ280B: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_YMZ280B]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_RF5C68: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_RF5C68]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; default: ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]); name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i); diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 5ae596bcd..641df4d34 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -27,6 +27,7 @@ #include "../engine/platform/nes.h" #include "../engine/platform/c64.h" #include "../engine/platform/arcade.h" +#include "../engine/platform/segapcm.h" #include "../engine/platform/ym2610.h" #include "../engine/platform/ym2610ext.h" #include "../engine/platform/ym2610b.h" @@ -36,9 +37,12 @@ #include "../engine/platform/tia.h" #include "../engine/platform/saa.h" #include "../engine/platform/amiga.h" +#include "../engine/platform/qsound.h" #include "../engine/platform/x1_010.h" #include "../engine/platform/n163.h" #include "../engine/platform/vrc6.h" +#include "../engine/platform/lynx.h" +#include "../engine/platform/pcmdac.h" #include "../engine/platform/dummy.h" #define GENESIS_DEBUG \ @@ -48,6 +52,7 @@ ImGui::Text("* freq: %d",ch->freq); \ ImGui::Text(" - base: %d",ch->baseFreq); \ ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ ImGui::Text("- note: %d",ch->note); \ ImGui::Text("- ins: %d",ch->ins); \ ImGui::Text("- vol: %.2x",ch->vol); \ @@ -68,6 +73,7 @@ ImGui::Text("* freq: %d",ch->freq); \ ImGui::Text(" - base: %d",ch->baseFreq); \ ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ ImGui::Text("- note: %d",ch->note); \ ImGui::Text("- ins: %d",ch->ins); \ ImGui::Text("- vol: %.2x",ch->vol); \ @@ -111,6 +117,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("- ins: %d",ch->ins); ImGui::Text("- duty: %d",ch->duty); @@ -133,17 +140,20 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("* DAC:"); ImGui::Text(" - period: %d",ch->dacPeriod); ImGui::Text(" - rate: %d",ch->dacRate); ImGui::Text(" - pos: %d",ch->dacPos); + ImGui::Text(" - out: %d",ch->dacOut); ImGui::Text(" - sample: %d",ch->dacSample); ImGui::Text("- ins: %d",ch->ins); ImGui::Text("- pan: %.2x",ch->pan); ImGui::Text("- vol: %.2x",ch->vol); ImGui::Text("- outVol: %.2x",ch->outVol); ImGui::Text("- wave: %d",ch->wave); + ImGui::Text("- macroVolMul: %d",ch->macroVolMul); ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); @@ -161,6 +171,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text(" - prev: %d",ch->prevFreq); ImGui::Text("- note: %d",ch->note); ImGui::Text("- ins: %d",ch->ins); @@ -185,6 +196,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text(" - prev: %d",ch->prevFreq); ImGui::Text("- testWhen: %d",ch->testWhen); ImGui::Text("- note: %d",ch->note); @@ -218,6 +230,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("- ins: %d",ch->ins); ImGui::Text("- KOnCycles: %d",ch->konCycles); @@ -231,8 +244,140 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + break; + } + case DIV_SYSTEM_SEGAPCM: + case DIV_SYSTEM_SEGAPCM_COMPAT: { + DivPlatformSegaPCM::Channel* ch=(DivPlatformSegaPCM::Channel*)data; + ImGui::Text("> SegaPCM"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("* PCM:"); + ImGui::Text(" - sample: %d",ch->pcm.sample); + ImGui::Text(" - pos: %d",ch->pcm.pos); + ImGui::Text(" - len: %d",ch->pcm.len); + ImGui::Text(" - freq: %d",ch->pcm.freq); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- chVolL: %.2x",ch->chVolL); + ImGui::Text("- chVolR: %.2x",ch->chVolR); + ImGui::Text("- chPanL: %.2x",ch->chPanL); + ImGui::Text("- chPanR: %.2x",ch->chPanR); + ImGui::Text("- macroVolMul: %.2x",ch->macroVolMul); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->isNewSegaPCM?colorOn:colorOff,">> IsNewSegaPCM"); + break; + } + case DIV_SYSTEM_AY8910: { + DivPlatformAY8910::Channel* ch=(DivPlatformAY8910::Channel*)data; + ImGui::Text("> AY-3-8910"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("* psgMode:"); + ImGui::Text(" - tone: %d",ch->psgMode.tone); + ImGui::Text(" - noise: %d",ch->psgMode.noise); + ImGui::Text(" - envelope: %d",ch->psgMode.envelope); + ImGui::Text(" - dac: %d",ch->psgMode.dac); + ImGui::Text("* DAC:"); + ImGui::Text(" - sample: %d",ch->dac.sample); + ImGui::Text(" - rate: %d",ch->dac.rate); + ImGui::Text(" - period: %d",ch->dac.period); + ImGui::Text(" - pos: %d",ch->dac.pos); + ImGui::Text(" - out: %d",ch->dac.out); + ImGui::Text("- autoEnvNum: %.2x",ch->autoEnvNum); + ImGui::Text("- autoEnvDen: %.2x",ch->autoEnvDen); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->dac.furnaceDAC?colorOn:colorOff,">> furnaceDAC"); + break; + } + case DIV_SYSTEM_AY8930: { + DivPlatformAY8930::Channel* ch=(DivPlatformAY8930::Channel*)data; + ImGui::Text("> AY8930"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- duty: %d",ch->duty); + ImGui::Text("* envelope:"); + ImGui::Text(" - mode: %d",ch->envelope.mode); + ImGui::Text(" - period: %d",ch->envelope.period); + ImGui::Text(" * slide: %d",ch->envelope.slide); + ImGui::Text(" - low: %d",ch->envelope.slideLow); + ImGui::Text("* psgMode:"); + ImGui::Text(" - tone: %d",ch->psgMode.tone); + ImGui::Text(" - noise: %d",ch->psgMode.noise); + ImGui::Text(" - envelope: %d",ch->psgMode.envelope); + ImGui::Text(" - dac: %d",ch->psgMode.dac); + ImGui::Text("* DAC:"); + ImGui::Text(" - sample: %d",ch->dac.sample); + ImGui::Text(" - rate: %d",ch->dac.rate); + ImGui::Text(" - period: %d",ch->dac.period); + ImGui::Text(" - pos: %d",ch->dac.pos); + ImGui::Text(" - out: %d",ch->dac.out); + ImGui::Text("- autoEnvNum: %.2x",ch->autoEnvNum); + ImGui::Text("- autoEnvDen: %.2x",ch->autoEnvDen); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->dac.furnaceDAC?colorOn:colorOff,">> furnaceDAC"); + break; + } + case DIV_SYSTEM_QSOUND: { + DivPlatformQSound::Channel* ch=(DivPlatformQSound::Channel*)data; + ImGui::Text("> QSound"); + ImGui::Text("* freq: %d",ch->freq); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("- note: %d",ch->note); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- sample: %d",ch->sample); + ImGui::Text("- echo: %d",ch->echo); + ImGui::Text("- panning: %d",ch->panning); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- resVol: %.2x",ch->resVol); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->useWave?colorOn:colorOff,">> UseWave"); + ImGui::TextColored(ch->surround?colorOn:colorOff,">> Surround"); + ImGui::TextColored(ch->isNewQSound?colorOn:colorOff,">> IsNewQSound"); break; } case DIV_SYSTEM_X1_010: { @@ -241,6 +386,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %.4x",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("- wave: %d",ch->wave); ImGui::Text("- sample: %d",ch->sample); @@ -254,6 +400,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text(" - autoEnvNum: %.2x",ch->autoEnvNum); ImGui::Text(" - autoEnvDen: %.2x",ch->autoEnvDen); ImGui::Text("- WaveBank: %d",ch->waveBank); + ImGui::Text("- bankSlot: %d",ch->bankSlot); ImGui::Text("- vol: %.2x",ch->vol); ImGui::Text("- outVol: %.2x",ch->outVol); ImGui::Text("- Lvol: %.2x",ch->lvol); @@ -282,6 +429,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %.4x",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("- wave: %d",ch->wave); ImGui::Text("- wavepos: %d",ch->wavePos); @@ -312,6 +460,7 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("* freq: %d",ch->freq); ImGui::Text(" - base: %d",ch->baseFreq); ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); ImGui::Text("- note: %d",ch->note); ImGui::Text("* DAC:"); ImGui::Text(" - period: %d",ch->dacPeriod); @@ -333,6 +482,71 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); break; } + case DIV_SYSTEM_LYNX: { + DivPlatformLynx::Channel* ch=(DivPlatformLynx::Channel*)data; + ImGui::Text("> Lynx"); + ImGui::Text("* freq:"); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("* FreqDiv:"); + ImGui::Text(" - clockDivider: %d",ch->fd.clockDivider); + ImGui::Text(" - backup: %d",ch->fd.backup); + ImGui::Text("* note: %d",ch->note); + ImGui::Text(" - actualNote: %d",ch->actualNote); + ImGui::Text("* Sample:"); + ImGui::Text(" - sample: %d",ch->sample); + ImGui::Text(" - pos: %d",ch->samplePos); + ImGui::Text(" - accum: %d",ch->sampleAccum); + ImGui::Text(" * freq: %d",ch->sampleFreq); + ImGui::Text(" - base: %d",ch->sampleBaseFreq); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("* duty:"); + ImGui::Text(" - int_feedback7: %d",ch->duty.int_feedback7); + ImGui::Text(" - feedback: %d",ch->duty.feedback); + ImGui::Text("- pan: %.2x",ch->pan); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- outVol: %.2x",ch->outVol); + ImGui::Text("- macroVolMul: %.2x",ch->macroVolMul); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->pcm?colorOn:colorOff,">> DAC"); + break; + } + case DIV_SYSTEM_PCM_DAC: { + DivPlatformPCMDAC::Channel* ch=(DivPlatformPCMDAC::Channel*)data; + ImGui::Text("> PCM DAC"); + ImGui::Text("* freq:"); + ImGui::Text(" - base: %d",ch->baseFreq); + ImGui::Text(" - pitch: %d",ch->pitch); + ImGui::Text(" - pitch2: %d",ch->pitch2); + ImGui::Text("* note: %d",ch->note); + ImGui::Text("* Sample: %d",ch->sample); + ImGui::Text(" - dir: %d",ch->audDir); + ImGui::Text(" - loc: %d",ch->audLoc); + ImGui::Text(" - len: %d",ch->audLen); + ImGui::Text(" * pos: %d",ch->audPos); + ImGui::Text(" - sub: %d",ch->audSub); + ImGui::Text("- wave: %d",ch->wave); + ImGui::Text("- ins: %d",ch->ins); + ImGui::Text("- panL: %.2x",ch->panL); + ImGui::Text("- panR: %.2x",ch->panR); + ImGui::Text("- vol: %.2x",ch->vol); + ImGui::Text("- envVol: %.2x",ch->envVol); + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->useWave?colorOn:colorOff,">> UseWave"); + ImGui::TextColored(ch->setPos?colorOn:colorOff,">> SetPos"); + break; + } default: ImGui::Text("Unimplemented chip! Help!"); break; diff --git a/src/gui/gui.h b/src/gui/gui.h index 0ce4afaee..de72c01ce 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -155,6 +155,14 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_SU, GUI_COLOR_INSTR_NAMCO, GUI_COLOR_INSTR_OPL_DRUMS, + GUI_COLOR_INSTR_MSM6258, + GUI_COLOR_INSTR_MSM6295, + GUI_COLOR_INSTR_ADPCMA, + GUI_COLOR_INSTR_ADPCMB, + GUI_COLOR_INSTR_SEGAPCM, + GUI_COLOR_INSTR_QSOUND, + GUI_COLOR_INSTR_YMZ280B, + GUI_COLOR_INSTR_RF5C68, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_FM, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index da86ce86a..1be7f9519 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -84,7 +84,7 @@ const char* insTypes[DIV_INS_MAX+1]={ "FM (4-operator)", "Game Boy", "C64", - "Sample", + "Generic Sample", "PC Engine", "AY-3-8910/SSG", "AY8930", @@ -113,6 +113,14 @@ const char* insTypes[DIV_INS_MAX+1]={ "Sound Unit", "Namco WSG", "OPL (drums)", + "MSM6258", + "MSM6295", + "ADPCM-A", + "ADPCM-B", + "SegaPCM", + "QSound", + "YMZ280B", + "RF5C68", NULL }; @@ -768,6 +776,14 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_SU,"",ImVec4(0.95f,0.98f,1.0f,1.0f)), D(GUI_COLOR_INSTR_NAMCO,"",ImVec4(1.0f,1.0f,0.0f,1.0f)), D(GUI_COLOR_INSTR_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,1.0f)), + D(GUI_COLOR_INSTR_MSM6258,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_MSM6295,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_ADPCMA,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_ADPCMB,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_SEGAPCM,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_QSOUND,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_YMZ280B,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_RF5C68,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_CHANNEL_FM,"",ImVec4(0.2f,0.8f,1.0f,1.0f)), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 55094252f..23ff2261a 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -250,6 +250,10 @@ const char* suControlBits[5]={ "ring mod", "low pass", "high pass", "band pass", NULL }; +const char* es5506FilterModes[4]={ + "HP/K2, HP/K2", "HP/K2, LP/K1", "LP/K2, LP/K2", "LP/K2, LP/K1", +}; + const char* panBits[3]={ "right", "left", NULL }; @@ -258,6 +262,14 @@ const char* oneBit[2]={ "on", NULL }; +const char* es5506EnvelopeModes[3]={ + "k1 slowdown", "k2 slowdown", NULL +}; + +const char* es5506ControlModes[2]={ + "pause", NULL +}; + const int orderedOps[4]={ 0, 2, 1, 3 }; @@ -314,6 +326,27 @@ String macroHoverLoop(int id, float val) { return ""; } +String macroHoverES5506FilterMode(int id, float val) { + String mode="???"; + switch (((int)val)&3) { + case 0: + mode="HP/K2, HP/K2"; + break; + case 1: + mode="HP/K2, LP/K1"; + break; + case 2: + mode="LP/K2, LP/K2"; + break; + case 3: + mode="LP/K2, LP/K1"; + break; + default: + break; + } + return fmt::sprintf("%d: %s",id,mode); +} + String macroLFOWaves(int id, float val) { switch (((int)val)&3) { case 0: @@ -3174,9 +3207,9 @@ void FurnaceGUI::drawInsEdit() { } } - ImGui::EndChild(); - ImGui::EndDisabled(); } + ImGui::EndChild(); + ImGui::EndDisabled(); ImGui::EndTabItem(); } if (ins->type==DIV_INS_C64) if (ImGui::BeginTabItem("C64")) { @@ -3296,97 +3329,133 @@ void FurnaceGUI::drawInsEdit() { P(ImGui::Checkbox("Don't test/gate before new note",&ins->c64.noTest)); ImGui::EndTabItem(); } - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SU) if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) { - String sName; - if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { - sName="none selected"; - } else { - sName=e->song.sample[ins->amiga.initSample]->name; - } - if (ins->type==DIV_INS_SU) { - P(ImGui::Checkbox("Use sample",&ins->su.useSample)); - P(ImGui::Checkbox("Switch roles of frequency and phase reset timer",&ins->su.switchRoles)); - } - if (ImGui::BeginCombo("Initial Sample",sName.c_str())) { - String id; - for (int i=0; isong.sampleLen; i++) { - id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER - ins->amiga.initSample=i; + if (ins->type==DIV_INS_PCE || + ins->type==DIV_INS_MSM6258 || + ins->type==DIV_INS_MSM6295 || + ins->type==DIV_INS_ADPCMA || + ins->type==DIV_INS_ADPCMB || + ins->type==DIV_INS_SEGAPCM || + ins->type==DIV_INS_QSOUND || + ins->type==DIV_INS_YMZ280B || + ins->type==DIV_INS_RF5C68 || + ins->type==DIV_INS_AMIGA || + ins->type==DIV_INS_MULTIPCM || + ins->type==DIV_INS_MIKEY || + ins->type==DIV_INS_X1_010 || + ins->type==DIV_INS_SWAN || + ins->type==DIV_INS_AY || + ins->type==DIV_INS_AY8930 || + ins->type==DIV_INS_VRC6 || + ins->type==DIV_INS_SU || + ins->type==DIV_INS_SNES || + ins->type==DIV_INS_ES5506) { + if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) { + String sName; + if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { + sName="none selected"; + } else { + sName=e->song.sample[ins->amiga.initSample]->name; + } + if (ins->type==DIV_INS_PCE || + ins->type==DIV_INS_MIKEY || + ins->type==DIV_INS_X1_010 || + ins->type==DIV_INS_SWAN || + ins->type==DIV_INS_AY || + ins->type==DIV_INS_AY8930 || + ins->type==DIV_INS_VRC6 || + ins->type==DIV_INS_SU) { + P(ImGui::Checkbox("Use sample",&ins->amiga.useSample)); + if (ins->type==DIV_INS_SU) { + P(ImGui::Checkbox("Switch roles of frequency and phase reset timer",&ins->su.switchRoles)); + } + if (ins->type==DIV_INS_X1_010) { + if (ImGui::InputInt("Sample bank slot##BANKSLOT",&ins->x1_010.bankSlot,1,4)) { PARAMETER + if (ins->x1_010.bankSlot<0) ins->x1_010.bankSlot=0; + if (ins->x1_010.bankSlot>=7) ins->x1_010.bankSlot=7; + } } } - ImGui::EndCombo(); - } - if (ins->type==DIV_INS_AMIGA) { - P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave)); - if (ins->amiga.useWave) { - int len=ins->amiga.waveLen+1; - if (ImGui::InputInt("Width",&len,2,16)) { - if (len<2) len=2; - if (len>256) len=256; - ins->amiga.waveLen=(len&(~1))-1; - PARAMETER + if (ImGui::BeginCombo("Initial Sample",sName.c_str())) { + String id; + for (int i=0; isong.sampleLen; i++) { + id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name); + if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER + ins->amiga.initSample=i; + } + } + ImGui::EndCombo(); + } + if (ins->type==DIV_INS_AMIGA) { + P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave)); + if (ins->amiga.useWave) { + int len=ins->amiga.waveLen+1; + if (ImGui::InputInt("Width",&len,2,16)) { + if (len<2) len=2; + if (len>256) len=256; + ins->amiga.waveLen=(len&(~1))-1; + PARAMETER + } } } - } - ImGui::BeginDisabled(ins->amiga.useWave); - P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); - if (ins->amiga.useNoteMap) { - // TODO: frequency map? - if (ImGui::BeginTable("NoteMap",2,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); - //ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::BeginDisabled(ins->amiga.useWave); + P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap)); + if (ins->amiga.useNoteMap) { + // TODO: frequency map? + if (ImGui::BeginTable("NoteMap",2,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + //ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupScrollFreeze(0,1); + ImGui::TableSetupScrollFreeze(0,1); - ImGui::TableNextRow(ImGuiTableRowFlags_Headers); - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - ImGui::Text("Sample"); - /*ImGui::TableNextColumn(); - ImGui::Text("Frequency");*/ - for (int i=0; i<120; i++) { - DivInstrumentAmiga::SampleMap& sampleMap=ins->amiga.noteMap[i]; - ImGui::TableNextRow(); - ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); - ImGui::Text("%s",noteNames[60+i]); ImGui::TableNextColumn(); - if (sampleMap.map<0 || sampleMap.map>=e->song.sampleLen) { - sName="-- empty --"; - sampleMap.map=-1; - } else { - sName=e->song.sample[sampleMap.map]->name; - } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##SM",sName.c_str())) { - String id; - if (ImGui::Selectable("-- empty --",sampleMap.map==-1)) { PARAMETER - sampleMap.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(),sampleMap.map==j)) { PARAMETER - sampleMap.map=j; - if (sampleMap.freq<=0) sampleMap.freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); - } - } - ImGui::EndCombo(); - } + ImGui::Text("Sample"); /*ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##SF",&sampleMap.freq,50,500)) { PARAMETER - if (sampleMap.freq<0) sampleMap.freq=0; - if (sampleMap.freq>262144) sampleMap.freq=262144; - }*/ - ImGui::PopID(); + ImGui::Text("Frequency");*/ + for (int i=0; i<120; i++) { + DivInstrumentAmiga::SampleMap& sampleMap=ins->amiga.noteMap[i]; + ImGui::TableNextRow(); + ImGui::PushID(fmt::sprintf("NM_%d",i).c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%s",noteNames[60+i]); + ImGui::TableNextColumn(); + if (sampleMap.map<0 || sampleMap.map>=e->song.sampleLen) { + sName="-- empty --"; + sampleMap.map=-1; + } else { + sName=e->song.sample[sampleMap.map]->name; + } + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##SM",sName.c_str())) { + String id; + if (ImGui::Selectable("-- empty --",sampleMap.map==-1)) { PARAMETER + sampleMap.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(),sampleMap.map==j)) { PARAMETER + sampleMap.map=j; + if (sampleMap.freq<=0) sampleMap.freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0)); + } + } + ImGui::EndCombo(); + } + /*ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##SF",&sampleMap.freq,50,500)) { PARAMETER + if (sampleMap.freq<0) sampleMap.freq=0; + if (sampleMap.freq>262144) sampleMap.freq=262144; + }*/ + ImGui::PopID(); + } + ImGui::EndTable(); } - ImGui::EndTable(); } + ImGui::EndDisabled(); + ImGui::EndTabItem(); } - ImGui::EndDisabled(); - ImGui::EndTabItem(); } if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem(settings.c163Name.c_str())) { if (ImGui::InputInt("Waveform##WAVE",&ins->n163.wave,1,10)) { PARAMETER @@ -3453,25 +3522,44 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndTabItem(); } + if (ins->type==DIV_INS_ES5506) if (ImGui::BeginTabItem("ES5506")) { + if (ImGui::BeginTable("ESParams",2,ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); + // filter + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter 4,3 Mode",ImGuiDataType_U8,&ins->es5506.filter.mode,&_ZERO,&_THREE,es5506FilterModes[ins->es5506.filter.mode&3])); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K1",ImGuiDataType_U16,&ins->es5506.filter.k1,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K2",ImGuiDataType_U16,&ins->es5506.filter.k2,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable + // envelope + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Envelope count",ImGuiDataType_U16,&ins->es5506.envelope.ecount,&_ZERO,&_FIVE_HUNDRED_ELEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Left Volume Ramp",ImGuiDataType_S8,&ins->es5506.envelope.lVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Right Volume Ramp",ImGuiDataType_S8,&ins->es5506.envelope.rVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K1 Ramp",ImGuiDataType_S8,&ins->es5506.envelope.k1Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("Filter K2 Ramp",ImGuiDataType_S8,&ins->es5506.envelope.k2Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Checkbox("K1 Ramp Slowdown",&ins->es5506.envelope.k1Slow); + ImGui::TableNextColumn(); + ImGui::Checkbox("K2 Ramp Slowdown",&ins->es5506.envelope.k2Slow); + ImGui::EndTable(); + } + ImGui::EndTabItem(); + } if (ins->type==DIV_INS_MULTIPCM) { if (ImGui::BeginTabItem("MultiPCM")) { - String sName; - if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { - sName="none selected"; - } else { - sName=e->song.sample[ins->amiga.initSample]->name; - } - if (ImGui::BeginCombo("Initial Sample",sName.c_str())) { - String id; - for (int i=0; isong.sampleLen; i++) { - id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name); - if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { - ins->amiga.initSample=i; - PARAMETER - } - } - ImGui::EndCombo(); - } ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); if (ImGui::BeginTable("MultiPCMADSRParams",7,ImGuiTableFlags_NoHostExtendX)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); @@ -3555,14 +3643,110 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTabItem(); } } + if (ins->type==DIV_INS_SNES) if (ImGui::BeginTabItem("SNES")) { + P(ImGui::Checkbox("Use envelope",&ins->snes.useEnv)); + ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); + if (ins->snes.useEnv) { + if (ImGui::BeginTable("SNESEnvParams",5,ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + CENTER_TEXT("A"); + ImGui::TextUnformatted("A"); + ImGui::TableNextColumn(); + CENTER_TEXT("D"); + ImGui::TextUnformatted("D"); + ImGui::TableNextColumn(); + CENTER_TEXT("S"); + ImGui::TextUnformatted("S"); + ImGui::TableNextColumn(); + CENTER_TEXT("R"); + ImGui::TextUnformatted("R"); + ImGui::TableNextColumn(); + CENTER_TEXT("Envelope"); + ImGui::TextUnformatted("Envelope"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE)); + ImGui::TableNextColumn(); + drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.r,ins->snes.r,(14-ins->snes.s*2),(ins->snes.r==0),0,0,7,16,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); + + ImGui::EndTable(); + } + } else { + if (ImGui::BeginTable("SNESGainParams",3,ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + CENTER_TEXT("Gain Mode"); + ImGui::TextUnformatted("Gain Mode"); + ImGui::TableNextColumn(); + CENTER_TEXT("Gain"); + ImGui::TextUnformatted("Gain"); + ImGui::TableNextColumn(); + CENTER_TEXT("Envelope"); + ImGui::TextUnformatted("Envelope"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::RadioButton("Direct",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DIRECT; + PARAMETER; + } + if (ImGui::RadioButton("Decrease (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LINEAR)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LINEAR; + PARAMETER; + } + if (ImGui::RadioButton("Decrease (logarithmic)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LOG)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LOG; + PARAMETER; + } + if (ImGui::RadioButton("Increase (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_LINEAR)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_LINEAR; + PARAMETER; + } + if (ImGui::RadioButton("Increase (bent line)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_INVLOG)) { + ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_INVLOG; + PARAMETER; + } + + ImGui::TableNextColumn(); + unsigned char gainMax=(ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)?127:31; + if (ins->snes.gain>gainMax) ins->snes.gain=gainMax; + P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); + + ImGui::TableNextColumn(); + ImGui::Text("Envelope goes here..."); + + ImGui::EndTable(); + } + } + ImGui::EndTabItem(); + } if (ins->type==DIV_INS_GB || (ins->type==DIV_INS_AMIGA && ins->amiga.useWave) || - ins->type==DIV_INS_X1_010 || + (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample) || ins->type==DIV_INS_N163 || ins->type==DIV_INS_FDS || - ins->type==DIV_INS_SWAN || - ins->type==DIV_INS_PCE || + (ins->type==DIV_INS_SWAN && !ins->amiga.useSample) || + (ins->type==DIV_INS_PCE && !ins->amiga.useSample) || ins->type==DIV_INS_SCC || + ins->type==DIV_INS_SNES || ins->type==DIV_INS_NAMCO) { if (ImGui::BeginTabItem("Wavetable")) { if (ImGui::Checkbox("Enable synthesizer",&ins->ws.enabled)) { @@ -3725,7 +3909,7 @@ void FurnaceGUI::drawInsEdit() { } } } - if ((ins->type==DIV_INS_PCE || ins->type==DIV_INS_AY8930)) { + if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_AY8930) { volMax=31; } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_VERA || ins->type==DIV_INS_VRC6_SAW) { @@ -3734,7 +3918,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_AMIGA) { volMax=64; } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_SEGAPCM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_OPZ) { volMax=127; } if (ins->type==DIV_INS_GB) { @@ -3750,6 +3934,24 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FDS) { volMax=32; } + if (ins->type==DIV_INS_ES5506) { + volMax=65535; + } + if (ins->type==DIV_INS_MSM6258) { + volMax=0; + } + if (ins->type==DIV_INS_MSM6295) { + volMax=8; + } + if (ins->type==DIV_INS_ADPCMA) { + volMax=31; + } + if (ins->type==DIV_INS_ADPCMB || ins->type==DIV_INS_YMZ280B || ins->type==DIV_INS_RF5C68) { + volMax=255; + } + if (ins->type==DIV_INS_QSOUND) { + volMax=16383; + } const char* dutyLabel="Duty/Noise"; int dutyMin=0; @@ -3766,33 +3968,33 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FM) { dutyMax=32; } - if ((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)) { - dutyMax=31; + if (ins->type==DIV_INS_AY) { + dutyMax=ins->amiga.useSample?0:31; } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_FM) { dutyLabel="Noise Freq"; } if (ins->type==DIV_INS_MIKEY) { dutyLabel="Duty/Int"; - dutyMax=10; + dutyMax=ins->amiga.useSample?0:10; } if (ins->type==DIV_INS_BEEPER) { dutyLabel="Pulse Width"; dutyMax=255; } if (ins->type==DIV_INS_AY8930) { - dutyMax=255; + dutyMax=ins->amiga.useSample?0:255; } - if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC) { + if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM) { dutyMax=0; } - if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_NAMCO) { + if ((ins->type==DIV_INS_PCE && !ins->amiga.useSample) || ins->type==DIV_INS_NAMCO) { dutyLabel="Noise"; - dutyMax=1; + dutyMax=(ins->type==DIV_INS_PCE && !ins->amiga.useSample)?0:1; } if (ins->type==DIV_INS_SWAN) { dutyLabel="Noise"; - dutyMax=8; + dutyMax=ins->amiga.useSample?0:8; } if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) { dutyMax=0; @@ -3807,19 +4009,42 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_VRC6) { dutyLabel="Duty"; - dutyMax=7; + dutyMax=ins->amiga.useSample?0:7; } if (ins->type==DIV_INS_SU) { dutyMax=127; } + if (ins->type==DIV_INS_ES5506) { + dutyLabel="Filter Mode"; + dutyMax=3; + } + if (ins->type==DIV_INS_MSM6258) { + dutyLabel="Frequency Divider"; + dutyMax=2; + } + if (ins->type==DIV_INS_MSM6295) { + dutyLabel="Frequency Divider"; + dutyMax=1; + } + if (ins->type==DIV_INS_ADPCMA) { + dutyLabel="Global Volume"; + dutyMax=63; + } + if (ins->type==DIV_INS_ADPCMB || ins->type==DIV_INS_YMZ280B || ins->type==DIV_INS_RF5C68) { + dutyMax=0; + } + if (ins->type==DIV_INS_QSOUND) { + dutyLabel="Echo Level"; + dutyMax=32767; + } const char* waveLabel="Waveform"; - int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:255; - bool bitMode=false; - if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) { - bitMode=true; + int waveMax=(ins->type==DIV_INS_VERA)?3:255; + bool waveBitMode=false; + if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_SAA1099) { + waveBitMode=true; } - if (ins->type==DIV_INS_STD || ins->type==DIV_INS_VRC6 || ins->type==DIV_INS_VRC6_SAW) waveMax=0; + if (ins->type==DIV_INS_STD || ins->type==DIV_INS_VRC6_SAW) waveMax=0; if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_VIC || ins->type==DIV_INS_OPLL) waveMax=15; if (ins->type==DIV_INS_C64) waveMax=4; if (ins->type==DIV_INS_SAA1099) waveMax=2; @@ -3829,13 +4054,21 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_SU) waveMax=7; if (ins->type==DIV_INS_PET) { waveMax=8; - bitMode=true; + waveBitMode=true; + } + if (ins->type==DIV_INS_VRC6) { + waveMax=ins->amiga.useSample?255:0; } if (ins->type==DIV_INS_OPLL) { waveLabel="Patch"; } + if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930) { + waveMax=ins->amiga.useSample?255:3; + waveBitMode=ins->amiga.useSample?false:true; + } + const char** waveNames=NULL; if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) waveNames=ayShapeBits; if (ins->type==DIV_INS_C64) waveNames=c64ShapeBits; @@ -3850,8 +4083,8 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_X1_010) { dutyMax=0; - ex1Max=7; - ex2Max=255; + ex1Max=ins->amiga.useSample?0:7; + ex2Max=ins->amiga.useSample?0:255; ex2Bit=false; } if (ins->type==DIV_INS_N163) { @@ -3866,7 +4099,18 @@ void FurnaceGUI::drawInsEdit() { ex1Max=16383; ex2Max=255; } + if (ins->type==DIV_INS_MSM6258) { + ex1Max=1; + } + if (ins->type==DIV_INS_QSOUND) { + ex1Max=16383; + ex2Max=2725; + } if (ins->type==DIV_INS_SAA1099) ex1Max=8; + if (ins->type==DIV_INS_ES5506) { + ex1Max=65535; + ex2Max=65535; + } int panMin=0; int panMax=0; @@ -3878,21 +4122,34 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_GB || ins->type==DIV_INS_OPZ || - ins->type==DIV_INS_VERA) { + ins->type==DIV_INS_MSM6258 || + ins->type==DIV_INS_VERA || + ins->type==DIV_INS_ADPCMA || + ins->type==DIV_INS_ADPCMB) { panMax=1; panSingle=true; } - if (ins->type==DIV_INS_AMIGA) { - panMax=127; - } - if (ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_PCE || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SAA1099 || ins->type==DIV_INS_NAMCO) { + if (ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_PCE || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SAA1099 || ins->type==DIV_INS_NAMCO || ins->type==DIV_INS_RF5C68) { panMax=15; } - if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { + if (ins->type==DIV_INS_SEGAPCM) { + panMax=127; + } + if (ins->type==DIV_INS_AMIGA) { + if (ins->std.panLMacro.mode) { + panMin=-16; + panMax=16; + } else { + panMin=0; + panMax=127; + } + } + if (ins->type==DIV_INS_QSOUND) { panMin=-16; panMax=16; + panSingleNoBit=true; } - if (ins->type==DIV_INS_MULTIPCM) { + if (ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_YMZ280B) { panMin=-7; panMax=7; panSingleNoBit=true; @@ -3902,6 +4159,9 @@ void FurnaceGUI::drawInsEdit() { panMax=127; panSingleNoBit=true; } + if (ins->type==DIV_INS_ES5506) { + panMax=65535; + } if (volMax>0) { macroList.push_back(FurnaceGUIMacroDesc(volumeLabel,&ins->std.volMacro,volMin,volMax,160,uiColors[GUI_COLOR_MACRO_VOLUME])); @@ -3910,27 +4170,32 @@ void FurnaceGUI::drawInsEdit() { if (dutyMax>0) { if (ins->type==DIV_INS_MIKEY) { macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,0,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,mikeyFeedbackBits)); + } else if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,¯oHoverES5506FilterMode)); } else { macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER])); } } if (waveMax>0) { - macroList.push_back(FurnaceGUIMacroDesc(waveLabel,&ins->std.waveMacro,0,waveMax,(bitMode && ins->type!=DIV_INS_PET)?64:160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,bitMode,waveNames,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0))); + macroList.push_back(FurnaceGUIMacroDesc(waveLabel,&ins->std.waveMacro,0,waveMax,(waveBitMode && ins->type!=DIV_INS_PET)?64:160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,waveBitMode,waveNames,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0))); } if (panMax>0) { if (panSingle) { macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits)); + } else if (ins->type==DIV_INS_QSOUND) { + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } else { if (panSingleNoBit || (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode)) { - macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); + macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL)); } 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,NULL,NULL,true)); } else { - macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER])); } } } @@ -3943,14 +4208,25 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_OPZ || ins->type==DIV_INS_PCE || ins->type==DIV_INS_GB || + ins->type==DIV_INS_MSM6258 || + ins->type==DIV_INS_MSM6295 || + ins->type==DIV_INS_ADPCMA || + ins->type==DIV_INS_ADPCMB || + ins->type==DIV_INS_SEGAPCM || + ins->type==DIV_INS_QSOUND || + ins->type==DIV_INS_YMZ280B || + ins->type==DIV_INS_RF5C68 || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SWAN || ins->type==DIV_INS_MULTIPCM || + (ins->type==DIV_INS_VRC6 && ins->amiga.useSample) || ins->type==DIV_INS_SU || - ins->type==DIV_INS_MIKEY) { + ins->type==DIV_INS_MIKEY || + ins->type==DIV_INS_ES5506 || + (ins->type==DIV_INS_X1_010 && ins->amiga.useSample)) { macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } if (ex1Max>0) { @@ -3958,7 +4234,7 @@ void FurnaceGUI::drawInsEdit() { 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) { + } else if (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample) { macroList.push_back(FurnaceGUIMacroDesc("Envelope Mode",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,x1_010EnvBits)); } else if (ins->type==DIV_INS_N163) { macroList.push_back(FurnaceGUIMacroDesc("Wave Length",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3966,6 +4242,12 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Mod Depth",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Cutoff",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); + } else if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode==1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); + } else if (ins->type==DIV_INS_MSM6258) { + macroList.push_back(FurnaceGUIMacroDesc("Clock Divider",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); + } else if (ins->type==DIV_INS_QSOUND) { + macroList.push_back(FurnaceGUIMacroDesc("Echo Feedback",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else { macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } @@ -3979,6 +4261,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Mod Speed",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else if (ins->type==DIV_INS_SU) { macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); + } else if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode==1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode)); + } else if (ins->type==DIV_INS_QSOUND) { + macroList.push_back(FurnaceGUIMacroDesc("Echo Buffer Len",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER])); } else { macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits)); } @@ -3987,7 +4273,7 @@ void FurnaceGUI::drawInsEdit() { 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) { + 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])); macroList.push_back(FurnaceGUIMacroDesc("AutoEnv Den",&ins->std.algMacro,0,15,160,uiColors[GUI_COLOR_MACRO_OTHER])); } @@ -4009,6 +4295,15 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.ex3Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,suControlBits)); macroList.push_back(FurnaceGUIMacroDesc("Phase Reset Timer",&ins->std.ex4Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_OTHER])); // again reuse code from resonance macro but use ex4 instead } + if (ins->type==DIV_INS_ES5506) { + macroList.push_back(FurnaceGUIMacroDesc("Envelope counter",&ins->std.ex3Macro,0,511,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope left volume ramp",&ins->std.ex4Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope right volume ramp",&ins->std.ex5Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope K1 ramp",&ins->std.ex6Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope K2 ramp",&ins->std.ex7Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER])); + macroList.push_back(FurnaceGUIMacroDesc("Envelope mode",&ins->std.ex8Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506EnvelopeModes)); + macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506ControlModes)); + } drawMacros(macroList); ImGui::EndTabItem(); diff --git a/src/gui/intConst.cpp b/src/gui/intConst.cpp index 8bee0f88c..9a41486e1 100644 --- a/src/gui/intConst.cpp +++ b/src/gui/intConst.cpp @@ -31,6 +31,9 @@ const int _SIXTY_FOUR=64; const int _ONE_HUNDRED=100; const int _ONE_HUNDRED_TWENTY_SEVEN=127; const int _TWO_HUNDRED_FIFTY_FIVE=255; +const int _FIVE_HUNDRED_ELEVEN=511; const int _TWO_THOUSAND_FORTY_SEVEN=2047; const int _FOUR_THOUSAND_NINETY_FIVE=4095; +const int _SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE=65535; const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN=-127; +const int _MINUS_ONE_HUNDRED_TWENTY_EIGHT=-128; diff --git a/src/gui/intConst.h b/src/gui/intConst.h index 98c6c34ff..ff11a4968 100644 --- a/src/gui/intConst.h +++ b/src/gui/intConst.h @@ -33,6 +33,9 @@ extern const int _SIXTY_FOUR; extern const int _ONE_HUNDRED; extern const int _ONE_HUNDRED_TWENTY_SEVEN; extern const int _TWO_HUNDRED_FIFTY_FIVE; +extern const int _FIVE_HUNDRED_ELEVEN; extern const int _TWO_THOUSAND_FORTY_SEVEN; extern const int _FOUR_THOUSAND_NINETY_FIVE; +extern const int _SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE; extern const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN; +extern const int _MINUS_ONE_HUNDRED_TWENTY_EIGHT; diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 37d4bfecf..1347c6969 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1485,7 +1485,7 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_INSTR_STD,"Standard"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_GB,"Game Boy"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_C64,"C64"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_AMIGA,"Amiga/Sample"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_AMIGA,"Amiga/Generic Sample"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_PCE,"PC Engine"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_AY,"AY-3-8910/SSG"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_AY8930,"AY8930"); @@ -1517,6 +1517,15 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_INSTR_SNES,"SNES"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_SU,"Sound Unit"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_NAMCO,"Namco WSG"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPL_DRUMS,"FM (OPL Drums)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_MSM6258,"MSM6258"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_MSM6295,"MSM6295"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_ADPCMA,"ADPCM-A"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_ADPCMB,"ADPCM-B"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_SEGAPCM,"Sega PCM"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_QSOUND,"QSound"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_YMZ280B,"YMZ280B"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_RF5C68,"RF5C68"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown"); ImGui::TreePop(); } From 22211a4ef0e72c1cf2773d7bfe04028b42caf387 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 17:28:08 +0900 Subject: [PATCH 03/46] Fix loop --- src/engine/engine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index fb37f4238..cee47e41a 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2764,6 +2764,7 @@ DivSample* DivEngine::sampleFromFile(const char* path) { sample->centerRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0)); if(inst.loop_count && inst.loops[0].mode >= SF_LOOP_FORWARD) { + sample->loop=true; sample->loopMode=(DivSampleLoopMode)(inst.loops[0].mode-SF_LOOP_FORWARD); sample->loopStart=inst.loops[0].start; sample->loopEnd=inst.loops[0].end; From c44f03b1a3d4c348bfab1bcb4c4f19265bdf6535 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:11:34 +0900 Subject: [PATCH 04/46] Sync with master --- src/engine/fileOps.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 488878203..dac3c5d18 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2644,10 +2644,6 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { if (sample[i].len>0) { s->init(sample[i].len*2); } - s->loopStart=sample[i].loopStart*2; - s->loopEnd=(sample[i].loopStart+sample[i].loopLen)*2; - s->loop=(s->loopStart>=0)&&(s->loopEnd>=0); - reader.read(s->data8,sample[i].len); s->name=fmt::sprintf("Sample %d",i+1); if (sample[i].loopLen>1) { s->loopStart=sample[i].loopStart; From 8f804f6e6b37f2132214789abfed457d3a2f2a67 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:20:33 +0900 Subject: [PATCH 05/46] Correct pitch to sample preview --- src/engine/platform/ay.cpp | 2 +- src/engine/platform/ay8930.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 5cb5574b2..de5dd6e78 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -381,7 +381,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { } chan[c.chan].dac.pos=0; chan[c.chan].dac.period=0; - chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate; + chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate*2048; if (dumpWrites) { rWrite(0x08+c.chan,0); addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 5ab9c3489..2dd4ca8de 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -400,7 +400,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { } chan[c.chan].dac.pos=0; chan[c.chan].dac.period=0; - chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate; + chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate*4096; if (dumpWrites) { rWrite(0x08+c.chan,0); addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate); From 570036ad6ffb9ed9e3b7a12bf77da41c50355942 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:22:36 +0900 Subject: [PATCH 06/46] CONTRIBUTING --- src/engine/platform/ym2610shared.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h index 7fc445d35..2fee30c7d 100644 --- a/src/engine/platform/ym2610shared.h +++ b/src/engine/platform/ym2610shared.h @@ -44,8 +44,7 @@ class DivYM2610Interface: public ymfm::ymfm_interface { sampleBank(0) {} }; -template -class DivPlatformYM2610Base: public DivPlatformOPN { +template class DivPlatformYM2610Base: public DivPlatformOPN { protected: struct Channel { DivInstrumentFM state; From 80c9b0c3f492b0ee8a732db43202f59fe24d325a Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:26:56 +0900 Subject: [PATCH 07/46] Fix compile --- src/engine/vgmOps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 51948f27f..78639cca1 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -1559,7 +1559,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p sample->offSegaPCM=memPos; unsigned int readPos=0; for (unsigned int j=0; j=sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { + if (readPos>=(unsigned int)sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) { if (sample->isLoopable()) { readPos=sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT); pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80); From 745837c41d51b65aac579488f4f8952e8d50100b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:40:16 +0900 Subject: [PATCH 08/46] Fix compile (2) --- src/engine/platform/ym2610.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index dc5d67b73..143ecb188 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -242,7 +242,7 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l ymfm::ssg_engine::output_data ssgOut; - ymfm::fm_channel>* fmChan[6]; + ymfm::fm_channel>* fmChan[4]; ymfm::adpcm_a_channel* adpcmAChan[6]; for (int i=0; i<4; i++) { fmChan[i]=fme->debug_channel(bchOffs[i]); From 5d3cecfea6dd1d173173ce98301cb0fd29e327c7 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 27 Aug 2022 18:58:49 +0900 Subject: [PATCH 09/46] Fix switch case --- src/engine/platform/pcmdac.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 4ce53925f..57f5c0026 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -66,6 +66,7 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l chan.audPos=s->getLoopEndPosition()-1-(s->getLoopStartPosition()-chan.audPos); chan.audDir=true; } + break; default: if (chan.audPos<0) { chan.sample=-1; @@ -90,6 +91,7 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l chan.audPos=s->getLoopEndPosition()-1-(s->getLoopEndPosition()-1-chan.audPos); chan.audDir=true; } + break; default: if (chan.audPos>=s->getEndPosition()) { chan.sample=-1; From f73d1bd82c600fe8a7bbf2c09bfcfeeab123a78b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 28 Aug 2022 01:04:27 +0900 Subject: [PATCH 10/46] Add ADPCM-B instrument support for Y8950 w/drums --- src/engine/sysDef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 241890839..04a598906 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1421,7 +1421,7 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick/FM 7", "Snare", "Tom", "Top", "HiHat", "ADPCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_AMIGA}, + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_ADPCMB}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}, fmEffectHandlerMap, fmOPLPostEffectHandlerMap From a411e34a62e6d7b6cd3bf801240f3faad74e63d5 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 28 Aug 2022 09:59:56 +0900 Subject: [PATCH 11/46] Performance adjusts --- src/engine/instrument.h | 18 ++++++++++-------- src/engine/platform/amiga.cpp | 4 ++-- src/engine/platform/ay.cpp | 2 +- src/engine/platform/ay8930.cpp | 2 +- src/engine/platform/mmc5.cpp | 2 +- src/engine/platform/nes.cpp | 2 +- src/engine/platform/pce.cpp | 2 +- src/engine/platform/pcmdac.cpp | 2 +- src/engine/platform/segapcm.cpp | 2 +- src/engine/platform/swan.cpp | 2 +- src/engine/platform/vera.cpp | 2 +- src/engine/platform/vrc6.cpp | 2 +- src/engine/platform/zxbeeper.cpp | 4 ++-- 13 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 68cd0b3cc..e95ef0b66 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -60,14 +60,16 @@ enum DivInstrumentType: unsigned short { DIV_INS_SU=30, DIV_INS_NAMCO=31, DIV_INS_OPL_DRUMS=32, - DIV_INS_MSM6258=33, - DIV_INS_MSM6295=34, - DIV_INS_ADPCMA=35, - DIV_INS_ADPCMB=36, - DIV_INS_SEGAPCM=37, - DIV_INS_QSOUND=38, - DIV_INS_YMZ280B=39, - DIV_INS_RF5C68=40, + //33 + //34 + DIV_INS_MSM6258=35, + DIV_INS_MSM6295=36, + DIV_INS_ADPCMA=37, + DIV_INS_ADPCMB=38, + DIV_INS_SEGAPCM=39, + DIV_INS_QSOUND=40, + DIV_INS_YMZ280B=41, + DIV_INS_RF5C68=42, DIV_INS_MAX, DIV_INS_NULL }; diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 764c4332c..d229998e2 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -95,8 +95,8 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le } } else { DivSample* s=parent->getSample(chan[i].sample); - if (s->getEndPosition()>0) { - if (chan[i].audPos<(unsigned int)s->getEndPosition()) { + if (s->samples>0) { + if (chan[i].audPossamples) { writeAudDat(s->data8[chan[i].audPos++]); } if (s->isLoopable() && chan[i].audPos>=MIN(131071,(unsigned int)s->getLoopEndPosition())) { diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index de5dd6e78..b7871b680 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -90,7 +90,7 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l int prev_out = chan[i].dac.out; while (chan[i].dac.period>rate && !end) { DivSample* s=parent->getSample(chan[i].dac.sample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { chan[i].dac.sample=-1; rWrite(0x08+i,0); end=true; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 2dd4ca8de..2943ac177 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -94,7 +94,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l int prev_out = chan[i].dac.out; while (chan[i].dac.period>rate && !end) { DivSample* s=parent->getSample(chan[i].dac.sample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { chan[i].dac.sample=-1; rWrite(0x08+i,0); end=true; diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 3b9f9b58e..de997a025 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -49,7 +49,7 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len dacPeriod+=dacRate; if (dacPeriod>=rate) { DivSample* s=parent->getSample(dacSample); - if (s->getEndPosition()>0) { + if (s->samples>0) { if (!isMuted[2]) { rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80)); } diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 7827cbac1..fbb7fa3a8 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -76,7 +76,7 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) { dacPeriod+=dacRate; \ if (dacPeriod>=rate) { \ DivSample* s=parent->getSample(dacSample); \ - if (s->getEndPosition()>0) { \ + if (s->samples>0) { \ if (!isMuted[4]) { \ unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; \ if (dacAntiClickOn && dacAntiClickrate) { DivSample* s=parent->getSample(chan[i].dacSample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { chan[i].dacSample=-1; continue; } diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 57f5c0026..8f1440878 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -50,7 +50,7 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l output=(chan.ws.output[chan.audPos]^0x80)<<8; } else { DivSample* s=parent->getSample(chan.sample); - if (s->getEndPosition()>0) { + if (s->samples>0) { if (chan.audDir) { if (s->isLoopable()) { switch (s->loopMode) { diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 2ff7552d2..93481d94f 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -36,7 +36,7 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t for (int i=0; i<16; i++) { if (chan[i].pcm.sample>=0 && chan[i].pcm.samplesong.sampleLen) { DivSample* s=parent->getSample(chan[i].pcm.sample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { chan[i].pcm.sample=-1; oscBuf[i]->data[oscBuf[i]->needle++]=0; continue; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 0d264f714..e6242c795 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -57,7 +57,7 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len dacPeriod+=dacRate; while (dacPeriod>rate) { DivSample* s=parent->getSample(dacSample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { dacSample=-1; continue; } diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 9d22a854d..22be5e984 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -58,7 +58,7 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len size_t pos=start; DivSample* s=parent->getSample(chan[16].pcm.sample); while (len>0) { - if (s->getEndPosition()>0) { + if (s->samples>0) { while (pcm_is_fifo_almost_empty(pcm)) { short tmp_l=0; short tmp_r=0; diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 2f670bf26..134905479 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -54,7 +54,7 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len chan[i].dacPeriod+=chan[i].dacRate; if (chan[i].dacPeriod>rate) { DivSample* s=parent->getSample(chan[i].dacSample); - if (s->getEndPosition()<=0) { + if (s->samples<=0) { chan[i].dacSample=-1; chWrite(i,0,0); continue; diff --git a/src/engine/platform/zxbeeper.cpp b/src/engine/platform/zxbeeper.cpp index 2869c38aa..5fa3840bb 100644 --- a/src/engine/platform/zxbeeper.cpp +++ b/src/engine/platform/zxbeeper.cpp @@ -34,9 +34,9 @@ void DivPlatformZXBeeper::acquire(short* bufL, short* bufR, size_t start, size_t if (curSample>=0 && curSamplesong.sampleLen) { if (--curSamplePeriod<0) { DivSample* s=parent->getSample(curSample); - if (s->getEndPosition()>0) { + if (s->samples>0) { sampleOut=(s->data8[curSamplePos++]>0); - if (curSamplePos>=(unsigned int)s->getEndPosition()) curSample=-1; + if (curSamplePos>=s->samples) curSample=-1; // 256 bits if (curSamplePos>2047) curSample=-1; From 3fcccb52ee8bae20864bc08dd3c658f0b1eb7643 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 28 Aug 2022 10:50:57 +0900 Subject: [PATCH 12/46] Reduce performance issue --- src/engine/platform/amiga.cpp | 6 ++--- src/engine/platform/ay.cpp | 6 ++--- src/engine/platform/ay8930.cpp | 6 ++--- src/engine/platform/genesis.cpp | 12 +++++----- src/engine/platform/lynx.cpp | 6 ++--- src/engine/platform/mmc5.cpp | 6 ++--- src/engine/platform/nes.cpp | 6 ++--- src/engine/platform/pce.cpp | 6 ++--- src/engine/platform/pcmdac.cpp | 24 +++++++++---------- src/engine/platform/qsound.cpp | 4 ++-- src/engine/platform/rf5c68.cpp | 2 +- src/engine/platform/segapcm.cpp | 6 ++--- src/engine/platform/su.cpp | 2 +- src/engine/platform/swan.cpp | 6 ++--- src/engine/platform/vera.cpp | 6 ++--- src/engine/platform/vrc6.cpp | 6 ++--- src/engine/playback.cpp | 42 ++++++++++++++++----------------- 17 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index d229998e2..7a49fccfa 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -99,9 +99,9 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le if (chan[i].audPossamples) { writeAudDat(s->data8[chan[i].audPos++]); } - if (s->isLoopable() && chan[i].audPos>=MIN(131071,(unsigned int)s->getLoopEndPosition())) { - chan[i].audPos=s->getLoopStartPosition(); - } else if (chan[i].audPos>=MIN(131071,(unsigned int)s->getEndPosition())) { + if (s->isLoopable() && chan[i].audPos>=MIN(131071,(unsigned int)s->loopEnd)) { + chan[i].audPos=s->loopStart; + } else if (chan[i].audPos>=MIN(131071,s->samples)) { chan[i].sample=-1; } } else { diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index b7871b680..0b275cb5d 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -104,9 +104,9 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l changed=true; } chan[i].dac.pos++; - if (s->isLoopable() && chan[i].dac.pos>=s->getLoopEndPosition()) { - chan[i].dac.pos=s->getLoopStartPosition(); - } else if (chan[i].dac.pos>=s->getEndPosition()) { + if (s->isLoopable() && chan[i].dac.pos>=s->loopEnd) { + chan[i].dac.pos=s->loopStart; + } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; rWrite(0x08+i,0); end=true; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 2943ac177..8714f2308 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -108,9 +108,9 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l changed=true; } chan[i].dac.pos++; - if (s->isLoopable() && chan[i].dac.pos>=s->getLoopEndPosition()) { - chan[i].dac.pos=s->getLoopStartPosition(); - } else if (chan[i].dac.pos>=s->getEndPosition()) { + if (s->isLoopable() && chan[i].dac.pos>=s->loopEnd) { + chan[i].dac.pos=s->loopStart; + } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; rWrite(0x08+i,0); end=true; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index e9e90c4bd..6ae10d0ce 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -52,9 +52,9 @@ void DivPlatformGenesis::processDAC() { if (s->samples>0) { while (chan[i].dacPeriod>=(chipClock/576)) { ++chan[i].dacPos; - if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition())) { - chan[i].dacPos=s->getLoopStartPosition(); - } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { + if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->loopEnd)) { + chan[i].dacPos=s->loopStart; + } else if (chan[i].dacPos>=s->samples) { chan[i].dacSample=-1; chan[i].dacPeriod=0; break; @@ -98,9 +98,9 @@ void DivPlatformGenesis::processDAC() { } } chan[5].dacPos++; - if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->getLoopEndPosition())) { - chan[5].dacPos=s->getLoopStartPosition(); - } else if (chan[5].dacPos>=(unsigned int)s->getEndPosition()) { + if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->loopEnd)) { + chan[5].dacPos=s->loopStart; + } else if (chan[5].dacPos>=s->samples) { chan[5].dacSample=-1; if (parent->song.brokenDACMode) { rWrite(0x2b,0); diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 6e9995bea..c67f35234 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -146,9 +146,9 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos++]*chan[i].outVol)>>7,-128,127)); } - if (s->isLoopable() && chan[i].samplePos>=s->getLoopEndPosition()) { - chan[i].samplePos=s->getLoopStartPosition(); - } else if (chan[i].samplePos>=s->getEndPosition()) { + if (s->isLoopable() && chan[i].samplePos>=s->loopEnd) { + chan[i].samplePos=s->loopStart; + } else if (chan[i].samplePos>=(int)s->samples) { chan[i].sample=-1; } } diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index de997a025..7d271046e 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -54,9 +54,9 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80)); } dacPos++; - if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { - dacPos=s->getLoopStartPosition(); - } else if (dacPos>=(unsigned int)s->getEndPosition()) { + if (s->isLoopable() && dacPos>=(unsigned int)s->loopEnd) { + dacPos=s->loopStart; + } else if (dacPos>=s->samples) { dacSample=-1; } dacPeriod-=rate; diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index fbb7fa3a8..c4376b126 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -88,9 +88,9 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) { } \ } \ dacPos++; \ - if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { \ - dacPos=s->getLoopStartPosition(); \ - } else if (dacPos>=(unsigned int)s->getEndPosition()) { \ + if (s->isLoopable() && dacPos>=(unsigned int)s->loopEnd) { \ + dacPos=s->loopStart; \ + } else if (dacPos>=s->samples) { \ dacSample=-1; \ } \ dacPeriod-=rate; \ diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index d9d339e4b..ea6f0e56e 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -76,9 +76,9 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) chWrite(i,0x06,0x10); } chan[i].dacPos++; - if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) { - chan[i].dacPos=s->getLoopStartPosition(); - } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { + if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->loopEnd) { + chan[i].dacPos=s->loopStart; + } else if (chan[i].dacPos>=s->samples) { chan[i].dacSample=-1; } chan[i].dacPeriod-=rate; diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 8f1440878..f7db0ef4c 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -56,14 +56,14 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l switch (s->loopMode) { case DIV_SAMPLE_LOOP_FORWARD: case DIV_SAMPLE_LOOP_PINGPONG: - if (chan.audPosgetLoopStartPosition()) { - chan.audPos=s->getLoopStartPosition()+(s->getLoopStartPosition()-chan.audPos); + if (chan.audPosloopStart) { + chan.audPos=s->loopStart+(s->loopStart-chan.audPos); chan.audDir=false; } break; case DIV_SAMPLE_LOOP_BACKWARD: - if (chan.audPosgetLoopStartPosition()) { - chan.audPos=s->getLoopEndPosition()-1-(s->getLoopStartPosition()-chan.audPos); + if (chan.audPosloopStart) { + chan.audPos=s->loopEnd-1-(s->loopStart-chan.audPos); chan.audDir=true; } break; @@ -73,36 +73,36 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l } break; } - } else if (chan.audPos>=s->getEndPosition()) { + } else if (chan.audPos>=(int)s->samples) { chan.sample=-1; } } else { if (s->isLoopable()) { switch (s->loopMode) { case DIV_SAMPLE_LOOP_FORWARD: - if (chan.audPos>=s->getLoopEndPosition()) { - chan.audPos=(chan.audPos+s->getLoopStartPosition())-s->getLoopEndPosition(); + if (chan.audPos>=s->loopEnd) { + chan.audPos=(chan.audPos+s->loopStart)-s->loopEnd; chan.audDir=false; } break; case DIV_SAMPLE_LOOP_BACKWARD: case DIV_SAMPLE_LOOP_PINGPONG: - if (chan.audPos>=s->getLoopEndPosition()) { - chan.audPos=s->getLoopEndPosition()-1-(s->getLoopEndPosition()-1-chan.audPos); + if (chan.audPos>=s->loopEnd) { + chan.audPos=s->loopEnd-1-(s->loopEnd-1-chan.audPos); chan.audDir=true; } break; default: - if (chan.audPos>=s->getEndPosition()) { + if (chan.audPos>=(int)s->samples) { chan.sample=-1; } break; } - } else if (chan.audPos>=s->getEndPosition()) { + } else if (chan.audPos>=(int)s->samples) { chan.sample=-1; } } - if (chan.audPos>=0 && chan.audPosgetEndPosition()) { + if (chan.audPos>=0 && chan.audPos<(int)s->samples) { output=s->data16[chan.audPos]; } } else { diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 63985c801..18216f03f 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -289,8 +289,8 @@ void DivPlatformQSound::tick(bool sysTick) { qsound_bank = 0x8000 | (s->offQSound >> 16); qsound_addr = s->offQSound & 0xffff; - int loopStart=s->getLoopStartPosition(); - int length = s->getLoopEndPosition(); + int loopStart=s->loopStart; + int length = s->loopEnd; if (length > 65536 - 16) { length = 65536 - 16; } diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index 9a0510b05..86d373722 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -136,7 +136,7 @@ void DivPlatformRF5C68::tick(bool sysTick) { start=start+MIN(chan[i].audPos,s->length8); } if (s->isLoopable()) { - loop=start+s->getLoopStartPosition(); + loop=start+s->loopStart; } start=MIN(start,getSampleMemCapacity()-31); loop=MIN(loop,getSampleMemCapacity()-31); diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 93481d94f..69e996b8b 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -47,9 +47,9 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR); } chan[i].pcm.pos+=chan[i].pcm.freq; - if (s->isLoopable() && chan[i].pcm.pos>=((unsigned int)s->getLoopEndPosition()<<8)) { - chan[i].pcm.pos=s->getLoopStartPosition()<<8; - } else if (chan[i].pcm.pos>=((unsigned int)s->getEndPosition()<<8)) { + if (s->isLoopable() && chan[i].pcm.pos>=((unsigned int)s->loopEnd<<8)) { + chan[i].pcm.pos=s->loopStart<<8; + } else if (chan[i].pcm.pos>=(s->samples<<8)) { chan[i].pcm.sample=-1; } } else { diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index b314ecde6..9a2c4f569 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -552,7 +552,7 @@ void DivPlatformSoundUnit::renderSamples() { for (int i=0; isong.sampleLen; i++) { DivSample* s=parent->song.sample[i]; if (s->data8==NULL) continue; - int paddedLen=s->getEndPosition(); + int paddedLen=s->length8; if (memPos>=getSampleMemCapacity(0)) { logW("out of PCM memory for sample %d!",i); break; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index e6242c795..6d2954530 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -62,9 +62,9 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len continue; } rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80); - if (s->isLoopable() && dacPos>=(unsigned int)s->getLoopEndPosition()) { - dacPos=s->getLoopStartPosition(); - } else if (dacPos>=(unsigned int)s->getEndPosition()) { + if (s->isLoopable() && dacPos>=(unsigned int)s->loopEnd) { + dacPos=s->loopStart; + } else if (dacPos>=s->samples) { dacSample=-1; } dacPeriod-=rate; diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 22be5e984..c586cc9fc 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -84,9 +84,9 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len rWritePCMData(tmp_r&0xff); } chan[16].pcm.pos++; - if (s->isLoopable() && chan[16].pcm.pos>=(unsigned int)s->getLoopEndPosition()) { - chan[16].pcm.pos=s->getLoopStartPosition(); - } else if (chan[16].pcm.pos>=(unsigned int)s->getEndPosition()) { + if (s->isLoopable() && chan[16].pcm.pos>=(unsigned int)s->loopEnd) { + chan[16].pcm.pos=s->loopStart; + } else if (chan[16].pcm.pos>=s->samples) { chan[16].pcm.sample=-1; break; } diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 134905479..e8cfb99d0 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -65,9 +65,9 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len chWrite(i,0,0x80|chan[i].dacOut); } chan[i].dacPos++; - if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) { - chan[i].dacPos=s->getLoopStartPosition(); - } else if (chan[i].dacPos>=(unsigned int)s->getEndPosition()) { + if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->loopEnd) { + chan[i].dacPos=s->loopStart; + } else if (chan[i].dacPos>=s->samples) { chan[i].dacSample=-1; chWrite(i,0,0); } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 9017c40bb..10f544d78 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1334,19 +1334,19 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi samp_prevSample=samp_temp; if (sPreview.dir) { // backward - if (sPreview.posgetLoopStartPosition() || (sPreview.pBegin>=0 && sPreview.posisLoopable() && sPreview.posgetLoopEndPosition()) { + if (sPreview.posloopStart || (sPreview.pBegin>=0 && sPreview.posisLoopable() && sPreview.posloopEnd) { switch (s->loopMode) { case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; default: @@ -1355,19 +1355,19 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } } else { // forward - if (sPreview.pos>=s->getLoopEndPosition() || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { - if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + if (sPreview.pos>=s->loopEnd || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { + if (s->isLoopable() && sPreview.pos>=s->loopStart) { switch (s->loopMode) { case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; default: @@ -1378,19 +1378,19 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } if (sPreview.dir) { // backward - if (sPreview.pos<=s->getLoopStartPosition() || (sPreview.pBegin>=0 && sPreview.pos<=sPreview.pBegin)) { - if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + if (sPreview.pos<=s->loopStart || (sPreview.pBegin>=0 && sPreview.pos<=sPreview.pBegin)) { + if (s->isLoopable() && sPreview.pos>=s->loopStart) { switch (s->loopMode) { case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; default: @@ -1401,25 +1401,25 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } } else { // forward - if (sPreview.pos>=s->getLoopEndPosition() || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { - if (s->isLoopable() && sPreview.pos>=s->getLoopStartPosition()) { + if (sPreview.pos>=s->loopEnd || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) { + if (s->isLoopable() && sPreview.pos>=s->loopStart) { switch (s->loopMode) { case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD: - sPreview.pos=s->getLoopStartPosition(); + sPreview.pos=s->loopStart; sPreview.dir=false; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG: - sPreview.pos=s->getLoopEndPosition()-1; + sPreview.pos=s->loopEnd-1; sPreview.dir=true; break; default: break; } - } else if (sPreview.pos>=s->getEndPosition()) { + } else if (sPreview.pos>=(int)s->samples) { sPreview.sample=-1; } } From 16e59bf0005c80718d5a335bd85e7ce9a9239729 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 14:14:06 +0900 Subject: [PATCH 13/46] Fix naming --- src/gui/guiConst.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index b4b18efe4..16c38962d 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -113,6 +113,8 @@ const char* insTypes[DIV_INS_MAX+1]={ "Sound Unit", "Namco WSG", "OPL (drums)", + "", // 33 + "", // 34 "MSM6258", "MSM6295", "ADPCM-A", From a23b0ff79018bd8cc4d30625306627000c030e0f Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 14:48:18 +0900 Subject: [PATCH 14/46] More consistent naming --- src/gui/guiConst.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 16c38962d..1827eb1a4 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -113,8 +113,8 @@ const char* insTypes[DIV_INS_MAX+1]={ "Sound Unit", "Namco WSG", "OPL (drums)", - "", // 33 - "", // 34 + "Reserved", // 33 + "Reserved", // 34 "MSM6258", "MSM6295", "ADPCM-A", From 5a84a35f3dd3bf98db737bc9c7d3c544bdd2d92c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 03:21:18 -0500 Subject: [PATCH 15/46] SegaPCM: fix regression --- src/engine/platform/segapcm.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 69e996b8b..53e844ebd 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -74,7 +74,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); - if (chan[i].isNewSegaPCM) { + if (parent->song.newSegaPCM) { if (chan[i].std.vol.had) { chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul; chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; @@ -93,7 +93,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { chan[i].freqChanged=true; } - if (chan[i].std.panL.had) { + if (parent->song.newSegaPCM) if (chan[i].std.panL.had) { if (chan[i].isNewSegaPCM) { chan[i].chPanL=chan[i].std.panL.val&127; chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; @@ -105,7 +105,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } } - if (chan[i].std.panR.had) { + if (parent->song.newSegaPCM) if (chan[i].std.panR.had) { if (chan[i].isNewSegaPCM) { chan[i].chPanR=chan[i].std.panR.val&127; chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127; @@ -212,7 +212,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { if (skipRegisterWrites) break; if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SEGAPCM) { chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:127; - chan[c.chan].isNewSegaPCM=(ins->type==DIV_INS_SEGAPCM || parent->song.newSegaPCM); + chan[c.chan].isNewSegaPCM=(ins->type==DIV_INS_SEGAPCM); chan[c.chan].pcm.sample=ins->amiga.getSample(c.value); if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) { chan[c.chan].pcm.sample=-1; @@ -278,7 +278,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (chan[c.chan].isNewSegaPCM) { + if (parent->song.newSegaPCM && chan[c.chan].isNewSegaPCM) { chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127; chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127; } else { @@ -302,7 +302,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].ins=c.value; break; case DIV_CMD_PANNING: { - if (chan[c.chan].isNewSegaPCM) { + if (parent->song.newSegaPCM && chan[c.chan].isNewSegaPCM) { chan[c.chan].chPanL=c.value>>1; chan[c.chan].chPanR=c.value2>>1; chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127; From 764ae60740e9c0f3e44f6b000818a31f4b6bf9c3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 03:41:38 -0500 Subject: [PATCH 16/46] prepare for splitting OPN/OPM and NES/SN --- src/engine/instrument.h | 4 ++-- src/gui/dataList.cpp | 8 ++++++++ src/gui/gui.h | 2 ++ src/gui/guiConst.cpp | 10 ++++++---- src/gui/settings.cpp | 6 ++++-- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 5c3882e3b..01323d90f 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -60,8 +60,8 @@ enum DivInstrumentType: unsigned short { DIV_INS_SU=30, DIV_INS_NAMCO=31, DIV_INS_OPL_DRUMS=32, - //33 - //34 + DIV_INS_OPM=33, + DIV_INS_NES=34, DIV_INS_MSM6258=35, DIV_INS_MSM6295=36, DIV_INS_ADPCMA=37, diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index e25f504dc..2a1c7a66a 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -338,6 +338,14 @@ void FurnaceGUI::drawInsList(bool asChild) { ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPL_DRUMS]); name=fmt::sprintf(ICON_FA_COFFEE " %.2X: %s##_INS%d",i,ins->name,i); break; + case DIV_INS_OPM: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPM]); + name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_NES: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_NES]); + name=fmt::sprintf(ICON_FA_GAMEPAD " %.2X: %s##_INS%d",i,ins->name,i); + break; case DIV_INS_MSM6258: ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MSM6258]); name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); diff --git a/src/gui/gui.h b/src/gui/gui.h index cb481f122..7f9c5924a 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -159,6 +159,8 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_SU, GUI_COLOR_INSTR_NAMCO, GUI_COLOR_INSTR_OPL_DRUMS, + GUI_COLOR_INSTR_OPM, + GUI_COLOR_INSTR_NES, GUI_COLOR_INSTR_MSM6258, GUI_COLOR_INSTR_MSM6295, GUI_COLOR_INSTR_ADPCMA, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 1827eb1a4..1ce78b5fa 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -80,8 +80,8 @@ const int vgmVersions[6]={ }; const char* insTypes[DIV_INS_MAX+1]={ - "Standard (SMS/NES)", - "FM (4-operator)", + "SN76489/Sega PSG", + "FM (OPN)", "Game Boy", "C64", "Generic Sample", @@ -113,8 +113,8 @@ const char* insTypes[DIV_INS_MAX+1]={ "Sound Unit", "Namco WSG", "OPL (drums)", - "Reserved", // 33 - "Reserved", // 34 + "FM (OPM)", // 33 + "NES", // 34 "MSM6258", "MSM6295", "ADPCM-A", @@ -788,6 +788,8 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_SU,"",ImVec4(0.95f,0.98f,1.0f,1.0f)), D(GUI_COLOR_INSTR_NAMCO,"",ImVec4(1.0f,1.0f,0.0f,1.0f)), D(GUI_COLOR_INSTR_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,1.0f)), + D(GUI_COLOR_INSTR_OPM,"",ImVec4(0.2f,0.6f,1.0f,1.0f)), + D(GUI_COLOR_INSTR_NES,"",ImVec4(0.4f,1.0f,0.3f,1.0f)), D(GUI_COLOR_INSTR_MSM6258,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), D(GUI_COLOR_INSTR_MSM6295,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), D(GUI_COLOR_INSTR_ADPCMA,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 14ade83bd..4e292879b 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1636,8 +1636,8 @@ void FurnaceGUI::drawSettings() { ImGui::TreePop(); } if (ImGui::TreeNode("Instrument Types")) { - UI_COLOR_CONFIG(GUI_COLOR_INSTR_FM,"FM (4-operator)"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_STD,"Standard"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_FM,"FM (OPN)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_STD,"SN76489/Sega PSG"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_GB,"Game Boy"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_C64,"C64"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_AMIGA,"Amiga/Generic Sample"); @@ -1673,6 +1673,8 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_INSTR_SU,"Sound Unit"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_NAMCO,"Namco WSG"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPL_DRUMS,"FM (OPL Drums)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPM,"FM (OPM)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_NES,"NES"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_MSM6258,"MSM6258"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_MSM6295,"MSM6295"); UI_COLOR_CONFIG(GUI_COLOR_INSTR_ADPCMA,"ADPCM-A"); From cf1d4e55cf826e6bec182679e7022b4d2a5beded Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 23:24:02 +0900 Subject: [PATCH 17/46] Fix ADPCM-A playback Add per-chip debug function Add YM2203, YM2608, YM2610/B debug window Extend YM2612 debug window Remove unnecessary values in YM2151, Sega PCM platform --- src/engine/platform/amiga.h | 1 + src/engine/platform/arcade.cpp | 5 - src/engine/platform/arcade.h | 4 +- src/engine/platform/ay.h | 3 +- src/engine/platform/ay8930.h | 3 +- src/engine/platform/bubsyswsg.h | 3 +- src/engine/platform/c64.h | 3 +- src/engine/platform/dummy.h | 3 +- src/engine/platform/fds.h | 3 +- src/engine/platform/gb.h | 3 +- src/engine/platform/genesis.h | 3 +- src/engine/platform/genesisext.h | 3 +- src/engine/platform/lynx.h | 3 +- src/engine/platform/mmc5.h | 3 +- src/engine/platform/msm6258.h | 1 + src/engine/platform/msm6295.h | 1 + src/engine/platform/n163.h | 1 + src/engine/platform/namcowsg.h | 1 + src/engine/platform/nes.h | 1 + src/engine/platform/opl.h | 1 + src/engine/platform/opll.h | 1 + src/engine/platform/pce.h | 1 + src/engine/platform/pcmdac.h | 1 + src/engine/platform/pcspkr.h | 1 + src/engine/platform/pet.h | 1 + src/engine/platform/qsound.h | 1 + src/engine/platform/rf5c68.h | 1 + src/engine/platform/saa.h | 1 + src/engine/platform/scc.h | 1 + src/engine/platform/segapcm.cpp | 4 - src/engine/platform/segapcm.h | 6 +- src/engine/platform/sms.h | 1 + src/engine/platform/su.h | 1 + src/engine/platform/swan.h | 1 + src/engine/platform/tia.h | 1 + src/engine/platform/tx81z.h | 1 + src/engine/platform/vera.h | 1 + src/engine/platform/vic20.h | 1 + src/engine/platform/vrc6.h | 1 + src/engine/platform/x1_010.h | 1 + src/engine/platform/ym2203.h | 1 + src/engine/platform/ym2203ext.cpp | 17 - src/engine/platform/ym2203ext.h | 22 +- src/engine/platform/ym2608.cpp | 27 +- src/engine/platform/ym2608.h | 1 + src/engine/platform/ym2608ext.cpp | 2 +- src/engine/platform/ym2608ext.h | 22 +- src/engine/platform/ym2610.cpp | 22 +- src/engine/platform/ym2610.h | 1 + src/engine/platform/ym2610b.cpp | 20 +- src/engine/platform/ym2610b.h | 1 + src/engine/platform/ym2610bext.h | 1 + src/engine/platform/ym2610ext.h | 1 + src/engine/platform/ymz280b.h | 1 + src/engine/platform/zxbeeper.h | 1 + src/gui/debug.cpp | 583 +++++++++++++++++++++++++++++- src/gui/debug.h | 1 + src/gui/debugWindow.cpp | 16 + 58 files changed, 726 insertions(+), 91 deletions(-) diff --git a/src/engine/platform/amiga.h b/src/engine/platform/amiga.h index 59617ec36..a0a80d6ce 100644 --- a/src/engine/platform/amiga.h +++ b/src/engine/platform/amiga.h @@ -86,6 +86,7 @@ class DivPlatformAmiga: public DivDispatch { int sep1, sep2; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index c86f806e1..477430994 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -833,9 +833,6 @@ void DivPlatformArcade::reset() { } lastBusy=60; - pcmCycles=0; - pcmL=0; - pcmR=0; delay=0; amDepth=0x7f; pmDepth=0x7f; @@ -846,8 +843,6 @@ void DivPlatformArcade::reset() { immWrite(0x19,amDepth); immWrite(0x19,0x80|pmDepth); //rWrite(0x1b,0x00); - - extMode=false; } void DivPlatformArcade::setFlags(unsigned int flags) { diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 2a9c2b40c..70265be39 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -79,14 +79,13 @@ class DivPlatformArcade: public DivPlatformOPM { DivDispatchOscBuffer* oscBuf[8]; opm_t fm; int baseFreqOff; - int pcmL, pcmR, pcmCycles; unsigned char amDepth, pmDepth; ymfm::ym2151* fm_ymfm; ymfm::ym2151::output_data out_ymfm; DivArcadeInterface iface; - bool extMode, useYMFM; + bool useYMFM; bool isMuted[8]; @@ -96,6 +95,7 @@ class DivPlatformArcade: public DivPlatformOPM { void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); void acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index e87430e2e..4f77281de 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -146,7 +146,8 @@ class DivPlatformAY8910: public DivDispatch { size_t ayBufLen; void updateOutSel(bool immediate=false); - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 3447f5d47..c1a50e7a5 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -150,7 +150,8 @@ class DivPlatformAY8930: public DivDispatch { void updateOutSel(bool immediate=false); void immWrite(unsigned char a, unsigned char v); - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/bubsyswsg.h b/src/engine/platform/bubsyswsg.h index f14b94a77..34bdad3dc 100644 --- a/src/engine/platform/bubsyswsg.h +++ b/src/engine/platform/bubsyswsg.h @@ -62,7 +62,8 @@ class DivPlatformBubSysWSG: public DivDispatch { k005289_core k005289; unsigned short regPool[4]; - void updateWave(int ch); + void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index 7587730b0..52685ce72 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -82,7 +82,8 @@ class DivPlatformC64: public DivDispatch { SID sid; reSIDfp::SID sid_fp; unsigned char regPool[32]; - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void acquire_classic(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/dummy.h b/src/engine/platform/dummy.h index b8601059b..0b5181f01 100644 --- a/src/engine/platform/dummy.h +++ b/src/engine/platform/dummy.h @@ -33,7 +33,8 @@ class DivPlatformDummy: public DivDispatch { Channel chan[128]; DivDispatchOscBuffer* oscBuf[128]; bool isMuted[128]; - unsigned char chans; + unsigned char chans; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/fds.h b/src/engine/platform/fds.h index 2bd983292..2721876e9 100644 --- a/src/engine/platform/fds.h +++ b/src/engine/platform/fds.h @@ -77,7 +77,8 @@ class DivPlatformFDS: public DivDispatch { unsigned char regPool[128]; void updateWave(); - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void doWrite(unsigned short addr, unsigned char data); diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index 516e7d9f1..347f528bd 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -92,7 +92,8 @@ class DivPlatformGB: public DivDispatch { unsigned char regPool[128]; unsigned char procMute(); - void updateWave(); + void updateWave(); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 8588b21d4..6c6837c03 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -115,7 +115,8 @@ class DivPlatformGenesis: public DivPlatformOPN { bool ladder; unsigned char dacVolTable[128]; - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); inline void processDAC(); diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index d4dd93e77..352ebc293 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -51,7 +51,8 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { pan(3) {} }; OpChannel opChan[4]; - bool isOpMuted[4]; + bool isOpMuted[4]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); diff --git a/src/engine/platform/lynx.h b/src/engine/platform/lynx.h index f7fdb62e3..a6c1c91c1 100644 --- a/src/engine/platform/lynx.h +++ b/src/engine/platform/lynx.h @@ -84,7 +84,8 @@ class DivPlatformLynx: public DivDispatch { Channel chan[4]; DivDispatchOscBuffer* oscBuf[4]; bool isMuted[4]; - std::unique_ptr mikey; + std::unique_ptr mikey; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index 90da3eaa2..0da3da32e 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -67,7 +67,8 @@ class DivPlatformMMC5: public DivDispatch { unsigned char writeOscBuf; struct _mmc5* mmc5; unsigned char regPool[128]; - + + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index f6a351b5e..f06bdc261 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -87,6 +87,7 @@ class DivPlatformMSM6258: public DivDispatch { int delay, updateOsc, sample, samplePos; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/msm6295.h b/src/engine/platform/msm6295.h index a37514685..5fc5ac7b8 100644 --- a/src/engine/platform/msm6295.h +++ b/src/engine/platform/msm6295.h @@ -74,6 +74,7 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf { bool rateSel=false, rateSelInit=false; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index d4a9ee357..0ff969b64 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -89,6 +89,7 @@ class DivPlatformN163: public DivDispatch { unsigned char regPool[128]; void updateWave(int ch, int wave, int pos, int len); void updateWaveCh(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/namcowsg.h b/src/engine/platform/namcowsg.h index ede25e8e6..56a8ba3cd 100644 --- a/src/engine/platform/namcowsg.h +++ b/src/engine/platform/namcowsg.h @@ -74,6 +74,7 @@ class DivPlatformNamcoWSG: public DivDispatch { int devType, chans; unsigned char regPool[512]; void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 85c14b0c9..2a9923fa6 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -79,6 +79,7 @@ class DivPlatformNES: public DivDispatch { xgm::NES_DMC* nes2_NP; unsigned char regPool[128]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void doWrite(unsigned short addr, unsigned char data); diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 49ea3b729..43f02790f 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -118,6 +118,7 @@ class DivPlatformOPL: public DivDispatch { int toFreq(int freq); double NOTE_ADPCMB(int note); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/opll.h b/src/engine/platform/opll.h index 21a77b4e6..3f243057b 100644 --- a/src/engine/platform/opll.h +++ b/src/engine/platform/opll.h @@ -93,6 +93,7 @@ class DivPlatformOPLL: public DivDispatch { int octave(int freq); int toFreq(int freq); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 6f35f1797..ec0308340 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -91,6 +91,7 @@ class DivPlatformPCE: public DivDispatch { PCE_PSG* pce; unsigned char regPool[128]; void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/pcmdac.h b/src/engine/platform/pcmdac.h index 127d39aae..7292f6ddf 100644 --- a/src/engine/platform/pcmdac.h +++ b/src/engine/platform/pcmdac.h @@ -77,6 +77,7 @@ class DivPlatformPCMDAC: public DivDispatch { int outDepth; bool outStereo; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/pcspkr.h b/src/engine/platform/pcspkr.h index ba6275c32..48bf1bf56 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -84,6 +84,7 @@ class DivPlatformPCSpeaker: public DivDispatch { unsigned short freq, lastFreq; unsigned char regPool[2]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void beepFreq(int freq, int delay=0); diff --git a/src/engine/platform/pet.h b/src/engine/platform/pet.h index 8de217790..3046cc263 100644 --- a/src/engine/platform/pet.h +++ b/src/engine/platform/pet.h @@ -62,6 +62,7 @@ class DivPlatformPET: public DivDispatch { bool isMuted; unsigned char regPool[16]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index 1d737de59..5e2a32fc7 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -72,6 +72,7 @@ class DivPlatformQSound: public DivDispatch { struct qsound_chip chip; unsigned short regPool[512]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/rf5c68.h b/src/engine/platform/rf5c68.h index 50324fbf3..bcbb3da2e 100644 --- a/src/engine/platform/rf5c68.h +++ b/src/engine/platform/rf5c68.h @@ -71,6 +71,7 @@ class DivPlatformRF5C68: public DivDispatch { size_t sampleMemLen; rf5c68_device rf5c68; unsigned char regPool[144]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index 92855be7e..d2092efb9 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -72,6 +72,7 @@ class DivPlatformSAA1099: public DivDispatch { size_t saaBufLen; unsigned char saaEnv[2]; unsigned char saaNoise[2]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void acquire_saaSound(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/scc.h b/src/engine/platform/scc.h index b6117d4a1..20dcf4a97 100644 --- a/src/engine/platform/scc.h +++ b/src/engine/platform/scc.h @@ -65,6 +65,7 @@ class DivPlatformSCC: public DivDispatch { unsigned char regBase; unsigned char regPool[225]; void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 53e844ebd..650f54c91 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -441,8 +441,6 @@ void DivPlatformSegaPCM::reset() { pcmR=0; sampleBank=0; delay=0; - amDepth=0x7f; - pmDepth=0x7f; if (dumpWrites) { for (int i=0; i<16; i++) { @@ -451,8 +449,6 @@ void DivPlatformSegaPCM::reset() { addWrite(0x10003+(i<<3),0x7f); } } - - extMode=false; } void DivPlatformSegaPCM::setFlags(unsigned int flags) { diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 01fd38c61..888a33848 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -80,21 +80,19 @@ class DivPlatformSegaPCM: public DivDispatch { QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} }; std::queue writes; - int delay, baseFreqOff; + int delay; int pcmL, pcmR, pcmCycles; unsigned char sampleBank; unsigned char lastBusy; - unsigned char amDepth, pmDepth; unsigned char regPool[256]; - bool extMode, useYMFM; - bool isMuted[16]; short oldWrites[256]; short pendingWrites[256]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index eef54da1e..b382d38da 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -78,6 +78,7 @@ class DivPlatformSMS: public DivDispatch { QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} }; std::queue writes; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index d76d07227..d94df8eac 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -113,6 +113,7 @@ class DivPlatformSoundUnit: public DivDispatch { void writeControl(int ch); void writeControlUpper(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index cf7926385..473667a93 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -74,6 +74,7 @@ class DivPlatformSwan: public DivDispatch { std::queue writes; WSwan* ws; void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index b838e0682..3eb32b97a 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -46,6 +46,7 @@ class DivPlatformTIA: public DivDispatch { unsigned char chanOscCounter; TIA::Audio tia; unsigned char regPool[16]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); unsigned char dealWithFreq(unsigned char shape, int base, int pitch); diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index d1e427282..b1d09db90 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -88,6 +88,7 @@ class DivPlatformTX81Z: public DivPlatformOPM { int octave(int freq); int toFreq(int freq); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/vera.h b/src/engine/platform/vera.h index 53e766dcd..9cda01203 100644 --- a/src/engine/platform/vera.h +++ b/src/engine/platform/vera.h @@ -60,6 +60,7 @@ class DivPlatformVERA: public DivDispatch { struct VERA_PCM* pcm; int calcNoteFreq(int ch, int note); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/vic20.h b/src/engine/platform/vic20.h index d4b56028c..834051ddb 100644 --- a/src/engine/platform/vic20.h +++ b/src/engine/platform/vic20.h @@ -63,6 +63,7 @@ class DivPlatformVIC20: public DivDispatch { unsigned char regPool[16]; sound_vic20_t* vic; void updateWave(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/vrc6.h b/src/engine/platform/vrc6.h index 81c81016f..4c56bc797 100644 --- a/src/engine/platform/vrc6.h +++ b/src/engine/platform/vrc6.h @@ -78,6 +78,7 @@ class DivPlatformVRC6: public DivDispatch, public vrcvi_intf { vrcvi_core vrc6; unsigned char regPool[13]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index 1844cf09a..19fb91350 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -120,6 +120,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf { double NoteX1_010(int ch, int note); void updateWave(int ch); void updateEnvelope(int ch); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: u8 read_byte(u32 address); diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index 756603651..7a4aa7975 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -94,6 +94,7 @@ class DivPlatformYM2203: public DivPlatformOPN { bool extMode; unsigned char prescale; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index 527a8be6b..f3b279c97 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -63,7 +63,6 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { } if (opChan[ch].insChanged) { // TODO how does this work? rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3)); - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); } opChan[ch].insChanged=false; @@ -103,22 +102,6 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { } opChan[ch].ins=c.value; break; - case DIV_CMD_PANNING: { - if (c.value==0 && c.value2==0) { - opChan[ch].pan=3; - } else { - opChan[ch].pan=(c.value2>0)|((c.value>0)<<1); - } - DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); - if (parent->song.sharedExtStat) { - for (int i=0; i<4; i++) { - if (ch==i) continue; - opChan[i].pan=opChan[ch].pan; - } - } - rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4)); - break; - } case DIV_CMD_PITCH: { opChan[ch].pitch=c.value; opChan[ch].freqChanged=true; diff --git a/src/engine/platform/ym2203ext.h b/src/engine/platform/ym2203ext.h index d25ca45d5..9bc460af4 100644 --- a/src/engine/platform/ym2203ext.h +++ b/src/engine/platform/ym2203ext.h @@ -29,13 +29,29 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 { signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask; int vol; - unsigned char pan; // UGLY - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), mask(true), vol(0), pan(3) {} + OpChannel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + portaPauseFreq(0), + ins(-1), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + mask(true), + vol(0) {} }; OpChannel opChan[4]; bool isOpMuted[4]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index ff342eb79..b27f81ea3 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -546,14 +546,14 @@ void DivPlatformYM2608::tick(bool sysTick) { if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) { immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } - if (chan[i].keyOff) { - writeRSSOff|=(1<<(i-9)); - chan[i].keyOff=false; - } - if (chan[i].keyOn) { - writeRSSOn|=(1<<(i-9)); - chan[i].keyOn=false; - } + } + if (chan[i].keyOff) { + writeRSSOff|=(1<<(i-9)); + chan[i].keyOff=false; + } + if (chan[i].keyOn) { + writeRSSOn|=(1<<(i-9)); + chan[i].keyOn=false; } } // ADPCM-B @@ -854,6 +854,13 @@ int DivPlatformYM2608::dispatch(DivCommand c) { } break; } + case DIV_CMD_ADPCMA_GLOBAL_VOLUME: { + if (globalRSSVolume!=(c.value&0x3f)) { + globalRSSVolume=c.value&0x3f; + immWrite(0x11,globalRSSVolume&0x3f); + } + break; + } case DIV_CMD_GET_VOLUME: { return chan[c.chan].vol; break; @@ -1184,7 +1191,7 @@ void DivPlatformYM2608::forceIns() { if (i>14) { // ADPCM-B immWrite(0x10b,chan[i].outVol); } else { - immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].vol)); + immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } } @@ -1267,7 +1274,7 @@ void DivPlatformYM2608::reset() { immWrite(0x22,0x08); // PCM volume - immWrite(0x11,0x3f); // A + immWrite(0x11,globalRSSVolume); // A immWrite(0x10b,0xff); // B // ADPCM limit diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 8e2c4e407..073e381d8 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -110,6 +110,7 @@ class DivPlatformYM2608: public DivPlatformOPN { double NOTE_OPNB(int ch, int note); double NOTE_ADPCMB(int note); + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index 7f49ed9d6..66a4d252c 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -477,7 +477,7 @@ void DivPlatformYM2608Ext::forceIns() { if (i>14) { // ADPCM-B immWrite(0x10b,chan[i].outVol); } else { - immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].vol)); + immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } } ay->forceIns(); diff --git a/src/engine/platform/ym2608ext.h b/src/engine/platform/ym2608ext.h index 21c8a35c4..4792323cc 100644 --- a/src/engine/platform/ym2608ext.h +++ b/src/engine/platform/ym2608ext.h @@ -31,11 +31,29 @@ class DivPlatformYM2608Ext: public DivPlatformYM2608 { int vol; unsigned char pan; // UGLY - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), - inPorta(false), mask(true), vol(0), pan(3) {} + OpChannel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + portaPauseFreq(0), + ins(-1), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + inPorta(false), + mask(true), + vol(0), + pan(3) {} }; OpChannel opChan[4]; bool isOpMuted[4]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index f80624f4c..b8882304c 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -484,16 +484,16 @@ void DivPlatformYM2610::tick(bool sysTick) { if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) { immWrite(0x108+(i-adpcmAChanOffs),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } - if (chan[i].keyOff) { - writeADPCMAOff|=(1<<(i-adpcmAChanOffs)); - chan[i].keyOff=false; - } - if (chan[i].keyOn) { - if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { - writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); - } - chan[i].keyOn=false; + } + if (chan[i].keyOff) { + writeADPCMAOff|=(1<<(i-adpcmAChanOffs)); + chan[i].keyOff=false; + } + if (chan[i].keyOn) { + if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { + writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); } + chan[i].keyOn=false; } } // ADPCM-B @@ -1246,7 +1246,7 @@ void DivPlatformYM2610::reset() { immWrite(0x22,0x08); // PCM volume - immWrite(0x101,0x3f); // A + immWrite(0x101,globalADPCMAVolume); // A immWrite(0x1b,0xff); // B } @@ -1259,7 +1259,7 @@ bool DivPlatformYM2610::keyOffAffectsArp(int ch) { } void DivPlatformYM2610::notifyInsChange(int ins) { - for (int i=0; i<14; i++) { + for (int i=0; i { 1, 2, 4, 5 }; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 4ee8dea7b..9bcc45741 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -546,16 +546,16 @@ void DivPlatformYM2610B::tick(bool sysTick) { if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) { immWrite(0x108+(i-adpcmAChanOffs),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } - if (chan[i].keyOff) { - writeADPCMAOff|=(1<<(i-adpcmAChanOffs)); - chan[i].keyOff=false; - } - if (chan[i].keyOn) { - if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { - writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); - } - chan[i].keyOn=false; + } + if (chan[i].keyOff) { + writeADPCMAOff|=(1<<(i-adpcmAChanOffs)); + chan[i].keyOff=false; + } + if (chan[i].keyOn) { + if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { + writeADPCMAOn|=(1<<(i-adpcmAChanOffs)); } + chan[i].keyOn=false; } } // ADPCM-B @@ -1325,7 +1325,7 @@ bool DivPlatformYM2610B::keyOffAffectsArp(int ch) { } void DivPlatformYM2610B::notifyInsChange(int ins) { - for (int i=0; i<16; i++) { + for (int i=0; i { 0, 1, 2, 4, 5, 6 }; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index c54586d36..fcb5e2b00 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -24,6 +24,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B { DivPlatformYM2610Base::OpChannel opChan[4]; bool isOpMuted[4]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index ab7c060ff..5cc4432c5 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -24,6 +24,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { DivPlatformYM2610Base::OpChannel opChan[4]; bool isOpMuted[4]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: int dispatch(DivCommand c); diff --git a/src/engine/platform/ymz280b.h b/src/engine/platform/ymz280b.h index cd04186c6..72bf3791c 100644 --- a/src/engine/platform/ymz280b.h +++ b/src/engine/platform/ymz280b.h @@ -71,6 +71,7 @@ class DivPlatformYMZ280B: public DivDispatch { size_t sampleMemLen; ymz280b_device ymz280b; unsigned char regPool[256]; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: diff --git a/src/engine/platform/zxbeeper.h b/src/engine/platform/zxbeeper.h index 226f556de..b02b1fb76 100644 --- a/src/engine/platform/zxbeeper.h +++ b/src/engine/platform/zxbeeper.h @@ -72,6 +72,7 @@ class DivPlatformZXBeeper: public DivDispatch { int tempR[32]; unsigned char regPool[128]; bool sampleOut; + friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: void acquire(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 641df4d34..aff827718 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -28,6 +28,10 @@ #include "../engine/platform/c64.h" #include "../engine/platform/arcade.h" #include "../engine/platform/segapcm.h" +#include "../engine/platform/ym2203.h" +#include "../engine/platform/ym2203ext.h" +#include "../engine/platform/ym2608.h" +#include "../engine/platform/ym2608ext.h" #include "../engine/platform/ym2610.h" #include "../engine/platform/ym2610ext.h" #include "../engine/platform/ym2610b.h" @@ -45,7 +49,82 @@ #include "../engine/platform/pcmdac.h" #include "../engine/platform/dummy.h" -#define GENESIS_DEBUG \ +#define COMMON_CHIP_DEBUG \ + ImGui::Text("- rate: %d",ch->rate); \ + ImGui::Text("- chipClock: %.f",ch->chipClock); + +#define FM_CHIP_DEBUG \ + COMMON_CHIP_DEBUG; \ + ImGui::Text("- lastBusy: %d",ch->lastBusy); \ + ImGui::Text("- delay: %d",ch->delay); + +#define FM_OPN_CHIP_DEBUG \ + FM_CHIP_DEBUG; \ + ImGui::Text("- fmFreqBase: %.f",ch->fmFreqBase); \ + ImGui::Text("- fmDivBase: %d",ch->fmDivBase); \ + ImGui::Text("- ayDiv: %d",ch->ayDiv); + +#define COMMON_CHIP_DEBUG_BOOL \ + ImGui::TextColored(ch->skipRegisterWrites?colorOn:colorOff,">> SkipRegisterWrites"); \ + ImGui::TextColored(ch->dumpWrites?colorOn:colorOff,">> DumpWrites"); + +#define FM_CHIP_DEBUG_BOOL \ + COMMON_CHIP_DEBUG_BOOL; \ + ImGui::TextColored(ch->lastBusy?colorOn:colorOff,">> LastBusy"); \ + +#define FM_OPN_CHIP_DEBUG_BOOL \ + FM_CHIP_DEBUG_BOOL; \ + ImGui::TextColored(ch->extSys?colorOn:colorOff,">> ExtSys"); \ + +#define GENESIS_CHIP_DEBUG \ + DivPlatformGenesis* ch=(DivPlatformGenesis*)data; \ + ImGui::Text("> YM2612"); \ + FM_OPN_CHIP_DEBUG; \ + ImGui::Text("- lfoValue: %d",ch->lfoValue); \ + ImGui::Text("- softPCMTimer: %d",ch->softPCMTimer); \ + FM_OPN_CHIP_DEBUG_BOOL; \ + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); \ + ImGui::TextColored(ch->softPCM?colorOn:colorOff,">> SoftPCM"); \ + ImGui::TextColored(ch->useYMFM?colorOn:colorOff,">> UseYMFM"); \ + ImGui::TextColored(ch->ladder?colorOn:colorOff,">> Ladder"); + +#define OPNB_CHIP_DEBUG \ + FM_OPN_CHIP_DEBUG; \ + ImGui::Text("- adpcmAMemLen: %d",ch->adpcmAMemLen); \ + ImGui::Text("- adpcmBMemLen: %d",ch->adpcmBMemLen); \ + ImGui::Text("- sampleBank: %d",ch->sampleBank); \ + ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ + ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ + ImGui::Text("- globalADPCMAVolume: %d",ch->globalADPCMAVolume); \ + ImGui::Text("- extChanOffs: %d",ch->extChanOffs); \ + ImGui::Text("- psgChanOffs: %d",ch->psgChanOffs); \ + ImGui::Text("- adpcmAChanOffs: %d",ch->adpcmAChanOffs); \ + ImGui::Text("- adpcmBChanOffs: %d",ch->adpcmBChanOffs); \ + ImGui::Text("- chanNum: %d",ch->chanNum); \ + FM_OPN_CHIP_DEBUG_BOOL; \ + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); + +#define SMS_CHIP_DEBUG \ + DivPlatformSMS* sms=(DivPlatformSMS*)data; \ + ImGui::Text("> SMS"); \ + ImGui::Text("- rate: %d",sms->rate); \ + ImGui::Text("- chipClock: %.f",sms->chipClock); \ + ImGui::Text("- lastPan: %d",sms->lastPan); \ + ImGui::Text("- oldValue: %d",sms->oldValue); \ + ImGui::Text("- snNoiseMode: %d",sms->snNoiseMode); \ + ImGui::Text("- divider: %d",sms->divider); \ + ImGui::Text("- toneDivider: %.f",sms->toneDivider); \ + ImGui::Text("- noiseDivider: %.f",sms->noiseDivider); \ + ImGui::TextColored(sms->skipRegisterWrites?colorOn:colorOff,">> SkipRegisterWrites"); \ + ImGui::TextColored(sms->dumpWrites?colorOn:colorOff,">> DumpWrites"); \ + ImGui::TextColored(sms->updateSNMode?colorOn:colorOff,">> UpdateSNMode"); \ + ImGui::TextColored(sms->resetPhase?colorOn:colorOff,">> ResetPhase"); \ + ImGui::TextColored(sms->isRealSN?colorOn:colorOff,">> IsRealSN"); \ + ImGui::TextColored(sms->stereo?colorOn:colorOff,">> Stereo"); \ + ImGui::TextColored(sms->nuked?colorOn:colorOff,">> Nuked"); + + +#define GENESIS_CHAN_DEBUG \ DivPlatformGenesis::Channel* ch=(DivPlatformGenesis::Channel*)data; \ ImGui::Text("> YM2612"); \ ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ @@ -53,11 +132,21 @@ ImGui::Text(" - base: %d",ch->baseFreq); \ ImGui::Text(" - pitch: %d",ch->pitch); \ ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("* DAC:"); \ + ImGui::Text(" - period: %d",ch->dacPeriod); \ + ImGui::Text(" - rate: %d",ch->dacRate); \ + ImGui::Text(" - pos: %d",ch->dacPos); \ + ImGui::Text(" - sample: %d",ch->dacSample); \ + ImGui::Text(" - delay: %d",ch->dacDelay); \ + ImGui::Text(" - output: %d",ch->dacOutput); \ ImGui::Text("- note: %d",ch->note); \ ImGui::Text("- ins: %d",ch->ins); \ ImGui::Text("- vol: %.2x",ch->vol); \ ImGui::Text("- outVol: %.2x",ch->outVol); \ ImGui::Text("- pan: %x",ch->pan); \ + ImGui::Text("- opMask: %x",ch->opMask); \ + ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ @@ -65,9 +154,35 @@ ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); \ - ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \ + ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \ + ImGui::TextColored(ch->dacMode?colorOn:colorOff,">> DACMode"); \ + ImGui::TextColored(ch->dacReady?colorOn:colorOff,">> DACReady"); \ + ImGui::TextColored(ch->dacDirection?colorOn:colorOff,">> DACDirection"); -#define SMS_DEBUG \ +#define GENESIS_OPCHAN_DEBUG \ + DivPlatformGenesisExt::OpChannel* ch=(DivPlatformGenesisExt::OpChannel*)data; \ + ImGui::Text("> YM2612 (per operator)"); \ + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ + ImGui::Text("* freq: %d",ch->freq); \ + ImGui::Text(" - base: %d",ch->baseFreq); \ + ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("- ins: %d",ch->ins); \ + ImGui::Text("- vol: %.2x",ch->vol); \ + ImGui::Text("- pan: %x",ch->pan); \ + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->mask?colorOn:colorOff,">> Mask"); + +#define SMS_CHAN_DEBUG \ DivPlatformSMS::Channel* ch=(DivPlatformSMS::Channel*)data; \ ImGui::Text("> SMS"); \ ImGui::Text("* freq: %d",ch->freq); \ @@ -84,31 +199,477 @@ ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); +#define OPN_CHAN_DEBUG \ + DivPlatformYM2203::Channel* ch=(DivPlatformYM2203::Channel*)data; \ + ImGui::Text("> YM2203"); \ + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ + ImGui::Text("* freq: %d",ch->freq); \ + ImGui::Text(" - base: %d",ch->baseFreq); \ + ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("* PSG:"); \ + ImGui::Text(" - psgMode: %d",ch->psgMode); \ + ImGui::Text(" - autoEnvNum: %d",ch->autoEnvNum); \ + ImGui::Text(" - autoEnvDen: %d",ch->autoEnvDen); \ + ImGui::Text("- sample: %d",ch->sample); \ + ImGui::Text("- note: %d",ch->note); \ + ImGui::Text("- ins: %d",ch->ins); \ + ImGui::Text("- vol: %.2x",ch->vol); \ + ImGui::Text("- outVol: %.2x",ch->outVol); \ + ImGui::Text("- opMask: %x",ch->opMask); \ + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \ + ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \ + ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); + +#define OPN_OPCHAN_DEBUG \ + DivPlatformYM2203Ext::OpChannel* ch=(DivPlatformYM2203Ext::OpChannel*)data; \ + ImGui::Text("> YM2203 (per operator)"); \ + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ + ImGui::Text("* freq: %d",ch->freq); \ + ImGui::Text(" - base: %d",ch->baseFreq); \ + ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("- ins: %d",ch->ins); \ + ImGui::Text("- vol: %.2x",ch->vol); \ + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->mask?colorOn:colorOff,">> Mask"); + +#define OPNB_CHAN_DEBUG \ + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ + ImGui::Text("* freq: %d",ch->freq); \ + ImGui::Text(" - base: %d",ch->baseFreq); \ + ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("* PSG:"); \ + ImGui::Text(" - psgMode: %d",ch->psgMode); \ + ImGui::Text(" - autoEnvNum: %d",ch->autoEnvNum); \ + ImGui::Text(" - autoEnvDen: %d",ch->autoEnvDen); \ + ImGui::Text("- sample: %d",ch->sample); \ + ImGui::Text("- note: %d",ch->note); \ + ImGui::Text("- ins: %d",ch->ins); \ + ImGui::Text("- vol: %.2x",ch->vol); \ + ImGui::Text("- outVol: %.2x",ch->outVol); \ + ImGui::Text("- pan: %x",ch->pan); \ + ImGui::Text("- opMask: %x",ch->opMask); \ + ImGui::Text("- macroVolMul: %x",ch->macroVolMul); \ + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \ + ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \ + ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM"); + +#define OPNB_OPCHAN_DEBUG \ + ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \ + ImGui::Text("* freq: %d",ch->freq); \ + ImGui::Text(" - base: %d",ch->baseFreq); \ + ImGui::Text(" - pitch: %d",ch->pitch); \ + ImGui::Text(" - pitch2: %d",ch->pitch2); \ + ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \ + ImGui::Text("- ins: %d",ch->ins); \ + ImGui::Text("- vol: %.2x",ch->vol); \ + ImGui::Text("- pan: %x",ch->pan); \ + ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \ + ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \ + ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \ + ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \ + ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \ + ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \ + ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \ + ImGui::TextColored(ch->mask?colorOn:colorOff,">> Mask"); + +void putDispatchChip(void* data, int type) { + ImVec4 colorOn=ImVec4(1.0f,1.0f,0.0f,1.0f); + ImVec4 colorOff=ImVec4(0.3f,0.3f,0.3f,1.0f); + switch (type) { + case DIV_SYSTEM_YM2612: + case DIV_SYSTEM_YM2612_EXT: + case DIV_SYSTEM_YM2612_FRAC: + case DIV_SYSTEM_YM2612_FRAC_EXT: { + GENESIS_CHIP_DEBUG; + break; + } + case DIV_SYSTEM_GENESIS: + case DIV_SYSTEM_GENESIS_EXT: { + GENESIS_CHIP_DEBUG; + SMS_CHIP_DEBUG; + break; + } + case DIV_SYSTEM_SMS: { + SMS_CHIP_DEBUG; + break; + } + case DIV_SYSTEM_OPN: + case DIV_SYSTEM_OPN_EXT: { + DivPlatformYM2203* ch=(DivPlatformYM2203*)data; + ImGui::Text("> YM2203"); + FM_OPN_CHIP_DEBUG; + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- prescale: %d",ch->prescale); + FM_OPN_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); + break; + } + case DIV_SYSTEM_PC98: + case DIV_SYSTEM_PC98_EXT: { + DivPlatformYM2608* ch=(DivPlatformYM2608*)data; + ImGui::Text("> YM2608"); + FM_OPN_CHIP_DEBUG; + ImGui::Text("- adpcmBMemLen: %d",ch->adpcmBMemLen); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); + ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); + ImGui::Text("- globalRSSVolume: %d",ch->globalRSSVolume); + ImGui::Text("- prescale: %d",ch->prescale); + FM_OPN_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); + break; + } + case DIV_SYSTEM_YM2610: + case DIV_SYSTEM_YM2610_EXT: + case DIV_SYSTEM_YM2610_FULL: + case DIV_SYSTEM_YM2610_FULL_EXT: { + DivPlatformYM2610* ch=(DivPlatformYM2610*)data; + ImGui::Text("> YM2610"); + OPNB_CHIP_DEBUG; + break; + } + case DIV_SYSTEM_YM2610B: + case DIV_SYSTEM_YM2610B_EXT: { + DivPlatformYM2610B* ch=(DivPlatformYM2610B*)data; + ImGui::Text("> YM2610B"); + OPNB_CHIP_DEBUG; + break; + } + case DIV_SYSTEM_GB: { + DivPlatformGB* ch=(DivPlatformGB*)data; + ImGui::Text("> GameBoy"); + COMMON_CHIP_DEBUG; + ImGui::Text("- lastPan: %d",ch->lastPan); + ImGui::Text("- antiClickPeriodCount: %d",ch->antiClickPeriodCount); + ImGui::Text("- antiClickWavePos: %d",ch->antiClickWavePos); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->antiClickEnabled?colorOn:colorOff,">> AntiClickEnabled"); + break; + } + case DIV_SYSTEM_PCE: { + DivPlatformPCE* ch=(DivPlatformPCE*)data; + ImGui::Text("> PCEngine"); + COMMON_CHIP_DEBUG; + ImGui::Text("- lastPan: %d",ch->lastPan); + ImGui::Text("- cycles: %d",ch->cycles); + ImGui::Text("- curChan: %d",ch->curChan); + ImGui::Text("- delay: %d",ch->delay); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- lfoMode: %d",ch->lfoMode); + ImGui::Text("- lfoSpeed: %d",ch->lfoSpeed); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->antiClickEnabled?colorOn:colorOff,">> AntiClickEnabled"); + break; + } + case DIV_SYSTEM_NES: { + DivPlatformNES* ch=(DivPlatformNES*)data; + ImGui::Text("> NES"); + COMMON_CHIP_DEBUG; + ImGui::Text("* DAC:"); + ImGui::Text(" - Period: %d",ch->dacPeriod); + ImGui::Text(" - Rate: %d",ch->dacRate); + ImGui::Text(" - Pos: %d",ch->dacPos); + ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); + ImGui::Text(" - Sample: %d",ch->dacSample); + ImGui::Text("- dpcmMemLen: %d",ch->dpcmMemLen); + ImGui::Text("- dpcmBank: %d",ch->dpcmBank); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); + ImGui::Text("- apuType: %d",ch->apuType); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->dpcmMode?colorOn:colorOff,">> DPCMMode"); + ImGui::TextColored(ch->dacAntiClickOn?colorOn:colorOff,">> DACAntiClickOn"); + ImGui::TextColored(ch->useNP?colorOn:colorOff,">> UseNP"); + ImGui::TextColored(ch->goingToLoop?colorOn:colorOff,">> GoingToLoop"); + break; + } + case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: { + DivPlatformC64* ch=(DivPlatformC64*)data; + ImGui::Text("> C64"); + COMMON_CHIP_DEBUG; + ImGui::Text("- filtControl: %d",ch->filtControl); + ImGui::Text("- filtRes: %d",ch->filtRes); + ImGui::Text("- vol: %d",ch->vol); + ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); + ImGui::Text("- filtCut: %d",ch->filtCut); + ImGui::Text("- resetTime: %d",ch->resetTime); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->isFP?colorOn:colorOff,">> IsFP"); + break; + } + case DIV_SYSTEM_ARCADE: + case DIV_SYSTEM_YM2151: { + DivPlatformArcade* ch=(DivPlatformArcade*)data; + ImGui::Text("> YM2151"); + FM_CHIP_DEBUG; + ImGui::Text("- baseFreqOff: %d",ch->baseFreqOff); + ImGui::Text("- amDepth: %d",ch->amDepth); + ImGui::Text("- pmDepth: %d",ch->pmDepth); + FM_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->useYMFM?colorOn:colorOff,">> UseYMFM"); + break; + } + case DIV_SYSTEM_SEGAPCM: + case DIV_SYSTEM_SEGAPCM_COMPAT: { + DivPlatformSegaPCM* ch=(DivPlatformSegaPCM*)data; + ImGui::Text("> SegaPCM"); + COMMON_CHIP_DEBUG; + ImGui::Text("- delay: %d",ch->delay); + ImGui::Text("- pcmL: %d",ch->pcmL); + ImGui::Text("- pcmR: %d",ch->pcmR); + ImGui::Text("- pcmCycles: %d",ch->pcmCycles); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- lastBusy: %d",ch->lastBusy); + COMMON_CHIP_DEBUG_BOOL; + break; + } + case DIV_SYSTEM_AY8910: { + DivPlatformAY8910* ch=(DivPlatformAY8910*)data; + ImGui::Text("> AY-3-8910"); + COMMON_CHIP_DEBUG; + ImGui::Text("- lastBusy: %d",ch->lastBusy); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- stereoSep: %d",ch->stereoSep); + ImGui::Text("- delay: %d",ch->delay); + ImGui::Text("- extClock: %d",ch->extClock); + ImGui::Text("- extDiv: %d",ch->extDiv); + ImGui::Text("- portAVal: %d",ch->portAVal); + ImGui::Text("- portBVal: %d",ch->portBVal); + ImGui::Text("* envelope:"); + ImGui::Text(" - mode: %d",ch->ayEnvMode); + ImGui::Text(" - period: %d",ch->ayEnvPeriod); + ImGui::Text(" * slide: %d",ch->ayEnvSlide); + ImGui::Text(" - slideLow: %d",ch->ayEnvSlideLow); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); + ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo"); + ImGui::TextColored(ch->sunsoft?colorOn:colorOff,">> Sunsoft"); + ImGui::TextColored(ch->intellivision?colorOn:colorOff,">> Intellivision"); + ImGui::TextColored(ch->clockSel?colorOn:colorOff,">> ClockSel"); + ImGui::TextColored(ch->ioPortA?colorOn:colorOff,">> IoPortA"); + ImGui::TextColored(ch->ioPortB?colorOn:colorOff,">> IoPortB"); + break; + } + case DIV_SYSTEM_AY8930: { + DivPlatformAY8930* ch=(DivPlatformAY8930*)data; + ImGui::Text("> AY8930"); + COMMON_CHIP_DEBUG; + ImGui::Text("* noise:"); + ImGui::Text(" - and: %d",ch->ayNoiseAnd); + ImGui::Text(" - or: %d",ch->ayNoiseOr); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- stereoSep: %d",ch->stereoSep); + ImGui::Text("- delay: %d",ch->delay); + ImGui::Text("- portAVal: %d",ch->portAVal); + ImGui::Text("- portBVal: %d",ch->portBVal); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->bank?colorOn:colorOff,">> Bank"); + ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); + ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo"); + ImGui::TextColored(ch->clockSel?colorOn:colorOff,">> ClockSel"); + ImGui::TextColored(ch->ioPortA?colorOn:colorOff,">> IoPortA"); + ImGui::TextColored(ch->ioPortB?colorOn:colorOff,">> IoPortB"); + break; + } + case DIV_SYSTEM_QSOUND: { + DivPlatformQSound* ch=(DivPlatformQSound*)data; + ImGui::Text("> QSound"); + COMMON_CHIP_DEBUG; + ImGui::Text("* echo:"); + ImGui::Text(" - delay: %d",ch->echoDelay); + ImGui::Text(" - feedback: %d",ch->echoFeedback); + ImGui::Text("- sampleMemLen: %d",ch->sampleMemLen); + COMMON_CHIP_DEBUG_BOOL; + break; + } + case DIV_SYSTEM_X1_010: { + DivPlatformX1_010* ch=(DivPlatformX1_010*)data; + ImGui::Text("> X1-010"); + COMMON_CHIP_DEBUG; + ImGui::Text("- sampleMemLen: %d",ch->sampleMemLen); + ImGui::Text("- sampleBank: %d",ch->sampleBank); + ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo"); + ImGui::TextColored(ch->isBanked?colorOn:colorOff,">> IsBanked"); + break; + } + case DIV_SYSTEM_N163: { + DivPlatformN163* ch=(DivPlatformN163*)data; + ImGui::Text("> N163"); + COMMON_CHIP_DEBUG; + ImGui::Text("- initChanMax: %d",ch->initChanMax); + ImGui::Text("- chanMax: %d",ch->chanMax); + ImGui::Text("- loadWave: %d",ch->loadWave); + ImGui::Text("- loadPos: %d",ch->loadPos); + ImGui::Text("- loadLen: %d",ch->loadLen); + ImGui::Text("- loadMode: %d",ch->loadMode); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->multiplex?colorOn:colorOff,">> Multiplex"); + break; + } + case DIV_SYSTEM_VRC6: { + DivPlatformVRC6* ch=(DivPlatformVRC6*)data; + ImGui::Text("> VRC6"); + COMMON_CHIP_DEBUG; + ImGui::Text("- sampleBank: %.2x",ch->sampleBank); + ImGui::Text("- writeOscBuf: %.2x",ch->writeOscBuf); + COMMON_CHIP_DEBUG_BOOL; + break; + } + case DIV_SYSTEM_LYNX: { + DivPlatformLynx* ch=(DivPlatformLynx*)data; + ImGui::Text("> Lynx"); + COMMON_CHIP_DEBUG; + COMMON_CHIP_DEBUG_BOOL; + break; + } + case DIV_SYSTEM_PCM_DAC: { + DivPlatformPCMDAC* ch=(DivPlatformPCMDAC*)data; + ImGui::Text("> PCM DAC"); + COMMON_CHIP_DEBUG; + ImGui::Text("- outDepth: %d",ch->outDepth); + COMMON_CHIP_DEBUG_BOOL; + ImGui::TextColored(ch->outStereo?colorOn:colorOff,">> OutStereo"); + break; + } + default: + ImGui::Text("Unimplemented chip! Help!"); + break; + } +} void putDispatchChan(void* data, int chanNum, int type) { ImVec4 colorOn=ImVec4(1.0f,1.0f,0.0f,1.0f); ImVec4 colorOff=ImVec4(0.3f,0.3f,0.3f,1.0f); switch (type) { - case DIV_SYSTEM_GENESIS: - case DIV_SYSTEM_YM2612: { + case DIV_SYSTEM_GENESIS: { if (chanNum>5) { - SMS_DEBUG; + SMS_CHAN_DEBUG; } else { - GENESIS_DEBUG; + GENESIS_CHAN_DEBUG; } break; } case DIV_SYSTEM_GENESIS_EXT: { if (chanNum>8) { - SMS_DEBUG; + SMS_CHAN_DEBUG; } else if (chanNum>=2 && chanNum<=5) { - // TODO ext ch 3 debug + GENESIS_OPCHAN_DEBUG } else { - GENESIS_DEBUG; + GENESIS_CHAN_DEBUG; + } + break; + } + case DIV_SYSTEM_YM2612: + case DIV_SYSTEM_YM2612_FRAC: { + GENESIS_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_YM2612_EXT: + case DIV_SYSTEM_YM2612_FRAC_EXT: { + if (chanNum>=2 && chanNum<=5) { + GENESIS_OPCHAN_DEBUG + } else { + GENESIS_CHAN_DEBUG; } break; } case DIV_SYSTEM_SMS: { - SMS_DEBUG; + SMS_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_OPN: { + OPN_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_OPN_EXT: { + if (chanNum>=2 && chanNum<=5) { + OPN_OPCHAN_DEBUG; + } else { + OPN_CHAN_DEBUG; + } + break; + } + case DIV_SYSTEM_PC98: { + DivPlatformYM2608::Channel* ch=(DivPlatformYM2608::Channel*)data; + ImGui::Text("> YM2608"); + OPNB_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_PC98_EXT: { + if (chanNum>=2 && chanNum<=5) { + DivPlatformYM2608Ext::OpChannel* ch=(DivPlatformYM2608Ext::OpChannel*)data; + ImGui::Text("> YM2608 (per operator)"); + OPNB_OPCHAN_DEBUG; + } else { + DivPlatformYM2608Ext::Channel* ch=(DivPlatformYM2608Ext::Channel*)data; + ImGui::Text("> YM2608"); + OPNB_CHAN_DEBUG; + } + break; + } + case DIV_SYSTEM_YM2610: + case DIV_SYSTEM_YM2610_FULL: { + DivPlatformYM2610::Channel* ch=(DivPlatformYM2610::Channel*)data; + ImGui::Text("> YM2610"); + OPNB_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_YM2610B: { + DivPlatformYM2610B::Channel* ch=(DivPlatformYM2610B::Channel*)data; + ImGui::Text("> YM2610B"); + OPNB_CHAN_DEBUG; + break; + } + case DIV_SYSTEM_YM2610_EXT: + case DIV_SYSTEM_YM2610_FULL_EXT: { + if (chanNum>=1 && chanNum<=4) { + DivPlatformYM2610Ext::OpChannel* ch=(DivPlatformYM2610Ext::OpChannel*)data; + ImGui::Text("> YM2610 (per operator)"); + OPNB_OPCHAN_DEBUG; + } else { + DivPlatformYM2610Ext::Channel* ch=(DivPlatformYM2610Ext::Channel*)data; + ImGui::Text("> YM2610"); + OPNB_CHAN_DEBUG; + } + break; + } + case DIV_SYSTEM_YM2610B_EXT: { + if (chanNum>=2 && chanNum<=5) { + DivPlatformYM2610BExt::OpChannel* ch=(DivPlatformYM2610BExt::OpChannel*)data; + ImGui::Text("> YM2610B (per operator)"); + OPNB_OPCHAN_DEBUG; + } else { + DivPlatformYM2610BExt::Channel* ch=(DivPlatformYM2610BExt::Channel*)data; + ImGui::Text("> YM2610B"); + OPNB_CHAN_DEBUG; + } break; } case DIV_SYSTEM_GB: { diff --git a/src/gui/debug.h b/src/gui/debug.h index 1f22b4855..e3c911a84 100644 --- a/src/gui/debug.h +++ b/src/gui/debug.h @@ -21,5 +21,6 @@ #define _GUI_DEBUG_H #include "../engine/song.h" +void putDispatchChip(void* data, int type); void putDispatchChan(void* data, int chanNum, int type); #endif \ No newline at end of file diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index eec6fefb2..8033add4d 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -66,6 +66,22 @@ void FurnaceGUI::drawDebug() { ImGui::Checkbox("Enable",&bpOn); ImGui::TreePop(); } + if (ImGui::TreeNode("Chip Status")) { + ImGui::Text("for best results set latency to minimum or use the Frame Advance button."); + ImGui::Columns(e->song.systemLen); + for (int i=0; isong.systemLen; i++) { + void* ch=e->getDispatch(i); + ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Chip %d: %s",i,getSystemName(e->song.system[i])); + if (e->song.system[i]==NULL) { + ImGui::Text("NULL"); + } else { + putDispatchChip(ch,e->song.system[i]); + } + ImGui::NextColumn(); + } + ImGui::Columns(); + ImGui::TreePop(); + } if (ImGui::TreeNode("Dispatch Status")) { ImGui::Text("for best results set latency to minimum or use the Frame Advance button."); ImGui::Columns(e->getTotalChannelCount()); From 62ce5ae3cedefd3f2869a55360ddd85ede19ecf7 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 23:41:55 +0900 Subject: [PATCH 18/46] Add compatible flag for PCE DAC volume (always enabled for now) Fix furnacePCM detection for MSM6295 --- src/engine/fileOps.cpp | 2 ++ src/engine/platform/msm6295.cpp | 2 +- src/engine/platform/pce.cpp | 14 ++++++++------ src/engine/song.h | 2 ++ src/gui/compatFlags.cpp | 4 ++++ 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index abfd7395b..2757ac274 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -178,6 +178,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.e1e2StopOnSameNote=true; ds.brokenPortaArp=false; ds.snNoLowPeriods=true; + ds.ignorePCEDACVolume=true; ds.delayBehavior=0; ds.jumpTreatment=2; @@ -1100,6 +1101,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<115) { ds.autoSystem=false; } + ds.ignorePCEDACVolume=true; ds.isDMF=false; reader.readS(); // reserved diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index bd9bce01c..5cfec125a 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -126,7 +126,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); - if (ins->type==DIV_INS_AMIGA) { + if (ins->type==DIV_INS_MSM6295 || ins->type==DIV_INS_AMIGA) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index ea6f0e56e..74667c870 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -69,7 +69,7 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) signed char dacData=((signed char)((unsigned char)s->data8[chan[i].dacPos]^0x80))>>3; chan[i].dacOut=CLAMP(dacData,-16,15); if (!isMuted[i]) { - chWrite(i,0x04,0xc0|chan[i].outVol); + chWrite(i,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[i].outVol)); chWrite(i,0x06,chan[i].dacOut&0x1f); } else { chWrite(i,0x04,0xc0); @@ -208,7 +208,7 @@ void DivPlatformPCE::tick(bool sysTick) { if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { chan[i].dacPos=0; chan[i].dacPeriod=0; - chWrite(i,0x04,0xc0|chan[i].vol); + chWrite(i,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[i].vol)); addWrite(0xffff0000+(i<<8),chan[i].dacSample); chan[i].keyOn=true; } @@ -275,7 +275,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; } else { if (dumpWrites) { - chWrite(c.chan,0x04,0xc0|chan[c.chan].vol); + chWrite(c.chan,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[c.chan].vol)); addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); } } @@ -310,7 +310,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].dacPeriod=0; chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate; if (dumpWrites) { - chWrite(c.chan,0x04,0xc0|chan[c.chan].vol); + chWrite(c.chan,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[c.chan].vol)); addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate); } } @@ -362,7 +362,9 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].vol=c.value; if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; - if (chan[c.chan].active) chWrite(c.chan,0x04,0x80|chan[c.chan].outVol); + if (chan[c.chan].active && !chan[c.chan].pcm) { + chWrite(c.chan,0x04,0x80|chan[c.chan].outVol); + } } } break; @@ -464,7 +466,7 @@ void DivPlatformPCE::muteChannel(int ch, bool mute) { isMuted[ch]=mute; chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan); if (!isMuted[ch] && (chan[ch].pcm && chan[ch].dacSample!=-1)) { - chWrite(ch,0x04,0xc0|chan[ch].outVol); + chWrite(ch,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[ch].outVol)); chWrite(ch,0x06,chan[ch].dacOut&0x1f); } } diff --git a/src/engine/song.h b/src/engine/song.h index 09a89378c..28a31c759 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -511,6 +511,7 @@ struct DivSong { bool e1e2StopOnSameNote; bool brokenPortaArp; bool snNoLowPeriods; + bool ignorePCEDACVolume; bool autoSystem; std::vector ins; @@ -616,6 +617,7 @@ struct DivSong { e1e2StopOnSameNote(false), brokenPortaArp(false), snNoLowPeriods(false), + ignorePCEDACVolume(true), autoSystem(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index 63571dcac..c3627efad 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -143,6 +143,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("when enabled, any SN period under 8 will be written as 1 instead.\nthis replicates DefleMask behavior, but reduces available period range."); } + ImGui::Checkbox("Ignore PC Engine DAC Volume",&e->song.ignorePCEDACVolume); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("when enabled, PC Engine DAC Volume is ignored."); + } ImGui::Text("Pitch linearity:"); if (ImGui::RadioButton("None",e->song.linearPitch==0)) { From b41d306cb3a47af14685bbadeea8697205fd916d Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 23 Sep 2022 23:42:56 +0900 Subject: [PATCH 19/46] Fix compile --- src/gui/debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index aff827718..23d0df10e 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -51,7 +51,7 @@ #define COMMON_CHIP_DEBUG \ ImGui::Text("- rate: %d",ch->rate); \ - ImGui::Text("- chipClock: %.f",ch->chipClock); + ImGui::Text("- chipClock: %d",ch->chipClock); #define FM_CHIP_DEBUG \ COMMON_CHIP_DEBUG; \ From a44d696f092c12c4b7af23173fe6e2c75398656d Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 00:11:34 +0900 Subject: [PATCH 20/46] Fix compile (again) --- src/gui/debug.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 23d0df10e..602b7fb0d 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -90,8 +90,8 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- adpcmAMemLen: %d",ch->adpcmAMemLen); \ - ImGui::Text("- adpcmBMemLen: %d",ch->adpcmBMemLen); \ + ImGui::Text("- adpcmAMemLen: %.8x",ch->adpcmAMemLen); \ + ImGui::Text("- adpcmBMemLen: %.8x",ch->adpcmBMemLen); \ ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ @@ -108,7 +108,7 @@ DivPlatformSMS* sms=(DivPlatformSMS*)data; \ ImGui::Text("> SMS"); \ ImGui::Text("- rate: %d",sms->rate); \ - ImGui::Text("- chipClock: %.f",sms->chipClock); \ + ImGui::Text("- chipClock: %d",sms->chipClock); \ ImGui::Text("- lastPan: %d",sms->lastPan); \ ImGui::Text("- oldValue: %d",sms->oldValue); \ ImGui::Text("- snNoiseMode: %d",sms->snNoiseMode); \ @@ -335,7 +335,7 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- adpcmBMemLen: %d",ch->adpcmBMemLen); + ImGui::Text("- adpcmBMemLen: %.8x",ch->adpcmBMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); @@ -397,7 +397,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - Pos: %d",ch->dacPos); ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); - ImGui::Text("- dpcmMemLen: %d",ch->dpcmMemLen); + ImGui::Text("- dpcmMemLen: %.8x",ch->dpcmMemLen); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); @@ -504,7 +504,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* echo:"); ImGui::Text(" - delay: %d",ch->echoDelay); ImGui::Text(" - feedback: %d",ch->echoFeedback); - ImGui::Text("- sampleMemLen: %d",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %.8x",ch->sampleMemLen); COMMON_CHIP_DEBUG_BOOL; break; } @@ -512,7 +512,7 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleMemLen: %d",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %.8x",ch->sampleMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; From b05dafe297795b8839c31670f9cdd413c1247754 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 00:24:30 +0900 Subject: [PATCH 21/46] Add compatible flag for Y8950 ADPCM Frequency --- src/engine/fileOps.cpp | 2 ++ src/engine/platform/opl.cpp | 6 ++++-- src/engine/song.h | 2 ++ src/gui/compatFlags.cpp | 4 ++++ src/gui/debug.cpp | 12 ++++++------ 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 2757ac274..7eb148eae 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -179,6 +179,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.brokenPortaArp=false; ds.snNoLowPeriods=true; ds.ignorePCEDACVolume=true; + ds.newY8950PCMFreq=false; ds.delayBehavior=0; ds.jumpTreatment=2; @@ -1102,6 +1103,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.autoSystem=false; } ds.ignorePCEDACVolume=true; + ds.newY8950PCMFreq=false; ds.isDMF=false; reader.readS(); // reserved diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index d3437240b..148ce2799 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -28,6 +28,8 @@ #define KVSL(x,y) ((chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==2 && isOutputL[ops==4][chan[x].state.alg][y]) || chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==1) +#define OPLPCMDiv (parent->song.newY8950PCMFreq?((oplType==3)?288:72):144) + #define CHIP_FREQBASE chipFreqBase // N = invalid @@ -274,7 +276,7 @@ double DivPlatformOPL::NOTE_ADPCMB(int note) { if (adpcmChan<0) return 0; if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - return parent->calcBaseFreq((double)chipClock/((oplType==3)?288:72),off,note,false); + return parent->calcBaseFreq((double)chipClock/OPLPCMDiv,off,note,false); } return 0; } @@ -504,7 +506,7 @@ void DivPlatformOPL::tick(bool sysTick) { if (chan[adpcmChan].freqChanged || chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/((oplType==3)?288:72),off); + chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/OPLPCMDiv,off); } else { chan[adpcmChan].freq=0; } diff --git a/src/engine/song.h b/src/engine/song.h index 28a31c759..9f5ca1544 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -512,6 +512,7 @@ struct DivSong { bool brokenPortaArp; bool snNoLowPeriods; bool ignorePCEDACVolume; + bool newY8950PCMFreq; bool autoSystem; std::vector ins; @@ -618,6 +619,7 @@ struct DivSong { brokenPortaArp(false), snNoLowPeriods(false), ignorePCEDACVolume(true), + newY8950PCMFreq(false), autoSystem(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index c3627efad..80e9b0f57 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -147,6 +147,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("when enabled, PC Engine DAC Volume is ignored."); } + ImGui::Checkbox("New Y8950 Frequency calculation",&e->song.newY8950PCMFreq); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("when enabled, use corrected Y8950 frequency calculation"); + } ImGui::Text("Pitch linearity:"); if (ImGui::RadioButton("None",e->song.linearPitch==0)) { diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 602b7fb0d..652150abb 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -90,8 +90,8 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- adpcmAMemLen: %.8x",ch->adpcmAMemLen); \ - ImGui::Text("- adpcmBMemLen: %.8x",ch->adpcmBMemLen); \ + ImGui::Text("- adpcmAMemLen: %lld",ch->adpcmAMemLen); \ + ImGui::Text("- adpcmBMemLen: %lld",ch->adpcmBMemLen); \ ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ @@ -335,7 +335,7 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- adpcmBMemLen: %.8x",ch->adpcmBMemLen); + ImGui::Text("- adpcmBMemLen: %lld",ch->adpcmBMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); @@ -397,7 +397,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - Pos: %d",ch->dacPos); ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); - ImGui::Text("- dpcmMemLen: %.8x",ch->dpcmMemLen); + ImGui::Text("- dpcmMemLen: %lld",ch->dpcmMemLen); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); @@ -504,7 +504,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* echo:"); ImGui::Text(" - delay: %d",ch->echoDelay); ImGui::Text(" - feedback: %d",ch->echoFeedback); - ImGui::Text("- sampleMemLen: %.8x",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %lld",ch->sampleMemLen); COMMON_CHIP_DEBUG_BOOL; break; } @@ -512,7 +512,7 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleMemLen: %.8x",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %lld",ch->sampleMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; From 53c3efc9c1a173ec8301f2273208a36193d965f4 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 00:32:05 +0900 Subject: [PATCH 22/46] Fix compile (once again) --- src/gui/debug.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 652150abb..e56828d65 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -90,8 +90,8 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- adpcmAMemLen: %lld",ch->adpcmAMemLen); \ - ImGui::Text("- adpcmBMemLen: %lld",ch->adpcmBMemLen); \ + ImGui::Text("- adpcmAMemLen: %llu",ch->adpcmAMemLen); \ + ImGui::Text("- adpcmBMemLen: %llu",ch->adpcmBMemLen); \ ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ @@ -335,7 +335,7 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- adpcmBMemLen: %lld",ch->adpcmBMemLen); + ImGui::Text("- adpcmBMemLen: %llu",ch->adpcmBMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); @@ -397,7 +397,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - Pos: %d",ch->dacPos); ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); - ImGui::Text("- dpcmMemLen: %lld",ch->dpcmMemLen); + ImGui::Text("- dpcmMemLen: %llu",ch->dpcmMemLen); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); @@ -504,7 +504,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* echo:"); ImGui::Text(" - delay: %d",ch->echoDelay); ImGui::Text(" - feedback: %d",ch->echoFeedback); - ImGui::Text("- sampleMemLen: %lld",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %llu",ch->sampleMemLen); COMMON_CHIP_DEBUG_BOOL; break; } @@ -512,7 +512,7 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleMemLen: %lld",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %llu",ch->sampleMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; From 8d80c5f743876ccea4b5f5b0286f1595cab3b8bf Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 00:37:37 +0900 Subject: [PATCH 23/46] Actually compile fix --- src/gui/debug.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index e56828d65..5bccb6de0 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -90,8 +90,8 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- adpcmAMemLen: %llu",ch->adpcmAMemLen); \ - ImGui::Text("- adpcmBMemLen: %llu",ch->adpcmBMemLen); \ + ImGui::Text("- adpcmAMemLen: %lu",ch->adpcmAMemLen); \ + ImGui::Text("- adpcmBMemLen: %lu",ch->adpcmBMemLen); \ ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ @@ -335,7 +335,7 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- adpcmBMemLen: %llu",ch->adpcmBMemLen); + ImGui::Text("- adpcmBMemLen: %lu",ch->adpcmBMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); @@ -397,7 +397,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - Pos: %d",ch->dacPos); ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); - ImGui::Text("- dpcmMemLen: %llu",ch->dpcmMemLen); + ImGui::Text("- dpcmMemLen: %lu",ch->dpcmMemLen); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); @@ -504,7 +504,7 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* echo:"); ImGui::Text(" - delay: %d",ch->echoDelay); ImGui::Text(" - feedback: %d",ch->echoFeedback); - ImGui::Text("- sampleMemLen: %llu",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %lu",ch->sampleMemLen); COMMON_CHIP_DEBUG_BOOL; break; } @@ -512,7 +512,7 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleMemLen: %llu",ch->sampleMemLen); + ImGui::Text("- sampleMemLen: %lu",ch->sampleMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; From 8f0966378ff9f5accb8a8aad3c1425dd22e5d8f1 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 00:45:24 +0900 Subject: [PATCH 24/46] Remove these for fix compile --- src/gui/debug.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index 5bccb6de0..c769f2f39 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -90,8 +90,6 @@ #define OPNB_CHIP_DEBUG \ FM_OPN_CHIP_DEBUG; \ - ImGui::Text("- adpcmAMemLen: %lu",ch->adpcmAMemLen); \ - ImGui::Text("- adpcmBMemLen: %lu",ch->adpcmBMemLen); \ ImGui::Text("- sampleBank: %d",ch->sampleBank); \ ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \ ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \ @@ -335,7 +333,6 @@ void putDispatchChip(void* data, int type) { DivPlatformYM2608* ch=(DivPlatformYM2608*)data; ImGui::Text("> YM2608"); FM_OPN_CHIP_DEBUG; - ImGui::Text("- adpcmBMemLen: %lu",ch->adpcmBMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff); ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn); @@ -397,7 +394,6 @@ void putDispatchChip(void* data, int type) { ImGui::Text(" - Pos: %d",ch->dacPos); ImGui::Text(" - AntiClick: %d",ch->dacAntiClick); ImGui::Text(" - Sample: %d",ch->dacSample); - ImGui::Text("- dpcmMemLen: %lu",ch->dpcmMemLen); ImGui::Text("- dpcmBank: %d",ch->dpcmBank); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf); @@ -504,7 +500,6 @@ void putDispatchChip(void* data, int type) { ImGui::Text("* echo:"); ImGui::Text(" - delay: %d",ch->echoDelay); ImGui::Text(" - feedback: %d",ch->echoFeedback); - ImGui::Text("- sampleMemLen: %lu",ch->sampleMemLen); COMMON_CHIP_DEBUG_BOOL; break; } @@ -512,7 +507,6 @@ void putDispatchChip(void* data, int type) { DivPlatformX1_010* ch=(DivPlatformX1_010*)data; ImGui::Text("> X1-010"); COMMON_CHIP_DEBUG; - ImGui::Text("- sampleMemLen: %lu",ch->sampleMemLen); ImGui::Text("- sampleBank: %d",ch->sampleBank); ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]); COMMON_CHIP_DEBUG_BOOL; From ef9fedb0b8942a71954d0be06f31d87bc3d325a3 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 01:04:09 +0900 Subject: [PATCH 25/46] Fix Lynx clamping --- src/engine/platform/lynx.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index c67f35234..4db41bcfb 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -34,7 +34,7 @@ #define WRITE_STEREO(v) rWrite(0x50,(v)) #define CHIP_DIVIDER 64 -#define CHIP_FREQBASE 4000000 +#define CHIP_FREQBASE 16000000 #if defined( _MSC_VER ) @@ -141,10 +141,10 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len if (s!=NULL) { if (isMuted[i]) { WRITE_OUTPUT(i,0); - chan[i].samplePos++; } else { - WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos++]*chan[i].outVol)>>7,-128,127)); + WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos]*chan[i].outVol)>>7,-128,127)); } + chan[i].samplePos++; if (s->isLoopable() && chan[i].samplePos>=s->loopEnd) { chan[i].samplePos=s->loopStart; From 6b684d655a9926c7fff45bbcdc52b115b766cf09 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 12:37:03 -0500 Subject: [PATCH 26/46] fix build --- src/gui/debugWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 8033add4d..d3ecbc98e 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -72,7 +72,7 @@ void FurnaceGUI::drawDebug() { for (int i=0; isong.systemLen; i++) { void* ch=e->getDispatch(i); ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Chip %d: %s",i,getSystemName(e->song.system[i])); - if (e->song.system[i]==NULL) { + if (e->song.system[i]==DIV_SYSTEM_NULL) { ImGui::Text("NULL"); } else { putDispatchChip(ch,e->song.system[i]); From b9a4b568b69c47ad0622d81225b9fd176a5d30e2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 13:28:57 -0500 Subject: [PATCH 27/46] i honestly don't agree with this compat flag --- src/engine/fileOps.cpp | 2 -- src/engine/platform/opl.cpp | 6 ++---- src/engine/song.h | 2 -- src/gui/compatFlags.cpp | 4 ---- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 7eb148eae..2757ac274 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -179,7 +179,6 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.brokenPortaArp=false; ds.snNoLowPeriods=true; ds.ignorePCEDACVolume=true; - ds.newY8950PCMFreq=false; ds.delayBehavior=0; ds.jumpTreatment=2; @@ -1103,7 +1102,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.autoSystem=false; } ds.ignorePCEDACVolume=true; - ds.newY8950PCMFreq=false; ds.isDMF=false; reader.readS(); // reserved diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 148ce2799..d44d62712 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -28,8 +28,6 @@ #define KVSL(x,y) ((chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==2 && isOutputL[ops==4][chan[x].state.alg][y]) || chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==1) -#define OPLPCMDiv (parent->song.newY8950PCMFreq?((oplType==3)?288:72):144) - #define CHIP_FREQBASE chipFreqBase // N = invalid @@ -276,7 +274,7 @@ double DivPlatformOPL::NOTE_ADPCMB(int note) { if (adpcmChan<0) return 0; if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - return parent->calcBaseFreq((double)chipClock/OPLPCMDiv,off,note,false); + return parent->calcBaseFreq((double)chipClock/144,off,note,false); } return 0; } @@ -506,7 +504,7 @@ void DivPlatformOPL::tick(bool sysTick) { if (chan[adpcmChan].freqChanged || chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { if (chan[adpcmChan].sample>=0 && chan[adpcmChan].samplesong.sampleLen) { double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0; - chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/OPLPCMDiv,off); + chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/144,off); } else { chan[adpcmChan].freq=0; } diff --git a/src/engine/song.h b/src/engine/song.h index 9f5ca1544..28a31c759 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -512,7 +512,6 @@ struct DivSong { bool brokenPortaArp; bool snNoLowPeriods; bool ignorePCEDACVolume; - bool newY8950PCMFreq; bool autoSystem; std::vector ins; @@ -619,7 +618,6 @@ struct DivSong { brokenPortaArp(false), snNoLowPeriods(false), ignorePCEDACVolume(true), - newY8950PCMFreq(false), autoSystem(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index 80e9b0f57..c3627efad 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -147,10 +147,6 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("when enabled, PC Engine DAC Volume is ignored."); } - ImGui::Checkbox("New Y8950 Frequency calculation",&e->song.newY8950PCMFreq); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("when enabled, use corrected Y8950 frequency calculation"); - } ImGui::Text("Pitch linearity:"); if (ImGui::RadioButton("None",e->song.linearPitch==0)) { From 5e2cefff9422a021c728f82fe30364e72a507dbc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 13:36:23 -0500 Subject: [PATCH 28/46] dev117 - save the flag also serves as marker version for this huge change --- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 14 +++++++++++--- src/gui/compatFlags.cpp | 8 ++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 42d29f120..0438e09ce 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "0.6pre1.5" -#define DIV_ENGINE_VERSION 116 +#define DIV_VERSION "dev117" +#define DIV_ENGINE_VERSION 117 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 2757ac274..4f4c6539e 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1101,7 +1101,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<115) { ds.autoSystem=false; } - ds.ignorePCEDACVolume=true; + if (ds.version<117) { + ds.ignorePCEDACVolume=true; + } ds.isDMF=false; reader.readS(); // reserved @@ -1534,7 +1536,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<3; i++) { + if (ds.version>=117) { + ds.ignorePCEDACVolume=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<2; i++) { reader.readC(); } } @@ -3779,7 +3786,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.delayBehavior); w->writeC(song.jumpTreatment); w->writeC(song.autoSystem); - for (int i=0; i<3; i++) { + w->writeC(song.ignorePCEDACVolume); + for (int i=0; i<2; i++) { w->writeC(0); } diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index c3627efad..ac7209d63 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -143,10 +143,6 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("when enabled, any SN period under 8 will be written as 1 instead.\nthis replicates DefleMask behavior, but reduces available period range."); } - ImGui::Checkbox("Ignore PC Engine DAC Volume",&e->song.ignorePCEDACVolume); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("when enabled, PC Engine DAC Volume is ignored."); - } ImGui::Text("Pitch linearity:"); if (ImGui::RadioButton("None",e->song.linearPitch==0)) { @@ -285,6 +281,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("behavior changed in 0.6pre1.5"); } + ImGui::Checkbox("Ignore PC Engine DAC volume",&e->song.ignorePCEDACVolume); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("behavior changed in 0.6pre2"); + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS; ImGui::End(); From e6fc9e09d2cae998657c49d1b8783005d148d7fb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 19:01:01 -0500 Subject: [PATCH 29/46] latency fix --- src/engine/platform/ym2608.cpp | 91 ++++++++++++++--------------- src/engine/platform/ym2610.cpp | 92 +++++++++++++++--------------- src/engine/platform/ym2610b.cpp | 91 ++++++++++++++--------------- src/engine/platform/ym2610shared.h | 4 +- 4 files changed, 140 insertions(+), 138 deletions(-) diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index b27f81ea3..82a130ac0 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -358,14 +358,6 @@ void DivPlatformYM2608::acquire(short* bufL, short* bufR, size_t start, size_t l } void DivPlatformYM2608::tick(bool sysTick) { - // PSG - ay->tick(sysTick); - ay->flushWrites(); - for (DivRegWrite& i: ay->getRegisterWrites()) { - immWrite(i.addr&15,i.val); - } - ay->getRegisterWrites().clear(); - // FM for (int i=0; i<6; i++) { if (i==2 && extMode) continue; @@ -522,6 +514,44 @@ void DivPlatformYM2608::tick(bool sysTick) { chan[i].keyOff=false; } } + + for (int i=16; i<512; i++) { + if (pendingWrites[i]!=oldWrites[i]) { + immWrite(i,pendingWrites[i]&0xff); + oldWrites[i]=pendingWrites[i]; + } + } + + for (int i=0; i<6; i++) { + if (i==2 && extMode) continue; + if (chan[i].freqChanged) { + if (parent->song.linearPitch==2) { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); + } else { + int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2); + int block=(chan[i].baseFreq&0xf800)>>11; + if (fNum<0) fNum=0; + if (fNum>2047) { + while (block<7) { + fNum>>=1; + block++; + } + if (fNum>2047) fNum=2047; + } + chan[i].freq=(block<<11)|fNum; + } + if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; + immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); + immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); + chan[i].freqChanged=false; + } + if (chan[i].keyOn || chan[i].opMaskChanged) { + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; + chan[i].keyOn=false; + } + } + // RSS for (int i=9; i<15; i++) { if (chan[i].furnacePCM) { @@ -615,47 +645,18 @@ void DivPlatformYM2608::tick(bool sysTick) { writeRSSOff=0; } - for (int i=16; i<512; i++) { - if (pendingWrites[i]!=oldWrites[i]) { - immWrite(i,pendingWrites[i]&0xff); - oldWrites[i]=pendingWrites[i]; - } - } - - for (int i=0; i<6; i++) { - if (i==2 && extMode) continue; - if (chan[i].freqChanged) { - if (parent->song.linearPitch==2) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); - } else { - int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2); - int block=(chan[i].baseFreq&0xf800)>>11; - if (fNum<0) fNum=0; - if (fNum>2047) { - while (block<7) { - fNum>>=1; - block++; - } - if (fNum>2047) fNum=2047; - } - chan[i].freq=(block<<11)|fNum; - } - if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; - immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); - immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); - chan[i].freqChanged=false; - } - if (chan[i].keyOn || chan[i].opMaskChanged) { - immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); - chan[i].opMaskChanged=false; - chan[i].keyOn=false; - } - } - if (writeRSSOn) { immWrite(0x10,writeRSSOn); writeRSSOn=0; } + + // PSG + ay->tick(sysTick); + ay->flushWrites(); + for (DivRegWrite& i: ay->getRegisterWrites()) { + immWrite(i.addr&15,i.val); + } + ay->getRegisterWrites().clear(); } int DivPlatformYM2608::dispatch(DivCommand c) { diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index b8882304c..0adab3ba5 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -294,15 +294,7 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l } } -void DivPlatformYM2610::tick(bool sysTick) { - // PSG - ay->tick(sysTick); - ay->flushWrites(); - for (DivRegWrite& i: ay->getRegisterWrites()) { - immWrite(i.addr&15,i.val); - } - ay->getRegisterWrites().clear(); - +void DivPlatformYM2610::tick(bool sysTick) { // FM for (int i=0; isong.linearPitch==2) { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); + } else { + int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); + int block=(chan[i].baseFreq&0xf800)>>11; + if (fNum<0) fNum=0; + if (fNum>2047) { + while (block<7) { + fNum>>=1; + block++; + } + if (fNum>2047) fNum=2047; + } + chan[i].freq=(block<<11)|fNum; + } + if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; + immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); + immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); + chan[i].freqChanged=false; + } + if (chan[i].keyOn || chan[i].opMaskChanged) { + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; + chan[i].keyOn=false; + } + } + // ADPCM-A for (int i=adpcmAChanOffs; isong.linearPitch==2) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); - } else { - int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); - int block=(chan[i].baseFreq&0xf800)>>11; - if (fNum<0) fNum=0; - if (fNum>2047) { - while (block<7) { - fNum>>=1; - block++; - } - if (fNum>2047) fNum=2047; - } - chan[i].freq=(block<<11)|fNum; - } - if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; - immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); - immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); - chan[i].freqChanged=false; - } - if (chan[i].keyOn || chan[i].opMaskChanged) { - immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); - chan[i].opMaskChanged=false; - chan[i].keyOn=false; - } - } - if (writeADPCMAOn) { immWrite(0x100,writeADPCMAOn); writeADPCMAOn=0; } + + // PSG + ay->tick(sysTick); + ay->flushWrites(); + for (DivRegWrite& i: ay->getRegisterWrites()) { + immWrite(i.addr&15,i.val); + } + ay->getRegisterWrites().clear(); } int DivPlatformYM2610::dispatch(DivCommand c) { diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 9bcc45741..59913b147 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -358,14 +358,6 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t } void DivPlatformYM2610B::tick(bool sysTick) { - // PSG - ay->tick(sysTick); - ay->flushWrites(); - for (DivRegWrite& i: ay->getRegisterWrites()) { - immWrite(i.addr&15,i.val); - } - ay->getRegisterWrites().clear(); - // FM for (int i=0; isong.linearPitch==2) { + chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); + } else { + int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2); + int block=(chan[i].baseFreq&0xf800)>>11; + if (fNum<0) fNum=0; + if (fNum>2047) { + while (block<7) { + fNum>>=1; + block++; + } + if (fNum>2047) fNum=2047; + } + chan[i].freq=(block<<11)|fNum; + } + if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; + immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); + immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); + chan[i].freqChanged=false; + } + if (chan[i].keyOn || chan[i].opMaskChanged) { + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); + chan[i].opMaskChanged=false; + chan[i].keyOn=false; + } + } + // ADPCM-A for (int i=adpcmAChanOffs; isong.linearPitch==2) { - chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); - } else { - int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2); - int block=(chan[i].baseFreq&0xf800)>>11; - if (fNum<0) fNum=0; - if (fNum>2047) { - while (block<7) { - fNum>>=1; - block++; - } - if (fNum>2047) fNum=2047; - } - chan[i].freq=(block<<11)|fNum; - } - if (chan[i].freq>0x3fff) chan[i].freq=0x3fff; - immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); - immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); - chan[i].freqChanged=false; - } - if (chan[i].keyOn || chan[i].opMaskChanged) { - immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); - chan[i].opMaskChanged=false; - chan[i].keyOn=false; - } - } - if (writeADPCMAOn) { immWrite(0x100,writeADPCMAOn); writeADPCMAOn=0; } + + // PSG + ay->tick(sysTick); + ay->flushWrites(); + for (DivRegWrite& i: ay->getRegisterWrites()) { + immWrite(i.addr&15,i.val); + } + ay->getRegisterWrites().clear(); } int DivPlatformYM2610B::dispatch(DivCommand c) { diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h index 6c06eb068..e8bbd16f9 100644 --- a/src/engine/platform/ym2610shared.h +++ b/src/engine/platform/ym2610shared.h @@ -265,7 +265,7 @@ template class DivPlatformYM2610Base: public DivPlatformOPN { chipClock=24167829/3; break; } - rate=fm->sample_rate(chipClock); + rate=chipClock/16; for (int i=0; irate=rate; } @@ -287,7 +287,7 @@ template class DivPlatformYM2610Base: public DivPlatformOPN { iface.adpcmBMem=adpcmBMem; iface.sampleBank=0; fm=new ymfm::ym2610b(iface); - fm->set_fidelity(ymfm::OPN_FIDELITY_MIN); + fm->set_fidelity(ymfm::OPN_FIDELITY_MAX); setFlags(flags); // YM2149, 2MHz ay=new DivPlatformAY8910(true,chipClock,32); From eb8849ce631ccb99a4bc35d8cc378f6520e04ada Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 19:18:32 -0500 Subject: [PATCH 30/46] add disableSampleMacro flag for compatibility --- src/engine/fileOps.cpp | 8 ++++---- src/engine/platform/ay.cpp | 4 ++-- src/engine/platform/msm6295.cpp | 1 + src/engine/platform/pce.cpp | 10 +++++----- src/engine/song.h | 4 ++-- src/gui/compatFlags.cpp | 2 +- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 4f4c6539e..47a837899 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -178,7 +178,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.e1e2StopOnSameNote=true; ds.brokenPortaArp=false; ds.snNoLowPeriods=true; - ds.ignorePCEDACVolume=true; + ds.disableSampleMacro=true; ds.delayBehavior=0; ds.jumpTreatment=2; @@ -1102,7 +1102,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.autoSystem=false; } if (ds.version<117) { - ds.ignorePCEDACVolume=true; + ds.disableSampleMacro=true; } ds.isDMF=false; @@ -1537,7 +1537,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { reader.readC(); } if (ds.version>=117) { - ds.ignorePCEDACVolume=reader.readC(); + ds.disableSampleMacro=reader.readC(); } else { reader.readC(); } @@ -3786,7 +3786,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.delayBehavior); w->writeC(song.jumpTreatment); w->writeC(song.autoSystem); - w->writeC(song.ignorePCEDACVolume); + w->writeC(song.disableSampleMacro); for (int i=0; i<2; i++) { w->writeC(0); } diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 5ce075ce0..ad2bbc650 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -348,14 +348,14 @@ int DivPlatformAY8910::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY); - if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) { chan[c.chan].psgMode.dac=true; } else if (chan[c.chan].dac.furnaceDAC) { chan[c.chan].psgMode.dac=false; } if (chan[c.chan].psgMode.dac) { if (skipRegisterWrites) break; - if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) { + if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) { chan[c.chan].dac.sample=ins->amiga.getSample(c.value); if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) { chan[c.chan].dac.sample=-1; diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 5cfec125a..b85bc1a58 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -88,6 +88,7 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t } void DivPlatformMSM6295::tick(bool sysTick) { + if (parent->song.disableSampleMacro) return; for (int i=0; i<4; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 74667c870..19b71a1be 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -69,7 +69,7 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) signed char dacData=((signed char)((unsigned char)s->data8[chan[i].dacPos]^0x80))>>3; chan[i].dacOut=CLAMP(dacData,-16,15); if (!isMuted[i]) { - chWrite(i,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[i].outVol)); + chWrite(i,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].outVol)); chWrite(i,0x06,chan[i].dacOut&0x1f); } else { chWrite(i,0x04,0xc0); @@ -208,7 +208,7 @@ void DivPlatformPCE::tick(bool sysTick) { if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSamplesong.sampleLen) { chan[i].dacPos=0; chan[i].dacPeriod=0; - chWrite(i,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[i].vol)); + chWrite(i,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].vol)); addWrite(0xffff0000+(i<<8),chan[i].dacSample); chan[i].keyOn=true; } @@ -275,7 +275,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; } else { if (dumpWrites) { - chWrite(c.chan,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[c.chan].vol)); + chWrite(c.chan,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol)); addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample); } } @@ -310,7 +310,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].dacPeriod=0; chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate; if (dumpWrites) { - chWrite(c.chan,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[c.chan].vol)); + chWrite(c.chan,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol)); addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate); } } @@ -466,7 +466,7 @@ void DivPlatformPCE::muteChannel(int ch, bool mute) { isMuted[ch]=mute; chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan); if (!isMuted[ch] && (chan[ch].pcm && chan[ch].dacSample!=-1)) { - chWrite(ch,0x04,parent->song.ignorePCEDACVolume?0xdf:(0xc0|chan[ch].outVol)); + chWrite(ch,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[ch].outVol)); chWrite(ch,0x06,chan[ch].dacOut&0x1f); } } diff --git a/src/engine/song.h b/src/engine/song.h index 28a31c759..a9a16263a 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -511,7 +511,7 @@ struct DivSong { bool e1e2StopOnSameNote; bool brokenPortaArp; bool snNoLowPeriods; - bool ignorePCEDACVolume; + bool disableSampleMacro; bool autoSystem; std::vector ins; @@ -617,7 +617,7 @@ struct DivSong { e1e2StopOnSameNote(false), brokenPortaArp(false), snNoLowPeriods(false), - ignorePCEDACVolume(true), + disableSampleMacro(true), autoSystem(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index ac7209d63..fcea0fa06 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -281,7 +281,7 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("behavior changed in 0.6pre1.5"); } - ImGui::Checkbox("Ignore PC Engine DAC volume",&e->song.ignorePCEDACVolume); + ImGui::Checkbox("Disable new sample features",&e->song.disableSampleMacro); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("behavior changed in 0.6pre2"); } From f620782919c3b95e15db37bef565fdc9f75e8e0b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 09:27:33 +0900 Subject: [PATCH 31/46] Fix playback issue --- src/engine/platform/msm6295.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index b85bc1a58..925fefed7 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -88,21 +88,22 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t } void DivPlatformMSM6295::tick(bool sysTick) { - if (parent->song.disableSampleMacro) return; for (int i=0; i<4; i++) { - chan[i].std.next(); - if (chan[i].std.vol.had) { - chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,8); - } - if (chan[i].std.duty.had) { - if (rateSel!=(chan[i].std.duty.val&1)) { - rateSel=chan[i].std.duty.val&1; - rWrite(12,!rateSel); + if (parent->song.disableSampleMacro) { + chan[i].std.next(); + if (chan[i].std.vol.had) { + chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,8); } - } - if (chan[i].std.phaseReset.had) { - if (chan[i].std.phaseReset.val && chan[i].active) { - chan[i].keyOn=true; + if (chan[i].std.duty.had) { + if (rateSel!=(chan[i].std.duty.val&1)) { + rateSel=chan[i].std.duty.val&1; + rWrite(12,!rateSel); + } + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active) { + chan[i].keyOn=true; + } } } if (chan[i].keyOn || chan[i].keyOff) { From 4bf46f9315836eeafccb869f790ec09ad7b7d482 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 09:27:46 +0900 Subject: [PATCH 32/46] Oops --- src/engine/platform/msm6295.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 925fefed7..a898ba150 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -89,7 +89,7 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t void DivPlatformMSM6295::tick(bool sysTick) { for (int i=0; i<4; i++) { - if (parent->song.disableSampleMacro) { + if (!parent->song.disableSampleMacro) { chan[i].std.next(); if (chan[i].std.vol.had) { chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,8); From a5fb9b766e8d51dbdf55926c58ad6cef138075bb Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 09:28:30 +0900 Subject: [PATCH 33/46] disableSampleMacro for MSM6258 --- src/engine/platform/msm6258.cpp | 40 +++++++++++++++++---------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index 119366186..ded3899ef 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -91,28 +91,30 @@ void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t void DivPlatformMSM6258::tick(bool sysTick) { for (int i=0; i<1; i++) { - chan[i].std.next(); - if (chan[i].std.duty.had) { - if (rateSel!=(chan[i].std.duty.val&3)) { - rateSel=chan[i].std.duty.val&3; - rWrite(12,rateSel); + if (!parent->song.disableSampleMacro) { + chan[i].std.next(); + if (chan[i].std.duty.had) { + if (rateSel!=(chan[i].std.duty.val&3)) { + rateSel=chan[i].std.duty.val&3; + rWrite(12,rateSel); + } } - } - if (chan[i].std.panL.had) { - if (chan[i].pan!=(chan[i].std.panL.val&3)) { - chan[i].pan=chan[i].std.panL.val&3; - rWrite(2,chan[i].pan); + if (chan[i].std.panL.had) { + if (chan[i].pan!=(chan[i].std.panL.val&3)) { + chan[i].pan=chan[i].std.panL.val&3; + rWrite(2,chan[i].pan); + } } - } - if (chan[i].std.ex1.had) { - if (clockSel!=(chan[i].std.ex1.val&1)) { - clockSel=chan[i].std.ex1.val&1; - rWrite(8,clockSel); + if (chan[i].std.ex1.had) { + if (clockSel!=(chan[i].std.ex1.val&1)) { + clockSel=chan[i].std.ex1.val&1; + rWrite(8,clockSel); + } } - } - if (chan[i].std.phaseReset.had) { - if (chan[i].std.phaseReset.val && chan[i].active) { - chan[i].keyOn=true; + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val && chan[i].active) { + chan[i].keyOn=true; + } } } if (chan[i].keyOn || chan[i].keyOff) { From bc4c8acd87fcc69814d14ec90e05205870612c4e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 19:34:44 -0500 Subject: [PATCH 34/46] AY PCM still doesn't work so I am leaving a note --- src/engine/platform/ay.cpp | 13 +++++++------ src/engine/platform/ay8930.cpp | 7 ++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index ad2bbc650..851ef46b4 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -89,26 +89,27 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l ayBuf[i]=new short[ayBufLen]; } } + // TODO: try to fit this into the actual loop // PCM part for (int i=0; i<3; i++) { if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { chan[i].dac.period+=chan[i].dac.rate; bool end=false; bool changed=false; - int prev_out = chan[i].dac.out; + int prevOut=chan[i].dac.out; while (chan[i].dac.period>rate && !end) { DivSample* s=parent->getSample(chan[i].dac.sample); if (s->samples<=0) { chan[i].dac.sample=-1; - rWrite(0x08+i,0); + immWrite(0x08+i,0); end=true; break; } // Partially unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>4); chan[i].dac.out=MAX(0,MIN(15,(dacData*chan[i].outVol)/15)); - if (prev_out!=chan[i].dac.out) { - prev_out=chan[i].dac.out; + if (prevOut!=chan[i].dac.out) { + prevOut=chan[i].dac.out; changed=true; } chan[i].dac.pos++; @@ -116,7 +117,7 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l chan[i].dac.pos=s->loopStart; } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; - rWrite(0x08+i,0); + immWrite(0x08+i,0); end=true; break; } @@ -124,7 +125,7 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l } if (changed && !end) { if (!isMuted[i]) { - rWrite(0x08+i,chan[i].dac.out); + immWrite(0x08+i,chan[i].dac.out); } } } diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 913be11b0..fbc9b3275 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -85,6 +85,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l ayBuf[i]=new short[ayBufLen]; } } + // TODO: try to fit this into the actual loop // PCM part for (int i=0; i<3; i++) { if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { @@ -96,7 +97,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l DivSample* s=parent->getSample(chan[i].dac.sample); if (s->samples<=0) { chan[i].dac.sample=-1; - rWrite(0x08+i,0); + immWrite(0x08+i,0); end=true; break; } @@ -112,7 +113,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l chan[i].dac.pos=s->loopStart; } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; - rWrite(0x08+i,0); + immWrite(0x08+i,0); end=true; break; } @@ -120,7 +121,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l } if (changed && !end) { if (!isMuted[i]) { - rWrite(0x08+i,chan[i].dac.out); + immWrite(0x08+i,chan[i].dac.out); } } } From b72b5bf0e6d6357da305cd39142d09cda2f04bc9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 20:15:20 -0500 Subject: [PATCH 35/46] A Y P C M --- src/engine/platform/ay.cpp | 92 +++++++++++++++++++++++---------- src/engine/platform/ay.h | 2 + src/engine/platform/ay8930.cpp | 94 +++++++++++++++++++++++----------- src/engine/platform/ay8930.h | 2 + 4 files changed, 133 insertions(+), 57 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 851ef46b4..9526e591d 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -81,16 +81,39 @@ const char** DivPlatformAY8910::getRegisterSheet() { return intellivision?regCheatSheetAY8914:regCheatSheetAY; } -void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t len) { - if (ayBufLen +#include + +int main(int argc, char** argv) { + for (int i=0; i<256; i++) { + if ((i&15)==0) printf("\n "); + printf(" %d,",(int)round(pow((double)i/255.0,0.36)*15.0)); } - // TODO: try to fit this into the actual loop - // PCM part +} +*/ + +const unsigned char dacLogTableAY[256]={ + 0, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 +}; + +void DivPlatformAY8910::runDAC() { for (int i=0; i<3; i++) { if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { chan[i].dac.period+=chan[i].dac.rate; @@ -105,9 +128,8 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l end=true; break; } - // Partially - unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>4); - chan[i].dac.out=MAX(0,MIN(15,(dacData*chan[i].outVol)/15)); + unsigned char dacData=dacLogTableAY[(unsigned char)s->data8[chan[i].dac.pos]^0x80]; + chan[i].dac.out=MAX(0,dacData-(15-chan[i].outVol)); if (prevOut!=chan[i].dac.out) { prevOut=chan[i].dac.out; changed=true; @@ -130,7 +152,9 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l } } } +} +void DivPlatformAY8910::checkWrites() { while (!writes.empty()) { QueuedWrite w=writes.front(); if (intellivision) { @@ -143,8 +167,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l regPool[w.addr&0x0f]=w.val; writes.pop(); } +} + +void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t len) { + if (ayBufLensound_stream_update(ayBuf,1); bufL[i+start]=ayBuf[0][0]; bufR[i+start]=bufL[i+start]; @@ -154,22 +192,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l oscBuf[2]->data[oscBuf[2]->needle++]=sunsoftVolTable[31-((ay->lastIndx>>10)&31)]>>3; } } else { - ay->sound_stream_update(ayBuf,len); - if (stereo) { - for (size_t i=0; i>8); - bufR[i+start]=((ayBuf[0][i]*stereoSep)>>8)+ayBuf[1][i]+ayBuf[2][i]; - } - } else { - for (size_t i=0; isound_stream_update(ayBuf,1); + if (stereo) { + bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+((ayBuf[2][0]*stereoSep)>>8); + bufR[i+start]=((ayBuf[0][0]*stereoSep)>>8)+ayBuf[1][0]+ayBuf[2][0]; + } else { + bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+ayBuf[2][0]; bufR[i+start]=bufL[i+start]; } - } - for (int ch=0; ch<3; ch++) { - for (size_t i=0; idata[oscBuf[ch]->needle++]=ayBuf[ch][i]<<2; - } + + oscBuf[0]->data[oscBuf[0]->needle++]=ayBuf[0][0]<<2; + oscBuf[1]->data[oscBuf[1]->needle++]=ayBuf[1][0]<<2; + oscBuf[2]->data[oscBuf[2]->needle++]=ayBuf[2][0]<<2; } } } @@ -291,7 +329,7 @@ void DivPlatformAY8910::tick(bool sysTick) { off=8363.0/(double)s->centerRate; } } - chan[i].dac.rate=((double)chipClock*4096.0)/(double)(MAX(1,off*chan[i].freq)); + chan[i].dac.rate=((double)rate*16.0)/(double)(MAX(1,off*chan[i].freq)); if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate); } if (chan[i].freq>4095) chan[i].freq=4095; diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index 4f77281de..ec9a14fe5 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -145,6 +145,8 @@ class DivPlatformAY8910: public DivDispatch { short* ayBuf[3]; size_t ayBufLen; + void runDAC(); + void checkWrites(); void updateOutSel(bool immediate=false); friend void putDispatchChip(void*,int); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index fbc9b3275..b6c59452f 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -77,22 +77,45 @@ const char** DivPlatformAY8930::getRegisterSheet() { return regCheatSheetAY8930; } -void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t len) { - if (ayBufLen +#include + +int main(int argc, char** argv) { + for (int i=0; i<256; i++) { + if ((i&15)==0) printf("\n "); + printf(" %d,",(int)round(pow((double)i/255.0,0.3)*31.0)); } - // TODO: try to fit this into the actual loop - // PCM part - for (int i=0; i<3; i++) { +} +*/ + +const unsigned char dacLogTableAY8930[256]={ + 0, 6, 7, 8, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 +}; + +void DivPlatformAY8930::runDAC() { + for (int i=0; i<3; i++) { if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) { chan[i].dac.period+=chan[i].dac.rate; bool end=false; bool changed=false; - int prev_out = chan[i].dac.out; + int prevOut=chan[i].dac.out; while (chan[i].dac.period>rate && !end) { DivSample* s=parent->getSample(chan[i].dac.sample); if (s->samples<=0) { @@ -101,11 +124,10 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l end=true; break; } - // Partially - unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>3); - chan[i].dac.out=MAX(0,MIN(31,(dacData*chan[i].outVol)/31)); - if (prev_out!=chan[i].dac.out) { - prev_out=chan[i].dac.out; + unsigned char dacData=dacLogTableAY8930[(unsigned char)s->data8[chan[i].dac.pos]^0x80]; + chan[i].dac.out=MAX(0,dacData-(31-chan[i].outVol)); + if (prevOut!=chan[i].dac.out) { + prevOut=chan[i].dac.out; changed=true; } chan[i].dac.pos++; @@ -126,7 +148,9 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l } } } +} +void DivPlatformAY8930::checkWrites() { while (!writes.empty()) { QueuedWrite w=writes.front(); ay->address_w(w.addr); @@ -138,23 +162,33 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l } writes.pop(); } - ay->sound_stream_update(ayBuf,len); - if (stereo) { - for (size_t i=0; i>8); - bufR[i+start]=((ayBuf[0][i]*stereoSep)>>8)+ayBuf[1][i]+ayBuf[2][i]; - } - } else { - for (size_t i=0; idata[oscBuf[ch]->needle++]=ayBuf[ch][i]<<2; + for (size_t i=0; isound_stream_update(ayBuf,1); + if (stereo) { + bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+((ayBuf[2][0]*stereoSep)>>8); + bufR[i+start]=((ayBuf[0][0]*stereoSep)>>8)+ayBuf[1][0]+ayBuf[2][0]; + } else { + bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+ayBuf[2][0]; + bufR[i+start]=bufL[i+start]; } + + oscBuf[0]->data[oscBuf[0]->needle++]=ayBuf[0][0]<<2; + oscBuf[1]->data[oscBuf[1]->needle++]=ayBuf[1][0]<<2; + oscBuf[2]->data[oscBuf[2]->needle++]=ayBuf[2][0]<<2; } } @@ -294,7 +328,7 @@ void DivPlatformAY8930::tick(bool sysTick) { off=8363.0/(double)s->centerRate; } } - chan[i].dac.rate=((double)chipClock*16384.0)/(double)(MAX(1,off*chan[i].freq)); + chan[i].dac.rate=((double)chipClock*4.0)/(double)(MAX(1,off*chan[i].freq)); if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate); } if (chan[i].freq>65535) chan[i].freq=65535; diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index c1a50e7a5..441e82148 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -148,6 +148,8 @@ class DivPlatformAY8930: public DivDispatch { short* ayBuf[3]; size_t ayBufLen; + void runDAC(); + void checkWrites(); void updateOutSel(bool immediate=false); void immWrite(unsigned char a, unsigned char v); From 593aeeb2437deab7ce618f79284400ce3b716e5f Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 24 Sep 2022 10:20:09 +0900 Subject: [PATCH 36/46] Unnecessary space --- src/engine/platform/genesisext.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index 352ebc293..ffc83d46c 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -51,7 +51,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { pan(3) {} }; OpChannel opChan[4]; - bool isOpMuted[4]; + bool isOpMuted[4]; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); public: From 95562afb166c4d635f668490203b644fd1b6a94d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 22:45:47 -0500 Subject: [PATCH 37/46] one more compatibility fix --- src/engine/platform/ym2610.cpp | 2 +- src/engine/platform/ym2610b.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 0adab3ba5..9e8f1847c 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -680,7 +680,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { if (c.chan>=adpcmAChanOffs) { // ADPCM-A DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { + if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA)) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 59913b147..bf854f36f 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -743,7 +743,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { if (c.chan>=adpcmAChanOffs) { // ADPCM-A DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31; - if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) { + if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA)) { chan[c.chan].furnacePCM=true; } else { chan[c.chan].furnacePCM=false; From e8ca6bd4837ac418c7652a8590c32bac51c4882e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 22:48:55 -0500 Subject: [PATCH 38/46] one more fix --- src/engine/platform/qsound.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 18216f03f..4f7d2545f 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -308,14 +308,14 @@ void DivPlatformQSound::tick(bool sysTick) { } chan[i].freqChanged=true; } - if (chan[i].std.duty.had) { + if (chan[i].isNewQSound && chan[i].std.duty.had) { chan[i].echo=CLAMP(chan[i].std.duty.val,0,32767); immWrite(Q1_ECHO+i,chan[i].echo&0x7fff); } - if (chan[i].std.ex1.had) { + if (chan[i].isNewQSound && chan[i].std.ex1.had) { immWrite(Q1_ECHO_FEEDBACK,chan[i].std.ex1.val&0x3fff); } - if (chan[i].std.ex2.had) { + if (chan[i].isNewQSound && chan[i].std.ex2.had) { immWrite(Q1_ECHO_LENGTH,0xfff-(2725-CLAMP(chan[i].std.ex2.val&0xfff,0,2725))); } if (chan[i].std.pitch.had) { From 67fc945992f3d7c7f3cc9a540278cee71b865d83 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 23:03:07 -0500 Subject: [PATCH 39/46] Y8950 regression fix --- src/engine/platform/opl.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index d44d62712..5d81f0834 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -508,6 +508,14 @@ void DivPlatformOPL::tick(bool sysTick) { } else { chan[adpcmChan].freq=0; } + if (chan[adpcmChan].fixedFreq>0) chan[adpcmChan].freq=chan[adpcmChan].fixedFreq; + if (pretendYMU) { // YMU759 only does 4KHz or 8KHz + if (chan[adpcmChan].freq>7500) { + chan[adpcmChan].freq=10922; // 8KHz + } else { + chan[adpcmChan].freq=5461; // 4KHz + } + } immWrite(16,chan[adpcmChan].freq&0xff); immWrite(17,(chan[adpcmChan].freq>>8)&0xff); if (chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) { @@ -673,6 +681,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (skipRegisterWrites) break; if (chan[c.chan].furnacePCM) { chan[c.chan].macroInit(ins); + chan[c.chan].fixedFreq=0; if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; immWrite(18,chan[c.chan].outVol); @@ -718,6 +727,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { immWrite(11,(end>>2)&0xff); immWrite(12,(end>>10)&0xff); int freq=(65536.0*(double)s->rate)/(double)chipRateBase; + chan[c.chan].fixedFreq=freq; immWrite(16,freq&0xff); immWrite(17,(freq>>8)&0xff); chan[c.chan].active=true; From 70825dc45a872d0bea78d9c645a9bbfcdf4e339e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 23:12:39 -0500 Subject: [PATCH 40/46] AY: reduce PCM clicking --- src/engine/platform/ay.cpp | 2 +- src/engine/platform/ay8930.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 9526e591d..5d9823715 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -139,7 +139,7 @@ void DivPlatformAY8910::runDAC() { chan[i].dac.pos=s->loopStart; } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; - immWrite(0x08+i,0); + //immWrite(0x08+i,0); end=true; break; } diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index b6c59452f..a1182a809 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -135,7 +135,7 @@ void DivPlatformAY8930::runDAC() { chan[i].dac.pos=s->loopStart; } else if (chan[i].dac.pos>=(int)s->samples) { chan[i].dac.sample=-1; - immWrite(0x08+i,0); + //immWrite(0x08+i,0); end=true; break; } From 3992a1c677e49fb0d0e9a04338c5e8c1d422c166 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 23 Sep 2022 23:29:19 -0500 Subject: [PATCH 41/46] AY: clockSel PCM fix --- src/engine/platform/ay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 5d9823715..9f4e0dc28 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -329,7 +329,7 @@ void DivPlatformAY8910::tick(bool sysTick) { off=8363.0/(double)s->centerRate; } } - chan[i].dac.rate=((double)rate*16.0)/(double)(MAX(1,off*chan[i].freq)); + chan[i].dac.rate=((double)rate*((sunsoft||clockSel)?8.0:16.0))/(double)(MAX(1,off*chan[i].freq)); if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate); } if (chan[i].freq>4095) chan[i].freq=4095; From 5dfa089c4928c6b47c791004d2c642f46a831f52 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 00:57:53 -0500 Subject: [PATCH 42/46] GUI: some UI corrections and prepare for OPM/NES split --- src/gui/guiConst.cpp | 16 +++---- src/gui/insEdit.cpp | 101 ++++++++++++++++++++++--------------------- 2 files changed, 60 insertions(+), 57 deletions(-) diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 1ce78b5fa..16261e2a4 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -790,14 +790,14 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,1.0f)), D(GUI_COLOR_INSTR_OPM,"",ImVec4(0.2f,0.6f,1.0f,1.0f)), D(GUI_COLOR_INSTR_NES,"",ImVec4(0.4f,1.0f,0.3f,1.0f)), - D(GUI_COLOR_INSTR_MSM6258,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_MSM6295,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_ADPCMA,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_ADPCMB,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_SEGAPCM,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_QSOUND,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_YMZ280B,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), - D(GUI_COLOR_INSTR_RF5C68,"",ImVec4(1.0f,0.5f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_MSM6258,"",ImVec4(1.0f,0.5f,0.7f,1.0f)), + D(GUI_COLOR_INSTR_MSM6295,"",ImVec4(1.0f,0.6f,0.9f,1.0f)), + D(GUI_COLOR_INSTR_ADPCMA,"",ImVec4(1.0f,1.0f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_ADPCMB,"",ImVec4(1.0f,0.75f,0.5f,1.0f)), + D(GUI_COLOR_INSTR_SEGAPCM,"",ImVec4(1.0f,0.9f,0.6f,1.0f)), + D(GUI_COLOR_INSTR_QSOUND,"",ImVec4(1.0f,0.8f,0.3f,1.0f)), + D(GUI_COLOR_INSTR_YMZ280B,"",ImVec4(0.4f,0.5f,1.0f,1.0f)), + D(GUI_COLOR_INSTR_RF5C68,"",ImVec4(1.0f,0.3f,0.3f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 9d61fff6b..97be4a713 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1786,12 +1786,12 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::BeginTabBar("insEditTab")) { std::vector macroList; - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL_DRUMS) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPM) { char label[32]; int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; - bool opsAreMutable=(ins->type==DIV_INS_FM); + bool opsAreMutable=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM); if (ImGui::BeginTabItem("FM")) { if (ImGui::BeginTable("fmDetails",3,ImGuiTableFlags_SizingStretchSame)) { @@ -1801,6 +1801,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextRow(); switch (ins->type) { case DIV_INS_FM: + case DIV_INS_OPM: ImGui::TableNextColumn(); P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_FMS),ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN)); rightClickable @@ -1995,7 +1996,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.05f); // ar ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.05f); // dr ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.05f); // sl - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.05f); // d2r } ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthStretch,0.05f); // rr @@ -2012,7 +2013,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableSetupColumn("c9z",ImGuiTableColumnFlags_WidthStretch,0.05f); // fine } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableSetupColumn("c10",ImGuiTableColumnFlags_WidthStretch,0.05f); // dt ImGui::TableSetupColumn("c11",ImGuiTableColumnFlags_WidthStretch,0.05f); // dt2 } @@ -2039,7 +2040,7 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT(FM_SHORT_NAME(FM_SL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_SL)); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableNextColumn(); CENTER_TEXT(FM_SHORT_NAME(FM_D2R)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_D2R)); @@ -2057,7 +2058,7 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT(FM_SHORT_NAME(FM_TL)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_TL)); ImGui::TableNextColumn(); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_RS)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_RS)); } else { @@ -2081,7 +2082,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TextUnformatted(FM_SHORT_NAME(FM_FINE)); } ImGui::TableNextColumn(); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_DT)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_DT)); ImGui::TableNextColumn(); @@ -2089,7 +2090,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TextUnformatted(FM_SHORT_NAME(FM_DT2)); ImGui::TableNextColumn(); } - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_AM)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AM)); } else { @@ -2188,7 +2189,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } - int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; + int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; bool ssgOn=op.ssgEnv&8; bool ksrOn=op.ksr; bool vibOn=op.vib; @@ -2212,7 +2213,7 @@ void FurnaceGUI::drawInsEdit() { P(CWVSliderScalar("##SL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableNextColumn(); op.d2r&=31; CENTER_VSLIDER; @@ -2241,7 +2242,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); CENTER_VSLIDER; - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { P(CWVSliderScalar("##RS",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); } else { P(CWVSliderScalar("##KSL",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); @@ -2267,7 +2268,7 @@ void FurnaceGUI::drawInsEdit() { P(CWVSliderScalar("##FINE",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { int detune=(op.dt&7)-(settings.unsignedDetune?0:3); ImGui::TableNextColumn(); CENTER_VSLIDER; @@ -2275,12 +2276,10 @@ void FurnaceGUI::drawInsEdit() { op.dt=detune+(settings.unsignedDetune?0:3); } + // TODO: separate OPN/OPM ImGui::TableNextColumn(); CENTER_VSLIDER; P(CWVSliderScalar("##DT2",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable - if (ImGui::IsItemHovered() && ins->type==DIV_INS_FM) { - ImGui::SetTooltip("Only on YM2151 (OPM)"); - } ImGui::TableNextColumn(); bool amOn=op.am; @@ -2329,11 +2328,6 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } - if (ins->type==DIV_INS_FM) { - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only for OPN family chips"); - } - } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -2489,7 +2483,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } - int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; + int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; bool ssgOn=op.ssgEnv&8; bool ksrOn=op.ksr; @@ -2511,7 +2505,7 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT_20(FM_SHORT_NAME(FM_AR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR)); ImGui::TableNextColumn(); - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { ImGui::Text("SSG-EG"); } else { ImGui::Text("Waveform"); @@ -2542,7 +2536,7 @@ void FurnaceGUI::drawInsEdit() { } float textX_D2R=0.0f; - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::SameLine(); op.d2r&=31; textX_D2R=ImGui::GetCursorPosX(); @@ -2576,7 +2570,7 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT_20(FM_SHORT_NAME(FM_RR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_RR)); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::SetCursorPos(ImVec2(textX_D2R,textY)); CENTER_TEXT_20(FM_SHORT_NAME(FM_D2R)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_D2R)); @@ -2586,7 +2580,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); switch (ins->type) { - case DIV_INS_FM: { + case DIV_INS_FM: + case DIV_INS_OPM: { // SSG ImGui::BeginDisabled(!ssgOn); drawSSGEnv(op.ssgEnv&7,ImVec2(waveWidth,waveHeight)); @@ -2827,9 +2822,9 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); op.tl&=maxTl; - P(CWVSliderScalar("##TL",ImVec2(ImGui::GetFrameHeight(),sliderHeight-(ins->type==DIV_INS_FM?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); + P(CWVSliderScalar("##TL",ImVec2(ImGui::GetFrameHeight(),sliderHeight-((ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM)?(ImGui::GetFrameHeightWithSpacing()+ImGui::CalcTextSize(FM_SHORT_NAME(FM_AM)).y+ImGui::GetStyle().ItemSpacing.y):0.0f)),ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_AM)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AM)); bool amOn=op.am; @@ -2947,7 +2942,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } - int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; + int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; bool ssgOn=op.ssgEnv&8; bool ksrOn=op.ksr; @@ -2959,7 +2954,7 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Only for OPN family chips"); } @@ -3013,7 +3008,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("%s",FM_NAME(FM_SL)); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -3055,7 +3050,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_RS)); @@ -3132,7 +3127,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("%s",FM_NAME(FM_MULT)); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { if (!(ins->type==DIV_INS_OPZ && op.egt)) { int detune=(op.dt&7)-(settings.unsignedDetune?0:3); ImGui::TableNextRow(); @@ -3149,13 +3144,10 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable - if (ImGui::IsItemHovered() && ins->type==DIV_INS_FM) { - ImGui::SetTooltip("Only on YM2151 (OPM)"); - } ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_DT2)); - if (ins->type==DIV_INS_FM) { // OPN only + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { // OPN only ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -3225,13 +3217,13 @@ void FurnaceGUI::drawInsEdit() { } } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc("AM Depth",&ins->std.ex1Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("PM Depth",&ins->std.ex2Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO Speed",&ins->std.ex3Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO Shape",&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroLFOWaves)); } - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc("OpMask",&ins->std.ex4Macro,0,4,128,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,fmOperatorBits)); } else if (ins->type==DIV_INS_OPZ) { macroList.push_back(FurnaceGUIMacroDesc("AM Depth 2",&ins->std.ex5Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3263,7 +3255,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } - int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; + int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM)?31:15; if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3305,7 +3297,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT2),&ins->std.opMacros[ordi].dt2Macro,0,3,32,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,NULL,NULL,true)); - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { 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)); } } @@ -4271,7 +4263,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_AMIGA) { volMax=64; } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_SEGAPCM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_SEGAPCM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { volMax=127; } if (ins->type==DIV_INS_GB) { @@ -4318,13 +4310,13 @@ void FurnaceGUI::drawInsEdit() { dutyMax=96; } } - if (ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { dutyMax=32; } if (ins->type==DIV_INS_AY) { dutyMax=ins->amiga.useSample?0:31; } - if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_FM) { + if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { dutyLabel="Noise Freq"; } if (ins->type==DIV_INS_MIKEY) { @@ -4338,18 +4330,20 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_AY8930) { dutyMax=ins->amiga.useSample?0:255; } - if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM) { + if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || + ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM) { dutyMax=0; } - if ((ins->type==DIV_INS_PCE && !ins->amiga.useSample) || ins->type==DIV_INS_NAMCO) { + if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_NAMCO) { dutyLabel="Noise"; - dutyMax=(ins->type==DIV_INS_PCE && !ins->amiga.useSample)?0:1; + dutyMax=(ins->type==DIV_INS_PCE && !ins->amiga.useSample)?1:0; } if (ins->type==DIV_INS_SWAN) { dutyLabel="Noise"; dutyMax=ins->amiga.useSample?0:8; } - if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) { + if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || + ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) { dutyMax=0; } if (ins->type==DIV_INS_VERA) { @@ -4401,9 +4395,16 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_VIC || ins->type==DIV_INS_OPLL) waveMax=15; if (ins->type==DIV_INS_C64) waveMax=4; if (ins->type==DIV_INS_SAA1099) waveMax=2; - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ) waveMax=0; + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) waveMax=0; if (ins->type==DIV_INS_MIKEY) waveMax=0; if (ins->type==DIV_INS_MULTIPCM) waveMax=0; + if (ins->type==DIV_INS_ADPCMA) waveMax=0; + if (ins->type==DIV_INS_ADPCMB) waveMax=0; + if (ins->type==DIV_INS_QSOUND) waveMax=0; + if (ins->type==DIV_INS_YMZ280B) waveMax=0; + if (ins->type==DIV_INS_MSM6258) waveMax=0; + if (ins->type==DIV_INS_MSM6295) waveMax=0; + if (ins->type==DIV_INS_SEGAPCM) waveMax=0; if (ins->type==DIV_INS_SU) waveMax=7; if (ins->type==DIV_INS_PET) { waveMax=8; @@ -4418,7 +4419,7 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930) { - waveMax=ins->amiga.useSample?(MAX(1,e->song.waveLen-1)):3; + waveMax=ins->amiga.useSample?0:3; waveBitMode=ins->amiga.useSample?false:true; } @@ -4471,6 +4472,7 @@ void FurnaceGUI::drawInsEdit() { bool panSingleNoBit=false; if (ins->type==DIV_INS_STD ||//Game Gear ins->type==DIV_INS_FM || + ins->type==DIV_INS_OPM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_GB || @@ -4555,6 +4557,7 @@ void FurnaceGUI::drawInsEdit() { } 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 || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || From 3d5125e792036dd820be00d5ee1ddaa4fb06efdf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 01:33:36 -0500 Subject: [PATCH 43/46] OPM/NES ins type split, part 1 --- src/gui/insEdit.cpp | 99 +++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 40 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 97be4a713..bbf7fd5e3 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1214,7 +1214,7 @@ inline bool enBit30(const int val) { void FurnaceGUI::kvsConfig(DivInstrument* ins) { if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("(click to configure KVS)"); + ImGui::SetTooltip("(click to configure TL scaling)"); } int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; @@ -1986,7 +1986,7 @@ void FurnaceGUI::drawInsEdit() { } if (willDisplayOps) { if (settings.fmLayout==0) { - int numCols=16; + int numCols=15; if (ins->type==DIV_INS_OPL ||ins->type==DIV_INS_OPL_DRUMS) numCols=13; if (ins->type==DIV_INS_OPLL) numCols=12; if (ins->type==DIV_INS_OPZ) numCols=19; @@ -2015,12 +2015,14 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableSetupColumn("c10",ImGuiTableColumnFlags_WidthStretch,0.05f); // dt + } + if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { ImGui::TableSetupColumn("c11",ImGuiTableColumnFlags_WidthStretch,0.05f); // dt2 } ImGui::TableSetupColumn("c15",ImGuiTableColumnFlags_WidthFixed); // am ImGui::TableSetupColumn("c12",ImGuiTableColumnFlags_WidthFixed); // -separator- - if (ins->type!=DIV_INS_OPLL) { + if (ins->type!=DIV_INS_OPLL && ins->type!=DIV_INS_OPM) { ImGui::TableSetupColumn("c13",ImGuiTableColumnFlags_WidthStretch,0.2f); // ssg/waveform } ImGui::TableSetupColumn("c14",ImGuiTableColumnFlags_WidthStretch,0.3f); // env @@ -2086,6 +2088,8 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT(FM_SHORT_NAME(FM_DT)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_DT)); ImGui::TableNextColumn(); + } + if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { CENTER_TEXT(FM_SHORT_NAME(FM_DT2)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_DT2)); ImGui::TableNextColumn(); @@ -2102,7 +2106,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); CENTER_TEXT(FM_NAME(FM_WS)); ImGui::TextUnformatted(FM_NAME(FM_WS)); - } else if (ins->type!=DIV_INS_OPLL) { + } else if (ins->type!=DIV_INS_OPLL && ins->type!=DIV_INS_OPM) { ImGui::TableNextColumn(); CENTER_TEXT(FM_NAME(FM_SSG)); ImGui::TextUnformatted(FM_NAME(FM_SSG)); @@ -2276,10 +2280,11 @@ void FurnaceGUI::drawInsEdit() { op.dt=detune+(settings.unsignedDetune?0:3); } - // TODO: separate OPN/OPM - ImGui::TableNextColumn(); - CENTER_VSLIDER; - P(CWVSliderScalar("##DT2",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable + if (ins->type!=DIV_INS_FM) { + ImGui::TableNextColumn(); + CENTER_VSLIDER; + P(CWVSliderScalar("##DT2",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable + } ImGui::TableNextColumn(); bool amOn=op.am; @@ -2318,7 +2323,7 @@ void FurnaceGUI::drawInsEdit() { } } - if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ) { + if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ && ins->type!=DIV_INS_OPM) { ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); ImGui::TableNextColumn(); @@ -2335,7 +2340,7 @@ void FurnaceGUI::drawInsEdit() { op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); } } - } else { + } else if (ins->type!=DIV_INS_OPM) { ImGui::TableNextColumn(); bool amOn=op.am; ImGui::SetCursorPosY(ImGui::GetCursorPosY()+0.5*(sliderHeight-ImGui::GetFrameHeight()*4.0-ImGui::GetStyle().ItemSpacing.y*3.0)); @@ -2370,7 +2375,7 @@ void FurnaceGUI::drawInsEdit() { if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); } - } else if (ins->type==DIV_INS_OPLL) { + } else if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPM) { ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); } @@ -2470,7 +2475,7 @@ void FurnaceGUI::drawInsEdit() { float sliderHeight=200.0f*dpiScale; float waveWidth=140.0*dpiScale; - float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*(ins->type==DIV_INS_OPLL?4.5f:5.5f); + float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*((ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL)?5.0f:4.5f); int maxTl=127; if (ins->type==DIV_INS_OPLL) { @@ -2505,7 +2510,7 @@ void FurnaceGUI::drawInsEdit() { CENTER_TEXT_20(FM_SHORT_NAME(FM_AR)); ImGui::TextUnformatted(FM_SHORT_NAME(FM_AR)); ImGui::TableNextColumn(); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { + if (ins->type==DIV_INS_FM) { ImGui::Text("SSG-EG"); } else { ImGui::Text("Waveform"); @@ -2580,8 +2585,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); switch (ins->type) { - case DIV_INS_FM: - case DIV_INS_OPM: { + case DIV_INS_FM: { // SSG ImGui::BeginDisabled(!ssgOn); drawSSGEnv(op.ssgEnv&7,ImVec2(waveWidth,waveHeight)); @@ -2589,9 +2593,6 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only for OPN family chips"); - } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -2612,17 +2613,35 @@ void FurnaceGUI::drawInsEdit() { op.dt=detune+(settings.unsignedDetune?0:3); } rightClickable + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); + P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable + + break; + } + case DIV_INS_OPM: { + drawWaveform(0,true,ImVec2(waveWidth,waveHeight)); + + // params + ImGui::Separator(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT)); + P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable + + int detune=(op.dt&7)-(settings.unsignedDetune?0:3); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT)); + if (CWSliderInt("##DT",&detune,-3,4,tempID)) { PARAMETER + op.dt=detune+(settings.unsignedDetune?0:3); + } rightClickable + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT2)); P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE,tempID)); rightClickable - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only on YM2151 (OPM)"); - } ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_RS)); P(CWSliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE,tempID)); rightClickable - break; } case DIV_INS_OPLL: @@ -2949,16 +2968,11 @@ void FurnaceGUI::drawInsEdit() { bool vibOn=op.vib; bool susOn=op.sus; // don't you make fun of this one unsigned char ssgEnv=op.ssgEnv&7; - if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ) { + if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ && ins->type!=DIV_INS_OPM) { ImGui::SameLine(); if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Only for OPN family chips"); - } - } } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { @@ -3140,14 +3154,16 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("%s",FM_NAME(FM_DT)); } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_DT2)); + if (ins->type!=DIV_INS_FM) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_DT2)); + } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { // OPN only + if (ins->type==DIV_INS_FM) { // OPN only ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -3217,7 +3233,7 @@ void FurnaceGUI::drawInsEdit() { } } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { + if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) { macroList.push_back(FurnaceGUIMacroDesc("AM Depth",&ins->std.ex1Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("PM Depth",&ins->std.ex2Macro,0,127,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO Speed",&ins->std.ex3Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -3294,10 +3310,12 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_RS),&ins->std.opMacros[ordi].rsMacro,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_DT),&ins->std.opMacros[ordi].dtMacro,0,7,64,uiColors[GUI_COLOR_MACRO_OTHER])); - macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT2),&ins->std.opMacros[ordi].dt2Macro,0,3,32,uiColors[GUI_COLOR_MACRO_OTHER])); + if (ins->type==DIV_INS_OPM || ins->type==DIV_INS_OPZ) { + macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DT2),&ins->std.opMacros[ordi].dt2Macro,0,3,32,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,NULL,NULL,true)); - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { + 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,NULL,NULL,true,ssgEnvBits)); } } @@ -4310,7 +4328,7 @@ void FurnaceGUI::drawInsEdit() { dutyMax=96; } } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM) { + if (ins->type==DIV_INS_OPM || ins->type==DIV_INS_OPZ) { dutyMax=32; } if (ins->type==DIV_INS_AY) { @@ -4331,7 +4349,8 @@ void FurnaceGUI::drawInsEdit() { dutyMax=ins->amiga.useSample?0:255; } if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || - ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM) { + ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM || + ins->type==DIV_INS_FM) { dutyMax=0; } if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_NAMCO) { From d0e581e4cdc591fccb761a4411adb758d946ac18 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 01:37:29 -0500 Subject: [PATCH 44/46] OPM/NES ins type split, part 2 --- src/gui/insEdit.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index bbf7fd5e3..4cb03bf05 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4328,6 +4328,9 @@ void FurnaceGUI::drawInsEdit() { dutyMax=96; } } + if (ins->type==DIV_INS_STD) { + dutyLabel="Duty"; + } if (ins->type==DIV_INS_OPM || ins->type==DIV_INS_OPZ) { dutyMax=32; } @@ -4410,7 +4413,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_SAA1099) { waveBitMode=true; } - if (ins->type==DIV_INS_STD || ins->type==DIV_INS_VRC6_SAW) waveMax=0; + if (ins->type==DIV_INS_STD || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_NES) waveMax=0; if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_VIC || ins->type==DIV_INS_OPLL) waveMax=15; if (ins->type==DIV_INS_C64) waveMax=4; if (ins->type==DIV_INS_SAA1099) waveMax=2; @@ -4578,6 +4581,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM || ins->type==DIV_INS_STD || + ins->type==DIV_INS_NES || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ || From d2a417e1d59605baa9166b341d79a52b0be980aa Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 01:46:44 -0500 Subject: [PATCH 45/46] OPM/NES ins type split, part 3 --- src/engine/sysDef.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 1f3f8e07b..624b6a721 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -666,7 +666,7 @@ void DivEngine::registerSystems() { {"Pulse 1", "Pulse 2", "Triangle", "Noise", "PCM"}, {"S1", "S2", "TR", "NO", "PCM"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE, DIV_CH_PCM}, - {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA}, + {DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_AMIGA}, {}, { {0x11, {DIV_CMD_NES_DMC, "11xx: Write to delta modulation counter (0 to 7F)"}}, @@ -777,7 +777,7 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM}, + {DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM}, {}, fmEffectHandlerMap, fmOPMPostEffectHandlerMap @@ -916,7 +916,7 @@ void DivEngine::registerSystems() { {"Pulse 1", "Pulse 2", "PCM"}, {"S1", "S2", "PCM"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM}, - {DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA}, + {DIV_INS_NES, DIV_INS_NES, DIV_INS_AMIGA}, {}, { {0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"}}, @@ -1106,7 +1106,7 @@ void DivEngine::registerSystems() { {"Square"}, {"SQ"}, {DIV_CH_PULSE}, - {DIV_INS_STD} + {DIV_INS_BEEPER} ); sysDefs[DIV_SYSTEM_SEGAPCM]=new DivSysDef( From 3eb4f997da0f76d0f45b4afe3d507367cb89e171 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 24 Sep 2022 02:14:26 -0500 Subject: [PATCH 46/46] OPM/NES ins type split, part 4 --- src/engine/fileOps.cpp | 82 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 9 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 47a837899..0d8817ebf 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -337,7 +337,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } logD("%d name: %s",i,ins->name.c_str()); if (ds.version<0x0b) { - // instruments in ancient versions were all FM or STD. + // instruments in ancient versions were all FM. mode=1; } else { mode=reader.readC(); @@ -366,6 +366,12 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (ds.system[0]==DIV_SYSTEM_YMU759) { ins->type=DIV_INS_OPL; } + if (ds.system[0]==DIV_SYSTEM_ARCADE) { + ins->type=DIV_INS_OPM; + } + if ((ds.system[0]==DIV_SYSTEM_NES || ds.system[0]==DIV_SYSTEM_NES_VRC7 || ds.system[0]==DIV_SYSTEM_NES_FDS) && ins->type==DIV_INS_STD) { + ins->type=DIV_INS_NES; + } if (mode) { // FM if (ds.version>0x05) { @@ -1919,6 +1925,57 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } } + // convert OPM/NES instrument types + if (ds.version<117) { + int opnCount=0; + int opmCount=0; + int snCount=0; + int nesCount=0; + for (int i=0; iopnCount) { + for (DivInstrument* i: ds.ins) { + if (i->type==DIV_INS_FM) i->type=DIV_INS_OPM; + } + } + if (nesCount>snCount) { + for (DivInstrument* i: ds.ins) { + if (i->type==DIV_INS_STD) i->type=DIV_INS_NES; + } + } + } + if (active) quitDispatch(); BUSY_BEGIN_SOFT; saveLock.lock(); @@ -3237,7 +3294,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) { unsigned char insType=reader.readC(); switch (insType) { case 1: - ins->type=DIV_INS_STD; + ins->type=DIV_INS_NES; break; case 2: // TODO: tell VRC6 and VRC6 saw instruments apart ins->type=DIV_INS_VRC6; @@ -3264,7 +3321,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) { // instrument data switch (ins->type) { - case DIV_INS_STD: { + case DIV_INS_NES: { unsigned int totalSeqs=reader.readI(); if (totalSeqs>5) { logE("%d: too many sequences!",insIndex); @@ -4183,7 +4240,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { } for (DivInstrument* i: song.ins) { - if (i->type==DIV_INS_FM) { + if (i->type==DIV_INS_FM || i->type==DIV_INS_OPM) { addWarning("no FM macros in .dmf format"); break; } @@ -4194,11 +4251,14 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeString(i->name,true); // safety check - if (!isFMSystem(sys) && i->type!=DIV_INS_STD && i->type!=DIV_INS_FDS) { + if (!isFMSystem(sys) && i->type!=DIV_INS_STD && i->type!=DIV_INS_NES && i->type!=DIV_INS_FDS) { switch (song.system[0]) { case DIV_SYSTEM_GB: i->type=DIV_INS_GB; break; + case DIV_SYSTEM_NES: + i->type=DIV_INS_NES; + break; case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: i->type=DIV_INS_C64; @@ -4215,12 +4275,16 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { break; } } - if (!isSTDSystem(sys) && i->type!=DIV_INS_FM) { - i->type=DIV_INS_FM; + if (!isSTDSystem(sys) && i->type!=DIV_INS_FM && i->type!=DIV_INS_OPM) { + if (sys==DIV_SYSTEM_ARCADE) { + i->type=DIV_INS_OPM; + } else { + i->type=DIV_INS_FM; + } } - w->writeC((i->type==DIV_INS_FM || i->type==DIV_INS_OPLL)?1:0); - if (i->type==DIV_INS_FM || i->type==DIV_INS_OPLL) { // FM + w->writeC((i->type==DIV_INS_FM || i->type==DIV_INS_OPM || i->type==DIV_INS_OPLL)?1:0); + if (i->type==DIV_INS_FM || i->type==DIV_INS_OPM || i->type==DIV_INS_OPLL) { // FM w->writeC(i->fm.alg); w->writeC(i->fm.fb); w->writeC(i->fm.fms);