From 5f47166012f41d36b8f57cbcbf04fe2e43cc2b39 Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Wed, 9 Oct 2024 17:28:58 +0400 Subject: [PATCH] redo opnx csm --- src/engine/dispatchContainer.cpp | 40 ++++++ src/engine/platform/fmshared_OPN.h | 2 +- src/engine/platform/ym2203.cpp | 84 ++++++++---- src/engine/platform/ym2203.h | 10 +- src/engine/platform/ym2203ext.cpp | 52 +++++++- src/engine/platform/ym2203ext.h | 1 + src/engine/platform/ym2608.cpp | 199 ++++++++++++++++++----------- src/engine/platform/ym2608.h | 11 +- src/engine/platform/ym2608ext.cpp | 53 +++++++- src/engine/platform/ym2610.cpp | 79 ++++++++++-- src/engine/platform/ym2610.h | 5 +- src/engine/platform/ym2610b.cpp | 73 +++++++++-- src/engine/platform/ym2610b.h | 5 +- src/engine/platform/ym2610bext.cpp | 43 ++++++- src/engine/platform/ym2610ext.cpp | 42 +++++- src/engine/platform/ym2610shared.h | 12 +- src/gui/guiConst.cpp | 8 ++ 17 files changed, 572 insertions(+), 147 deletions(-) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index af472a268..f6d9a1069 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -374,6 +374,16 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do } else { ((DivPlatformYM2610Ext*)dispatch)->setCombo(eng->getConfInt("opnbCore",1)); } + ((DivPlatformYM2610Ext*)dispatch)->setCSM(0); + break; + case DIV_SYSTEM_YM2610_CSM: + dispatch=new DivPlatformYM2610Ext; + if (isRender) { + ((DivPlatformYM2610Ext*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2610Ext*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } + ((DivPlatformYM2610Ext*)dispatch)->setCSM(1); break; case DIV_SYSTEM_YM2610B: dispatch=new DivPlatformYM2610B; @@ -390,6 +400,16 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do } else { ((DivPlatformYM2610BExt*)dispatch)->setCombo(eng->getConfInt("opnbCore",1)); } + ((DivPlatformYM2610BExt*)dispatch)->setCSM(0); + break; + case DIV_SYSTEM_YM2610B_CSM: + dispatch=new DivPlatformYM2610BExt; + if (isRender) { + ((DivPlatformYM2610BExt*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2610BExt*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } + ((DivPlatformYM2610BExt*)dispatch)->setCSM(1); break; case DIV_SYSTEM_AMIGA: dispatch=new DivPlatformAmiga; @@ -431,6 +451,16 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do } else { ((DivPlatformYM2203Ext*)dispatch)->setCombo(eng->getConfInt("opn1Core",1)); } + ((DivPlatformYM2203Ext*)dispatch)->setCSM(0); + break; + case DIV_SYSTEM_YM2203_CSM: + dispatch=new DivPlatformYM2203Ext; + if (isRender) { + ((DivPlatformYM2203Ext*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2203Ext*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } + ((DivPlatformYM2203Ext*)dispatch)->setCSM(1); break; case DIV_SYSTEM_YM2608: dispatch=new DivPlatformYM2608; @@ -447,6 +477,16 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do } else { ((DivPlatformYM2608Ext*)dispatch)->setCombo(eng->getConfInt("opnaCore",1)); } + ((DivPlatformYM2608Ext*)dispatch)->setCSM(0); + break; + case DIV_SYSTEM_YM2608_CSM: + dispatch=new DivPlatformYM2608Ext; + if (isRender) { + ((DivPlatformYM2608Ext*)dispatch)->setCombo(eng->getConfInt("opnaCoreRender",1)); + } else { + ((DivPlatformYM2608Ext*)dispatch)->setCombo(eng->getConfInt("opnaCore",1)); + } + ((DivPlatformYM2608Ext*)dispatch)->setCSM(1); break; case DIV_SYSTEM_OPLL: case DIV_SYSTEM_OPLL_DRUMS: diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index d7ba70418..65f9700c4 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -148,7 +148,7 @@ class DivPlatformOPN: public DivPlatformFMBase { pan(3) {} }; - const int extChanOffs, psgChanOffs, adpcmAChanOffs, adpcmBChanOffs, chanNum; + int extChanOffs, psgChanOffs, adpcmAChanOffs, adpcmBChanOffs, chanNum; // i really wanted to keep this constant... double fmFreqBase; unsigned int fmDivBase; diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 63e3db25e..004330fd9 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -237,8 +237,8 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) { oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767); } - for (int i=3; i<6; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2]<<1; + for (int i=(3+isCSM); i<(6+isCSM); i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2+isCSM]<<1; } } } @@ -290,8 +290,8 @@ void DivPlatformYM2203::acquire_ymfm(short** buf, size_t len) { oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } - for (int i=3; i<6; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2]<<1; + for (int i=(3+isCSM); i<(6+isCSM); i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2+isCSM]<<1; } } } @@ -723,15 +723,29 @@ void DivPlatformYM2203::commitState(int ch, DivInstrument* ins) { } int DivPlatformYM2203::dispatch(DivCommand c) { - if (c.chan>2) { - c.chan-=3; + if (c.chan>(2+isCSM)) { + c.chan-=(3+isCSM); return ay->dispatch(c); } switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); + if (c.chan==csmChan && extMode) { // CSM + chan[c.chan].macroInit(ins); + chan[c.chan].insChanged=false; + + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].portaPause=false; + chan[c.chan].note=c.value; + chan[c.chan].freqChanged=true; + } + chan[c.chan].keyOn=true; + chan[c.chan].active=true; + break; + } chan[c.chan].macroInit(ins); - if (c.chan<3) { + if (c.chan2 || parent->song.linearPitch==2) { // PSG + if (c.chan==csmChan) { + int destFreq=NOTE_PERIODIC(c.value2); + bool return2=false; + if (destFreq>chan[c.chan].baseFreq) { + chan[c.chan].baseFreq+=c.value; + if (chan[c.chan].baseFreq>=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } else { + chan[c.chan].baseFreq-=c.value; + if (chan[c.chan].baseFreq<=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } + chan[c.chan].freqChanged=true; + if (return2) { + chan[c.chan].inPorta=false; + return 2; + } + break; + } + if (c.chan>(psgChanOffs-1) || parent->song.linearPitch==2) { // PSG int destFreq=NOTE_FNUM_BLOCK(c.value2,11); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { @@ -828,6 +865,9 @@ int DivPlatformYM2203::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { + if (c.chan==csmChan) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + } if (chan[c.chan].insChanged) { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); commitState(c.chan,ins); @@ -1053,11 +1093,11 @@ int DivPlatformYM2203::dispatch(DivCommand c) { chan[c.chan].std.restart(c.value); break; case DIV_CMD_GET_VOLMAX: - if (c.chan>2) return 15; + if (c.chan>(2+isCSM)) return 15; return 127; break; case DIV_CMD_PRE_PORTA: - if (c.chan>2) { + if (c.chan>(2+isCSM)) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); } @@ -1075,8 +1115,8 @@ int DivPlatformYM2203::dispatch(DivCommand c) { void DivPlatformYM2203::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - if (ch>2) { // PSG - ay->muteChannel(ch-3,mute); + if (ch>(2+isCSM)) { // PSG + ay->muteChannel(ch-(3+isCSM),mute); return; } for (int j=0; j<4; j++) { @@ -1121,7 +1161,7 @@ void DivPlatformYM2203::forceIns() { chan[i].freqChanged=true; } } - for (int i=3; i<6; i++) { + for (int i=(3+isCSM); i<(6+isCSM); i++) { chan[i].insChanged=true; } @@ -1139,7 +1179,7 @@ void* DivPlatformYM2203::getChanState(int ch) { } DivMacroInt* DivPlatformYM2203::getChanMacroInt(int ch) { - if (ch>=3) return ay->getChanMacroInt(ch-3); + if (ch>=(3+isCSM)) return ay->getChanMacroInt(ch-(3+isCSM)); return &chan[ch].std; } @@ -1173,15 +1213,15 @@ void DivPlatformYM2203::reset() { OPN2_SetChipType(&fm_nuked,ym3438_mode_opn); fm->reset(); memset(&fm_lle,0,sizeof(fmopna_t)); - for (int i=0; i<6; i++) { + for (int i=0; i<7; i++) { chan[i]=DivPlatformOPN::OPNChannel(); chan[i].std.setEngine(parent); } - for (int i=0; i<3; i++) { + for (int i=0; i<3; i++) { // check back later / me from future: wha? chan[i].vol=0x7f; chan[i].outVol=0x7f; } - for (int i=3; i<6; i++) { + for (int i=(3+isCSM); i<(6+isCSM); i++) { chan[i].vol=0x0f; } @@ -1255,7 +1295,7 @@ bool DivPlatformYM2203::keyOffAffectsArp(int ch) { } void DivPlatformYM2203::notifyInsChange(int ins) { - for (int i=0; i<6; i++) { + for (int i=0; i<7; i++) { if (chan[i].ins==ins) { chan[i].insChanged=true; } @@ -1331,7 +1371,7 @@ void DivPlatformYM2203::setFlags(const DivConfig& flags) { } else { rate=fm->sample_rate(chipClock); } - for (int i=0; i<6; i++) { + for (int i=0; i<7; i++) { oscBuf[i]->rate=rate; } immWrite(0x2d,0xff); @@ -1345,7 +1385,7 @@ int DivPlatformYM2203::init(DivEngine* p, int channels, int sugRate, const DivCo parent=p; dumpWrites=false; skipRegisterWrites=false; - for (int i=0; i<6; i++) { + for (int i=0; i<7; i++) { isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } @@ -1358,11 +1398,11 @@ int DivPlatformYM2203::init(DivEngine* p, int channels, int sugRate, const DivCo setFlags(flags); reset(); - return 6; + return 7; } void DivPlatformYM2203::quit() { - for (int i=0; i<6; i++) { + for (int i=0; i<7; i++) { delete oscBuf[i]; } ay->quit(); diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index baff93ebe..9113ffe9e 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -42,9 +42,9 @@ class DivPlatformYM2203: public DivPlatformOPN { 0, 1, 2 }; - OPNChannel chan[6]; - DivDispatchOscBuffer* oscBuf[6]; - bool isMuted[6]; + OPNChannel chan[7]; + DivDispatchOscBuffer* oscBuf[7]; + bool isMuted[7]; ym3438_t fm_nuked; ymfm::ym2203* fm; ymfm::ym2203::output_data fmout; @@ -73,6 +73,7 @@ class DivPlatformYM2203: public DivPlatformOPN { void acquire_lle(short** buf, size_t len); public: + bool isCSM; void acquire(short** buf, size_t len); void fillStream(std::vector& stream, int sRate, size_t len); int dispatch(DivCommand c); @@ -98,7 +99,8 @@ class DivPlatformYM2203: public DivPlatformOPN { void quit(); DivPlatformYM2203(): DivPlatformOPN(2, 3, 6, 6, 6, 4720270.0, 36, 16), - prescale(0x2d) {} + prescale(0x2d), + isCSM(false) {} ~DivPlatformYM2203(); }; #endif diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index bd2e6c4a5..834994492 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -414,6 +414,9 @@ void DivPlatformYM2203Ext::tick(bool sysTick) { } } if (writeSomething) { + if (chan[csmChan].active) { // CSM + writeMask^=0xf0; + } immWrite(0x28,writeMask); } } @@ -565,7 +568,28 @@ void DivPlatformYM2203Ext::tick(bool sysTick) { } } } + if (extMode) { + if (chan[csmChan].freqChanged) { + chan[csmChan].freq=parent->calcFreq(chan[csmChan].baseFreq,chan[csmChan].pitch,chan[csmChan].fixedArp?chan[csmChan].baseNoteOverride:chan[csmChan].arpOff,chan[csmChan].fixedArp,true,0,chan[csmChan].pitch2,chipClock,CHIP_DIVIDER); + if (chan[csmChan].freq<1) chan[csmChan].freq=1; + if (chan[csmChan].freq>1024) chan[csmChan].freq=1024; + int wf=0x400-chan[csmChan].freq; + immWrite(0x24,wf>>2); + immWrite(0x25,wf&3); + chan[csmChan].freqChanged=false; + } + + if (chan[csmChan].keyOff || chan[csmChan].keyOn) { + writeNoteOn=true; + for (int i=0; i<4; i++) { + writeMask|=opChan[i].active<<(4+i); + } + } + } if (writeNoteOn) { + if (chan[csmChan].active) { // CSM + writeMask^=0xf0; + } writeMask^=hardResetMask; immWrite(0x28,writeMask); writeMask^=hardResetMask; @@ -587,6 +611,17 @@ void DivPlatformYM2203Ext::tick(bool sysTick) { immWrite(0x28,writeMask); } } + + if (extMode) { + if (chan[csmChan].keyOn) { + immWrite(0x27,0x81); + chan[csmChan].keyOn=false; + } + if (chan[csmChan].keyOff) { + immWrite(0x27,0x40); + chan[csmChan].keyOff=false; + } + } } void DivPlatformYM2203Ext::muteChannel(int ch, bool mute) { @@ -666,6 +701,12 @@ void DivPlatformYM2203Ext::forceIns() { opChan[i].freqChanged=true; } } + + if (extMode && chan[csmChan].active) { // CSM + chan[csmChan].insChanged=true; + chan[csmChan].freqChanged=true; + chan[csmChan].keyOn=true; + } if (!extMode) { immWrite(0x27,0x00); } @@ -678,7 +719,7 @@ void* DivPlatformYM2203Ext::getChanState(int ch) { } DivMacroInt* DivPlatformYM2203Ext::getChanMacroInt(int ch) { - if (ch>=6) return ay->getChanMacroInt(ch-6); + if (ch>=(6+isCSM)) return ay->getChanMacroInt(ch-(6+isCSM)); if (ch>=2) return &opChan[ch-2].std; return &chan[ch].std; } @@ -738,12 +779,19 @@ int DivPlatformYM2203Ext::init(DivEngine* parent, int channels, int sugRate, con extSys=true; reset(); - return 9; + return 3+2+4+isCSM; // 3xPSG + 2xFM + 4xOP + optional CSM } void DivPlatformYM2203Ext::quit() { DivPlatformYM2203::quit(); } +void DivPlatformYM2203Ext::setCSM(bool isCSM) { + this->isCSM=isCSM; + if (isCSM) { + csmChan=3; + } +} + DivPlatformYM2203Ext::~DivPlatformYM2203Ext() { } diff --git a/src/engine/platform/ym2203ext.h b/src/engine/platform/ym2203ext.h index c735e196b..a182e2970 100644 --- a/src/engine/platform/ym2203ext.h +++ b/src/engine/platform/ym2203ext.h @@ -44,6 +44,7 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 { void notifyInsDeletion(void* ins); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); void quit(); + void setCSM(bool isCSM); ~DivPlatformYM2203Ext(); }; diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 29cf262ea..8cb610e04 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -480,15 +480,15 @@ void DivPlatformYM2608::acquire_ymfm(short** buf, size_t len) { } ssge->get_last_out(ssgOut); - for (int i=6; i<9; i++) { + for (int i=(6+isCSM); i<(9+isCSM); i++) { oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-6]<<1; } - for (int i=9; i<15; i++) { + for (int i=(9+isCSM); i<(15+isCSM); i++) { oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-9]->get_last_out(0)+adpcmAChan[i-9]->get_last_out(1))>>1; } - oscBuf[15]->data[oscBuf[15]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1; + oscBuf[15+isCSM]->data[oscBuf[15+isCSM]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1; } } @@ -894,7 +894,7 @@ void DivPlatformYM2608::tick(bool sysTick) { } // RSS - for (int i=9; i<15; i++) { + for (int i=(9+isCSM); i<(15+isCSM); i++) { if (chan[i].furnacePCM) { chan[i].std.next(); if (chan[i].std.vol.had) { @@ -916,93 +916,93 @@ 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)); + immWrite(0x18+(i-(9+isCSM)),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); hardResetElapsed++; } } if (chan[i].keyOff) { - writeRSSOff|=(1<<(i-9)); + writeRSSOff|=(1<<(i-(9+isCSM))); chan[i].keyOff=false; } if (chan[i].keyOn) { - writeRSSOn|=(1<<(i-9)); + writeRSSOn|=(1<<(i-(9+isCSM))); chan[i].keyOn=false; } } // ADPCM-B - if (chan[15].furnacePCM) { - chan[15].std.next(); + if (chan[(15+isCSM)].furnacePCM) { + chan[(15+isCSM)].std.next(); - if (chan[15].std.vol.had) { - chan[15].outVol=(chan[15].vol*MIN(chan[15].macroVolMul,chan[15].std.vol.val))/chan[15].macroVolMul; - immWrite(0x10b,chan[15].outVol); + if (chan[(15+isCSM)].std.vol.had) { + chan[(15+isCSM)].outVol=(chan[(15+isCSM)].vol*MIN(chan[(15+isCSM)].macroVolMul,chan[(15+isCSM)].std.vol.val))/chan[(15+isCSM)].macroVolMul; + immWrite(0x10b,chan[(15+isCSM)].outVol); hardResetElapsed++; } if (NEW_ARP_STRAT) { - chan[15].handleArp(); - } else if (chan[15].std.arp.had) { - if (!chan[15].inPorta) { - chan[15].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[15].note,chan[15].std.arp.val)); + chan[(15+isCSM)].handleArp(); + } else if (chan[(15+isCSM)].std.arp.had) { + if (!chan[(15+isCSM)].inPorta) { + chan[(15+isCSM)].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[(15+isCSM)].note,chan[(15+isCSM)].std.arp.val)); } - chan[15].freqChanged=true; + chan[(15+isCSM)].freqChanged=true; } - if (chan[15].std.pitch.had) { - if (chan[15].std.pitch.mode) { - chan[15].pitch2+=chan[15].std.pitch.val; - CLAMP_VAR(chan[15].pitch2,-65535,65535); + if (chan[(15+isCSM)].std.pitch.had) { + if (chan[(15+isCSM)].std.pitch.mode) { + chan[(15+isCSM)].pitch2+=chan[(15+isCSM)].std.pitch.val; + CLAMP_VAR(chan[(15+isCSM)].pitch2,-65535,65535); } else { - chan[15].pitch2=chan[15].std.pitch.val; + chan[(15+isCSM)].pitch2=chan[(15+isCSM)].std.pitch.val; } - chan[15].freqChanged=true; + chan[(15+isCSM)].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 (chan[(15+isCSM)].std.panL.had) { + if (chan[(15+isCSM)].pan!=(chan[(15+isCSM)].std.panL.val&3)) { + chan[(15+isCSM)].pan=chan[(15+isCSM)].std.panL.val&3; if (!isMuted[15]) { - immWrite(0x101,(isMuted[15]?0:(chan[15].pan<<6))|1); + immWrite(0x101,(isMuted[15]?0:(chan[(15+isCSM)].pan<<6))|1); hardResetElapsed++; } } } - if (chan[15].std.phaseReset.had) { - if ((chan[15].std.phaseReset.val==1) && chan[15].active) { - chan[15].keyOn=true; + if (chan[(15+isCSM)].std.phaseReset.had) { + if ((chan[(15+isCSM)].std.phaseReset.val==1) && chan[(15+isCSM)].active) { + chan[(15+isCSM)].keyOn=true; } } } - 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,chan[15].fixedArp?chan[15].baseNoteOverride:chan[15].arpOff,chan[15].fixedArp,false,4,chan[15].pitch2,(double)chipClock/144,off); + if (chan[(15+isCSM)].freqChanged || chan[(15+isCSM)].keyOn || chan[(15+isCSM)].keyOff) { + if (chan[(15+isCSM)].furnacePCM) { + if (chan[(15+isCSM)].sample>=0 && chan[(15+isCSM)].samplesong.sampleLen) { + double off=65535.0*(double)(parent->getSample(chan[(15+isCSM)].sample)->centerRate)/8363.0; + chan[(15+isCSM)].freq=parent->calcFreq(chan[(15+isCSM)].baseFreq,chan[(15+isCSM)].pitch,chan[(15+isCSM)].fixedArp?chan[(15+isCSM)].baseNoteOverride:chan[(15+isCSM)].arpOff,chan[(15+isCSM)].fixedArp,false,4,chan[(15+isCSM)].pitch2,(double)chipClock/144,off); } else { - chan[15].freq=0; + chan[(15+isCSM)].freq=0; } } if (chan[adpcmBChanOffs].freq<0) chan[adpcmBChanOffs].freq=0; if (chan[adpcmBChanOffs].freq>65535) chan[adpcmBChanOffs].freq=65535; - immWrite(0x109,chan[15].freq&0xff); - immWrite(0x10a,(chan[15].freq>>8)&0xff); + immWrite(0x109,chan[15+isCSM].freq&0xff); + immWrite(0x10a,(chan[15+isCSM].freq>>8)&0xff); hardResetElapsed+=2; - if (chan[15].keyOn || chan[15].keyOff) { - if (chan[15].keyOff) { + if (chan[15+isCSM].keyOn || chan[15+isCSM].keyOff) { + if (chan[15+isCSM].keyOff) { immWrite(0x100,0x01); // reset hardResetElapsed++; } - 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); + if (chan[15+isCSM].active && chan[15+isCSM].keyOn && !chan[15+isCSM].keyOff) { + if (chan[15+isCSM].sample>=0 && chan[15+isCSM].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[15+isCSM].sample); immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat hardResetElapsed++; } } - chan[15].keyOn=false; - chan[15].keyOff=false; + chan[15+isCSM].keyOn=false; + chan[15+isCSM].keyOff=false; } - chan[15].freqChanged=false; + chan[15+isCSM].freqChanged=false; } if (writeRSSOff) { @@ -1094,13 +1094,13 @@ void DivPlatformYM2608::commitState(int ch, DivInstrument* ins) { } int DivPlatformYM2608::dispatch(DivCommand c) { - if (c.chan>5 && c.chan<9) { - c.chan-=6; + if (c.chan>(5+isCSM) && c.chan<(9+isCSM)) { + c.chan-=(6+isCSM); return ay->dispatch(c); } switch (c.cmd) { case DIV_CMD_NOTE_ON: { - if (c.chan>14) { // ADPCM-B + if (c.chan>(14+isCSM)) { // ADPCM-B DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255; if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) { @@ -1179,7 +1179,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { } break; } - if (c.chan>8) { // RSS + if (c.chan>(8+isCSM)) { // RSS 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) { @@ -1192,18 +1192,32 @@ int DivPlatformYM2608::dispatch(DivCommand c) { 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)); + immWrite(0x18+(c.chan-(9+isCSM)),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)); + immWrite(0x18+(c.chan-(9+isCSM)),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); + if (c.chan==csmChan && extMode) { // CSM + chan[c.chan].macroInit(ins); + chan[c.chan].insChanged=false; + + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].portaPause=false; + chan[c.chan].note=c.value; + chan[c.chan].freqChanged=true; + } + chan[c.chan].keyOn=true; + chan[c.chan].active=true; + break; + } chan[c.chan].macroInit(ins); if (c.chan<6) { if (!chan[c.chan].std.vol.will) { @@ -1244,12 +1258,12 @@ int DivPlatformYM2608::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>(14+isCSM)) { // ADPCM-B immWrite(0x10b,chan[c.chan].outVol); break; } - if (c.chan>8) { // ADPCM-A - immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + if (c.chan>(8+isCSM)) { // ADPCM-A + immWrite(0x18+(c.chan-(9+isCSM)),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); break; } for (int i=0; i<4; i++) { @@ -1290,25 +1304,48 @@ int DivPlatformYM2608::dispatch(DivCommand c) { } else { chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1); } - if (c.chan>14) { + if (c.chan>(14+isCSM)) { immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|1); break; } if (c.chan>8) { - immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol)); + immWrite(0x18+(c.chan-(9+isCSM)),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==(15+isCSM) && !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==csmChan) { + int destFreq=NOTE_PERIODIC(c.value2); + bool return2=false; + if (destFreq>chan[c.chan].baseFreq) { + chan[c.chan].baseFreq+=c.value; + if (chan[c.chan].baseFreq>=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } else { + chan[c.chan].baseFreq-=c.value; + if (chan[c.chan].baseFreq<=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } + chan[c.chan].freqChanged=true; + if (return2) { + chan[c.chan].inPorta=false; + return 2; + } + break; + } + if (c.chan>(5+isCSM) || parent->song.linearPitch==2) { // PSG, ADPCM-B int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { @@ -1342,7 +1379,10 @@ int DivPlatformYM2608::dispatch(DivCommand c) { iface.sampleBank=sampleBank; break; case DIV_CMD_LEGATO: { - if (c.chan==15 && !chan[c.chan].furnacePCM) break; + if (c.chan==csmChan) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + } + if (c.chan==(15+isCSM) && !chan[c.chan].furnacePCM) break; if (c.chan<=psgChanOffs) { if (chan[c.chan].insChanged) { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); @@ -1576,8 +1616,8 @@ int DivPlatformYM2608::dispatch(DivCommand c) { chan[c.chan].std.restart(c.value); break; case DIV_CMD_GET_VOLMAX: - if (c.chan>14) return 255; - if (c.chan>8) return 31; + if (c.chan>(14+isCSM)) return 255; + if (c.chan>(8+isCSM)) return 31; if (c.chan>5) return 15; return 127; break; @@ -1600,10 +1640,10 @@ int DivPlatformYM2608::dispatch(DivCommand c) { void DivPlatformYM2608::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - if (ch>14) { // ADPCM-B + if (ch>(14+isCSM)) { // ADPCM-B immWrite(0x101,(isMuted[ch]?0:(chan[ch].pan<<6))|1); } - if (ch>8) { // ADPCM-A + if (ch>(8+isCSM)) { // ADPCM-A immWrite(0x18+(ch-9),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].outVol)); return; } @@ -1658,12 +1698,12 @@ void DivPlatformYM2608::forceIns() { } immWrite(0x11,globalRSSVolume&0x3f); immWrite(0x22,lfoValue); - for (int i=9; i<16; i++) { + for (int i=(+isCSM); i<(16+isCSM); i++) { chan[i].insChanged=true; - if (i>14) { // ADPCM-B + if (i>(14+isCSM)) { // ADPCM-B immWrite(0x10b,chan[i].outVol); } else { - immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); + immWrite(0x18+(i-(9+isCSM)),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } } @@ -1681,7 +1721,7 @@ void* DivPlatformYM2608::getChanState(int ch) { } DivMacroInt* DivPlatformYM2608::getChanMacroInt(int ch) { - if (ch>=6 && ch<9) return ay->getChanMacroInt(ch-6); + if (ch>=(6+isCSM) && ch<(9+isCSM)) return ay->getChanMacroInt(ch-6); return &chan[ch].std; } @@ -1728,10 +1768,10 @@ void DivPlatformYM2608::reset() { chan[i].vol=0x7f; chan[i].outVol=0x7f; } - for (int i=6; i<9; i++) { + for (int i=(6+isCSM); i<(9+isCSM); i++) { chan[i].vol=0x0f; } - for (int i=9; i<15; i++) { + for (int i=(9+isCSM); i<(15+isCSM); i++) { chan[i].vol=0x1f; } chan[15].vol=0xff; @@ -1833,7 +1873,7 @@ bool DivPlatformYM2608::keyOffAffectsArp(int ch) { } void DivPlatformYM2608::notifyInsChange(int ins) { - for (int i=0; i<16; i++) { + for (int i=0; i<(16+isCSM); i++) { if (chan[i].ins==ins) { chan[i].insChanged=true; } @@ -1964,7 +2004,7 @@ void DivPlatformYM2608::setFlags(const DivConfig& flags) { } else { rate=fm->sample_rate(chipClock); } - for (int i=0; i<16; i++) { + for (int i=0; i<(16+isCSM); i++) { oscBuf[i]->rate=rate; } immWrite(0x2d,0xff); @@ -1984,7 +2024,7 @@ int DivPlatformYM2608::init(DivEngine* p, int channels, int sugRate, const DivCo iface.sampleBank=0; dumpWrites=false; skipRegisterWrites=false; - for (int i=0; i<16; i++) { + for (int i=0; i<16+isCSM; i++) { isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } @@ -1996,11 +2036,20 @@ int DivPlatformYM2608::init(DivEngine* p, int channels, int sugRate, const DivCo ay->toggleRegisterDump(true); setFlags(flags); reset(); - return 16; + return 17; +} + +void DivPlatformYM2608::setCSM(bool isCSM) { + this->isCSM=isCSM; + if (isCSM) { + csmChan=6; + } else { + csmChan=16; // me from the furute: ??? + } } void DivPlatformYM2608::quit() { - for (int i=0; i<16; i++) { + for (int i=0; i<17; i++) { delete oscBuf[i]; } ay->quit(); diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index c4114e3d7..0ca851910 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -47,9 +47,9 @@ class DivPlatformYM2608: public DivPlatformOPN { 0, 1, 2, 4, 5, 6 }; - OPNChannelStereo chan[16]; - DivDispatchOscBuffer* oscBuf[16]; - bool isMuted[16]; + OPNChannelStereo chan[17]; + DivDispatchOscBuffer* oscBuf[17]; + bool isMuted[17]; ym3438_t fm_nuked; ymfm::ym2608* fm; ymfm::ym2608::output_data fmout; @@ -92,6 +92,7 @@ class DivPlatformYM2608: public DivPlatformOPN { void acquire_lle(short** buf, size_t len); public: + bool isCSM; void acquire(short** buf, size_t len); void fillStream(std::vector& stream, int sRate, size_t len); int dispatch(DivCommand c); @@ -121,10 +122,12 @@ class DivPlatformYM2608: public DivPlatformOPN { void renderSamples(int chipID); void setFlags(const DivConfig& flags); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); + void setCSM(bool isCSM); void quit(); DivPlatformYM2608(): DivPlatformOPN(2, 6, 9, 15, 16, 9440540.0, 72, 32), - prescale(0x2d) {} + prescale(0x2d), + isCSM(false) {} ~DivPlatformYM2608(); }; #endif diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index d27703c58..2d36242e0 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -438,6 +438,9 @@ void DivPlatformYM2608Ext::tick(bool sysTick) { } } if (writeSomething) { + if (chan[csmChan].active) { // CSM + writeMask^=0xf0; + } immWrite(0x28,writeMask); } } @@ -612,7 +615,28 @@ void DivPlatformYM2608Ext::tick(bool sysTick) { } } } + if (extMode) { + if (chan[csmChan].freqChanged) { + chan[csmChan].freq=parent->calcFreq(chan[csmChan].baseFreq,chan[csmChan].pitch,chan[csmChan].fixedArp?chan[csmChan].baseNoteOverride:chan[csmChan].arpOff,chan[csmChan].fixedArp,true,0,chan[csmChan].pitch2,chipClock,CHIP_DIVIDER); + if (chan[csmChan].freq<1) chan[csmChan].freq=1; + if (chan[csmChan].freq>1024) chan[csmChan].freq=1024; + int wf=0x400-chan[csmChan].freq; + immWrite(0x24,wf>>2); + immWrite(0x25,wf&3); + chan[csmChan].freqChanged=false; + } + + if (chan[csmChan].keyOff || chan[csmChan].keyOn) { + writeNoteOn=true; + for (int i=0; i<4; i++) { + writeMask|=opChan[i].active<<(4+i); + } + } + } if (writeNoteOn) { + if (chan[csmChan].active) { // CSM + writeMask^=0xf0; + } writeMask^=hardResetMask; immWrite(0x28,writeMask); writeMask^=hardResetMask; @@ -634,6 +658,17 @@ void DivPlatformYM2608Ext::tick(bool sysTick) { immWrite(0x28,writeMask); } } + + if (extMode) { + if (chan[csmChan].keyOn) { + immWrite(0x27,0x81); + chan[csmChan].keyOn=false; + } + if (chan[csmChan].keyOff) { + immWrite(0x27,0x40); + chan[csmChan].keyOff=false; + } + } } void DivPlatformYM2608Ext::muteChannel(int ch, bool mute) { @@ -705,12 +740,12 @@ void DivPlatformYM2608Ext::forceIns() { chan[i].freqChanged=true; } } - for (int i=9; i<16; i++) { + for (int i=(9+isCSM); i<(16+isCSM); i++) { chan[i].insChanged=true; - if (i>14) { // ADPCM-B + if (i>(14+isCSM)) { // ADPCM-B immWrite(0x10b,chan[i].outVol); } else { - immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); + immWrite(0x18+(i-(9+isCSM)),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol)); } } ay->forceIns(); @@ -728,6 +763,11 @@ void DivPlatformYM2608Ext::forceIns() { opChan[i].freqChanged=true; } } + if (extMode && chan[csmChan].active) { // CSM + chan[csmChan].insChanged=true; + chan[csmChan].freqChanged=true; + chan[csmChan].keyOn=true; + } if (!extMode) { immWrite(0x27,0x00); } @@ -740,13 +780,14 @@ void* DivPlatformYM2608Ext::getChanState(int ch) { } DivMacroInt* DivPlatformYM2608Ext::getChanMacroInt(int ch) { - if (ch>=9 && ch<12) return ay->getChanMacroInt(ch-9); + if (ch>=(9+isCSM) && ch<(12+isCSM)) return ay->getChanMacroInt(ch-(9+isCSM)); if (ch>=6) return &chan[ch-3].std; if (ch>=2) return &opChan[ch-2].std; return &chan[ch].std; } unsigned short DivPlatformYM2608Ext::getPan(int ch) { + if (ch==4+csmChan) return 0; if (ch>=4+extChanOffs) return DivPlatformYM2608::getPan(ch-3); if (ch>=extChanOffs) { if (extMode) { @@ -788,7 +829,7 @@ void DivPlatformYM2608Ext::reset() { } bool DivPlatformYM2608Ext::keyOffAffectsArp(int ch) { - return (ch>8); + return (ch>(8+isCSM)); } void DivPlatformYM2608Ext::notifyInsChange(int ins) { @@ -815,7 +856,7 @@ int DivPlatformYM2608Ext::init(DivEngine* parent, int channels, int sugRate, con extSys=true; reset(); - return 19; + return 19+isCSM; } void DivPlatformYM2608Ext::quit() { diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index ff1a7af46..3113accf1 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -335,7 +335,7 @@ void DivPlatformYM2610::acquire_combo(short** buf, size_t len) { buf[1][h]=os[1]; - for (int i=0; idata[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[bchOffs[i]]<<1,-32768,32767); } @@ -407,7 +407,7 @@ void DivPlatformYM2610::acquire_ymfm(short** buf, size_t len) { buf[0][h]=os[0]; buf[1][h]=os[1]; - for (int i=0; idebug_output(0)+fmChan[i]->debug_output(1))<<1; oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } @@ -615,7 +615,7 @@ void DivPlatformYM2610::acquire_lle(short** buf, size_t len) { void DivPlatformYM2610::tick(bool sysTick) { // FM - for (int i=0; isong.linearPitch==2) { @@ -959,7 +959,7 @@ void DivPlatformYM2610::tick(bool sysTick) { for (unsigned int i=hardResetElapsed; igetIns(chan[c.chan].ins,DIV_INS_FM); + if (c.chan==csmChan && extMode) { // CSM + chan[c.chan].macroInit(ins); + chan[c.chan].insChanged=false; + + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].portaPause=false; + chan[c.chan].note=c.value; + chan[c.chan].freqChanged=true; + } + chan[c.chan].keyOn=true; + chan[c.chan].active=true; + break; + } chan[c.chan].macroInit(ins); - if (c.chanchan[c.chan].baseFreq) { + chan[c.chan].baseFreq+=c.value; + if (chan[c.chan].baseFreq>=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } else { + chan[c.chan].baseFreq-=c.value; + if (chan[c.chan].baseFreq<=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } + chan[c.chan].freqChanged=true; + if (return2) { + chan[c.chan].inPorta=false; + return 2; + } + break; + } if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta); bool return2=false; @@ -1309,6 +1346,9 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; case DIV_CMD_LEGATO: { if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; + if (c.chan==csmChan) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + } if (c.chan<=psgChanOffs) { if (chan[c.chan].insChanged) { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); @@ -1588,7 +1628,7 @@ void DivPlatformYM2610::muteChannel(int ch, bool mute) { } void DivPlatformYM2610::forceIns() { - for (int i=0; ireset(); - for (int i=0; i<14; i++) { + for (int i=0; i<15; i++) { chan[i]=DivPlatformOPN::OPNChannelStereo(); chan[i].std.setEngine(parent); } - for (int i=0; inotifyInsDeletion(ins); - for (int i=0; iisCSM=isCSM; + psgChanOffs=4+isCSM; // doing this hurts me... + adpcmAChanOffs=7+isCSM; + adpcmBChanOffs=13+isCSM; + chanNum=14+isCSM; + if (isCSM) { + csmChan=4; + } else { + csmChan=14; + } } void DivPlatformYM2610::quit() { diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 767ce45e7..d5c6ea8d0 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -45,6 +45,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { void acquire_lle(short** buf, size_t len); public: + bool isCSM; void acquire(short** buf, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); @@ -66,9 +67,11 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { void poke(std::vector& wlist); const char** getRegisterSheet(); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); + void setCSM(bool isCSM); void quit(); DivPlatformYM2610(): - DivPlatformYM2610Base(1,4,7,13,14) {} + DivPlatformYM2610Base(1,4,7,13,14), + isCSM(false) {} ~DivPlatformYM2610(); }; #endif diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 51e0de088..f23ac5c63 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -403,7 +403,7 @@ void DivPlatformYM2610B::acquire_combo(short** buf, size_t len) { buf[1][h]=os[1]; - for (int i=0; idata[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767); } @@ -474,7 +474,7 @@ void DivPlatformYM2610B::acquire_ymfm(short** buf, size_t len) { buf[1][h]=os[1]; - for (int i=0; idebug_output(0)+fmChan[i]->debug_output(1))<<1; oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } @@ -684,7 +684,7 @@ void DivPlatformYM2610B::acquire_lle(short** buf, size_t len) { void DivPlatformYM2610B::tick(bool sysTick) { // FM - for (int i=0; isong.linearPitch==2) { @@ -1028,7 +1028,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { for (unsigned int i=hardResetElapsed; igetIns(chan[c.chan].ins,DIV_INS_FM); + if (c.chan==csmChan && extMode) { // CSM + chan[c.chan].macroInit(ins); + chan[c.chan].insChanged=false; + + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].portaPause=false; + chan[c.chan].note=c.value; + chan[c.chan].freqChanged=true; + } + chan[c.chan].keyOn=true; + chan[c.chan].active=true; + break; + } chan[c.chan].macroInit(ins); if (c.chan<6) { if (!chan[c.chan].std.vol.will) { @@ -1343,6 +1357,29 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { + if (c.chan==csmChan) { + int destFreq=NOTE_PERIODIC(c.value2); + bool return2=false; + if (destFreq>chan[c.chan].baseFreq) { + chan[c.chan].baseFreq+=c.value; + if (chan[c.chan].baseFreq>=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } else { + chan[c.chan].baseFreq-=c.value; + if (chan[c.chan].baseFreq<=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } + chan[c.chan].freqChanged=true; + if (return2) { + chan[c.chan].inPorta=false; + return 2; + } + break; + } if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta); bool return2=false; @@ -1378,7 +1415,10 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; case DIV_CMD_LEGATO: { if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break; - if (c.chan<=psgChanOffs) { + if (c.chan==csmChan) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + } + if (c.chan<=(psgChanOffs-isCSM)) { if (chan[c.chan].insChanged) { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); commitState(c.chan,ins); @@ -1794,7 +1834,7 @@ bool DivPlatformYM2610B::keyOffAffectsArp(int ch) { } void DivPlatformYM2610B::notifyInsChange(int ins) { - for (int i=0; i<16; i++) { + for (int i=0; i<17; i++) { if (chan[i].ins==ins) { chan[i].insChanged=true; } @@ -1804,7 +1844,7 @@ void DivPlatformYM2610B::notifyInsChange(int ins) { void DivPlatformYM2610B::notifyInsDeletion(void* ins) { ay->notifyInsDeletion(ins); - for (int i=0; iisCSM=isCSM; + psgChanOffs=6+isCSM; // doing this hurts me... + adpcmAChanOffs=9+isCSM; + adpcmBChanOffs=15+isCSM; + chanNum=16+isCSM; + if (isCSM) { + csmChan=6; + } else { + csmChan=16; + } } void DivPlatformYM2610B::quit() { diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index a9f4498a9..67021412f 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -41,6 +41,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { void acquire_lle(short** buf, size_t len); public: + bool isCSM; void acquire(short** buf, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); @@ -62,9 +63,11 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { void poke(std::vector& wlist); const char** getRegisterSheet(); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); + void setCSM(bool isCSM); void quit(); DivPlatformYM2610B(): - DivPlatformYM2610Base(2,6,9,15,16) {} + DivPlatformYM2610Base(2,6,9,15,16), + isCSM(false) {} ~DivPlatformYM2610B(); }; #endif diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 519c7004e..4408c48e1 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -434,6 +434,9 @@ void DivPlatformYM2610BExt::tick(bool sysTick) { } } if (writeSomething) { + if (chan[csmChan].active) { // CSM + writeMask^=0xf0; + } immWrite(0x28,writeMask); } } @@ -607,7 +610,28 @@ void DivPlatformYM2610BExt::tick(bool sysTick) { } } } + if (extMode) { + if (chan[csmChan].freqChanged) { + chan[csmChan].freq=parent->calcFreq(chan[csmChan].baseFreq,chan[csmChan].pitch,chan[csmChan].fixedArp?chan[csmChan].baseNoteOverride:chan[csmChan].arpOff,chan[csmChan].fixedArp,true,0,chan[csmChan].pitch2,chipClock,CHIP_DIVIDER); + if (chan[csmChan].freq<1) chan[csmChan].freq=1; + if (chan[csmChan].freq>1024) chan[csmChan].freq=1024; + int wf=0x400-chan[csmChan].freq; + immWrite(0x24,wf>>2); + immWrite(0x25,wf&3); + chan[csmChan].freqChanged=false; + } + + if (chan[csmChan].keyOff || chan[csmChan].keyOn) { + writeNoteOn=true; + for (int i=0; i<4; i++) { + writeMask|=opChan[i].active<<(4+i); + } + } + } if (writeNoteOn) { + if (chan[csmChan].active) { // CSM + writeMask^=0xf0; + } writeMask^=hardResetMask; immWrite(0x28,writeMask); writeMask^=hardResetMask; @@ -629,6 +653,17 @@ void DivPlatformYM2610BExt::tick(bool sysTick) { immWrite(0x28,writeMask); } } + + if (extMode) { + if (chan[csmChan].keyOn) { + immWrite(0x27,0x81); + chan[csmChan].keyOn=false; + } + if (chan[csmChan].keyOff) { + immWrite(0x27,0x40); + chan[csmChan].keyOff=false; + } + } } void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) { @@ -718,6 +753,11 @@ void DivPlatformYM2610BExt::forceIns() { opChan[i].freqChanged=true; } } + if (extMode && chan[csmChan].active) { // CSM + chan[csmChan].insChanged=true; + chan[csmChan].freqChanged=true; + chan[csmChan].keyOn=true; + } if (!extMode) { immWrite(0x27,0x00); } @@ -737,6 +777,7 @@ DivMacroInt* DivPlatformYM2610BExt::getChanMacroInt(int ch) { } unsigned short DivPlatformYM2610BExt::getPan(int ch) { + if (ch==4+csmChan) return 0; if (ch>=4+extChanOffs) return DivPlatformYM2610B::getPan(ch-3); if (ch>=extChanOffs) { if (extMode) { @@ -805,7 +846,7 @@ int DivPlatformYM2610BExt::init(DivEngine* parent, int channels, int sugRate, co extSys=true; reset(); - return 19; + return 20; } void DivPlatformYM2610BExt::quit() { diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index d9a111114..a23a2baa6 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -434,6 +434,9 @@ void DivPlatformYM2610Ext::tick(bool sysTick) { } } if (writeSomething) { + if (chan[csmChan].active) { // CSM + writeMask^=0xf0; + } immWrite(0x28,writeMask); } } @@ -607,7 +610,28 @@ void DivPlatformYM2610Ext::tick(bool sysTick) { } } } + if (extMode) { + if (chan[csmChan].freqChanged) { + chan[csmChan].freq=parent->calcFreq(chan[csmChan].baseFreq,chan[csmChan].pitch,chan[csmChan].fixedArp?chan[csmChan].baseNoteOverride:chan[csmChan].arpOff,chan[csmChan].fixedArp,true,0,chan[csmChan].pitch2,chipClock,CHIP_DIVIDER); + if (chan[csmChan].freq<1) chan[csmChan].freq=1; + if (chan[csmChan].freq>1024) chan[csmChan].freq=1024; + int wf=0x400-chan[csmChan].freq; + immWrite(0x24,wf>>2); + immWrite(0x25,wf&3); + chan[csmChan].freqChanged=false; + } + + if (chan[csmChan].keyOff || chan[csmChan].keyOn) { + writeNoteOn=true; + for (int i=0; i<4; i++) { + writeMask|=opChan[i].active<<(4+i); + } + } + } if (writeNoteOn) { + if (chan[csmChan].active) { // CSM + writeMask^=0xf0; + } writeMask^=hardResetMask; immWrite(0x28,writeMask); writeMask^=hardResetMask; @@ -629,6 +653,16 @@ void DivPlatformYM2610Ext::tick(bool sysTick) { immWrite(0x28,writeMask); } } + if (extMode) { + if (chan[csmChan].keyOn) { + immWrite(0x27,0x81); + chan[csmChan].keyOn=false; + } + if (chan[csmChan].keyOff) { + immWrite(0x27,0x40); + chan[csmChan].keyOff=false; + } + } } void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) { @@ -718,6 +752,11 @@ void DivPlatformYM2610Ext::forceIns() { opChan[i].freqChanged=true; } } + if (extMode && chan[csmChan].active) { // CSM + chan[csmChan].insChanged=true; + chan[csmChan].freqChanged=true; + chan[csmChan].keyOn=true; + } if (!extMode) { immWrite(0x27,0x00); } @@ -737,6 +776,7 @@ DivMacroInt* DivPlatformYM2610Ext::getChanMacroInt(int ch) { } unsigned short DivPlatformYM2610Ext::getPan(int ch) { + if (ch==4+csmChan) return 0; if (ch>=4+extChanOffs) return DivPlatformYM2610::getPan(ch-3); if (ch>=extChanOffs) { if (extMode) { @@ -805,7 +845,7 @@ int DivPlatformYM2610Ext::init(DivEngine* parent, int channels, int sugRate, con extSys=true; reset(); - return 17; + return 17+isCSM; } void DivPlatformYM2610Ext::quit() { diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h index 08977d0d1..1e60af92e 100644 --- a/src/engine/platform/ym2610shared.h +++ b/src/engine/platform/ym2610shared.h @@ -49,9 +49,9 @@ class DivYM2610Interface: public ymfm::ymfm_interface { class DivPlatformYM2610Base: public DivPlatformOPN { protected: - OPNChannelStereo chan[16]; - DivDispatchOscBuffer* oscBuf[16]; - bool isMuted[16]; + OPNChannelStereo chan[17]; + DivDispatchOscBuffer* oscBuf[17]; + bool isMuted[17]; ym3438_t fm_nuked; ymfm::ym2610b* fm; @@ -322,7 +322,7 @@ class DivPlatformYM2610Base: public DivPlatformOPN { } else { rate=fm->sample_rate(chipClock); } - for (int i=0; i<16; i++) { + for (int i=0; i<17; i++) { oscBuf[i]->rate=rate; } } @@ -332,7 +332,7 @@ class DivPlatformYM2610Base: public DivPlatformOPN { ayFlags.set("chipType",1); dumpWrites=false; skipRegisterWrites=false; - for (int i=0; i<16; i++) { + for (int i=0; i<17; i++) { isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; } @@ -354,7 +354,7 @@ class DivPlatformYM2610Base: public DivPlatformOPN { } void quit() { - for (int i=0; i<16; i++) { + for (int i=0; i<17; i++) { delete oscBuf[i]; } ay->quit(); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 4a52cc0e1..bf74d741f 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -1218,8 +1218,10 @@ const int availableSystems[]={ DIV_SYSTEM_YM2610_EXT, DIV_SYSTEM_YM2610_FULL, DIV_SYSTEM_YM2610_FULL_EXT, + DIV_SYSTEM_YM2610_CSM, DIV_SYSTEM_YM2610B, DIV_SYSTEM_YM2610B_EXT, + DIV_SYSTEM_YM2610B_CSM, DIV_SYSTEM_T6W28, DIV_SYSTEM_AY8910, DIV_SYSTEM_AMIGA, @@ -1232,8 +1234,10 @@ const int availableSystems[]={ DIV_SYSTEM_SOUND_UNIT, DIV_SYSTEM_YM2203, DIV_SYSTEM_YM2203_EXT, + DIV_SYSTEM_YM2203_CSM, DIV_SYSTEM_YM2608, DIV_SYSTEM_YM2608_EXT, + DIV_SYSTEM_YM2608_CSM, DIV_SYSTEM_OPLL, DIV_SYSTEM_OPLL_DRUMS, DIV_SYSTEM_VRC7, @@ -1314,13 +1318,17 @@ const int chipsFM[]={ DIV_SYSTEM_YM2610_EXT, DIV_SYSTEM_YM2610_FULL, DIV_SYSTEM_YM2610_FULL_EXT, + DIV_SYSTEM_YM2610_CSM, DIV_SYSTEM_YM2610B, DIV_SYSTEM_YM2610B_EXT, + DIV_SYSTEM_YM2610B_CSM, DIV_SYSTEM_YMU759, DIV_SYSTEM_YM2203, DIV_SYSTEM_YM2203_EXT, + DIV_SYSTEM_YM2203_CSM, DIV_SYSTEM_YM2608, DIV_SYSTEM_YM2608_EXT, + DIV_SYSTEM_YM2608_CSM, DIV_SYSTEM_OPLL, DIV_SYSTEM_OPLL_DRUMS, DIV_SYSTEM_VRC7,