diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index b86e11ad..3b1d9d6c 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1279,6 +1279,11 @@ DivChannelState* DivEngine::getChanState(int ch) { return &chan[ch]; } +unsigned short DivEngine::getChanPan(int ch) { + if (ch<0 || ch>=chans) return 0; + return disCont[dispatchOfChan[ch]].dispatch->getPan(dispatchChanOfChan[ch]); +} + void* DivEngine::getDispatchChanState(int ch) { if (ch<0 || ch>=chans) return NULL; return disCont[dispatchOfChan[ch]].dispatch->getChanState(dispatchChanOfChan[ch]); diff --git a/src/engine/engine.h b/src/engine/engine.h index 683289ed..653ca8ce 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -976,6 +976,9 @@ class DivEngine { // get macro interpreter DivMacroInt* getMacroInt(int chan); + // get channel panning + unsigned short getChanPan(int chan); + // get sample position DivSamplePos getSamplePos(int chan); diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index 8d3d059c..32ea4c00 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -155,6 +155,7 @@ class DivPlatformOPN: public DivPlatformFMBase { unsigned int ayDiv; unsigned char csmChan; unsigned char lfoValue; + unsigned char lastExtChPan; unsigned short ssgVol; unsigned short fmVol; bool extSys, useCombo, fbAllOps; @@ -175,6 +176,7 @@ class DivPlatformOPN: public DivPlatformFMBase { ayDiv(a), csmChan(cc), lfoValue(0), + lastExtChPan(3), ssgVol(128), fmVol(256), extSys(isExtSys), diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index e8f3410f..1564fa0c 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -1276,7 +1276,7 @@ DivMacroInt* DivPlatformGenesis::getChanMacroInt(int ch) { unsigned short DivPlatformGenesis::getPan(int ch) { if (ch>5) ch=5; - return ((chan[ch].pan<<7)&1)|(chan[ch].pan&1); + return ((chan[ch].pan&2)<<7)|(chan[ch].pan&1); } DivSamplePos DivPlatformGenesis::getSamplePos(int ch) { diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index a1dacdc3..a147545c 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -159,6 +159,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { } } rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); + lastExtChPan=opChan[ch].pan; break; } case DIV_CMD_PITCH: { @@ -756,7 +757,7 @@ void DivPlatformGenesisExt::forceIns() { } rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); if (i==2) { - rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[0].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(lastExtChPan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } else { rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } @@ -803,7 +804,13 @@ DivMacroInt* DivPlatformGenesisExt::getChanMacroInt(int ch) { unsigned short DivPlatformGenesisExt::getPan(int ch) { if (ch==csmChan) return 0; if (ch>=4+extChanOffs) return DivPlatformGenesis::getPan(ch-3); - if (ch>=extChanOffs) return ((opChan[0].pan<<7)&1)|(opChan[0].pan&1); + if (ch>=extChanOffs) { + if (extMode) { + return ((lastExtChPan&2)<<7)|(lastExtChPan&1); + } else { + return DivPlatformGenesis::getPan(extChanOffs); + } + } return DivPlatformGenesis::getPan(ch); } @@ -823,6 +830,8 @@ void DivPlatformGenesisExt::reset() { opChan[i].outVol=127; } + lastExtChPan=3; + // channel 3 mode immWrite(0x27,0x40); extMode=true; diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 1bb9dd26..c8c5c944 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1566,14 +1566,14 @@ DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) { unsigned short DivPlatformOPL::getPan(int ch) { if (totalOutputs<=1) return 0; - if (chan[ch&(~1)].fourOp) { + /*if (chan[ch&(~1)].fourOp) { if (ch&1) { - return ((chan[ch-1].pan<<7)&1)|(chan[ch-1].pan&1); + return ((chan[ch-1].pan&2)<<7)|(chan[ch-1].pan&1); } else { - return ((chan[ch+1].pan<<7)&1)|(chan[ch+1].pan&1); + return ((chan[ch+1].pan&2)<<7)|(chan[ch+1].pan&1); } - } - return ((chan[ch].pan<<7)&1)|(chan[ch].pan&1); + }*/ + return ((chan[ch].pan&1)<<8)|((chan[ch].pan&2)>>1); } DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) { diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 7ca626d0..93c09fd6 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1463,7 +1463,7 @@ DivMacroInt* DivPlatformYM2608::getChanMacroInt(int ch) { unsigned short DivPlatformYM2608::getPan(int ch) { if (ch>=psgChanOffs && ch=4+extChanOffs) return DivPlatformYM2608::getPan(ch-3); - if (ch>=extChanOffs) return ((opChan[0].pan<<7)&1)|(opChan[0].pan&1); + if (ch>=extChanOffs) { + if (extMode) { + return ((lastExtChPan&2)<<7)|(lastExtChPan&1); + } else { + return DivPlatformYM2608::getPan(extChanOffs); + } + } return DivPlatformYM2608::getPan(ch); } @@ -772,7 +779,9 @@ void DivPlatformYM2608Ext::reset() { opChan[i].outVol=127; } - // channel 2 mode + lastExtChPan=3; + + // channel 3 mode immWrite(0x27,0x40); extMode=true; } diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index ea4a3bde..b7dcdb23 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -1423,7 +1423,7 @@ DivMacroInt* DivPlatformYM2610::getChanMacroInt(int ch) { unsigned short DivPlatformYM2610::getPan(int ch) { if (ch>=psgChanOffs && ch=psgChanOffs && ch=4+extChanOffs) return DivPlatformYM2610B::getPan(ch-3); - if (ch>=extChanOffs) return ((opChan[0].pan<<7)&1)|(opChan[0].pan&1); + if (ch>=extChanOffs) { + if (extMode) { + return ((lastExtChPan&2)<<7)|(lastExtChPan&1); + } else { + return DivPlatformYM2610B::getPan(extChanOffs); + } + } return DivPlatformYM2610B::getPan(ch); } @@ -762,7 +769,9 @@ void DivPlatformYM2610BExt::reset() { opChan[i].outVol=127; } - // channel 2 mode + lastExtChPan=3; + + // channel 3 mode immWrite(0x27,0x40); extMode=true; } diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index bf17659b..f0ab4699 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -152,6 +152,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { } } rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); + lastExtChPan=opChan[ch].pan; break; } case DIV_CMD_PITCH: { @@ -695,7 +696,7 @@ void DivPlatformYM2610Ext::forceIns() { } rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); if (i==extChanOffs) { - rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[0].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(lastExtChPan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } else { rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } @@ -742,7 +743,13 @@ DivMacroInt* DivPlatformYM2610Ext::getChanMacroInt(int ch) { unsigned short DivPlatformYM2610Ext::getPan(int ch) { if (ch>=4+extChanOffs) return DivPlatformYM2610::getPan(ch-3); - if (ch>=extChanOffs) return ((opChan[0].pan<<7)&1)|(opChan[0].pan&1); + if (ch>=extChanOffs) { + if (extMode) { + return ((lastExtChPan&2)<<7)|(lastExtChPan&1); + } else { + return DivPlatformYM2610::getPan(extChanOffs); + } + } return DivPlatformYM2610::getPan(ch); } @@ -762,6 +769,8 @@ void DivPlatformYM2610Ext::reset() { opChan[i].outVol=127; } + lastExtChPan=3; + // channel 2 mode immWrite(0x27,0x40); extMode=true; diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 63b575c6..6c84c8d7 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -800,13 +800,14 @@ void FurnaceGUI::drawPattern() { if (e->isRunning()) { DivChannelState* cs=e->getChanState(i); - float stereoPan=(float)(e->convertPanSplitToLinearLR(cs->panL,cs->panR,256)-128)/128.0; + unsigned short chanPan=e->getChanPan(i); + float stereoPan=(float)(e->convertPanSplitToLinear(chanPan,8,256)-128)/128.0; switch (settings.channelVolStyle) { case 1: // simple - xRight=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.9+(keyHit1[i]*0.1f); + xRight=((float)(cs->volume>>8)/(float)e->getMaxVolumeChan(i))*0.9+(keyHit1[i]*0.1f); break; case 2: { // stereo - float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f); + float amount=((float)(cs->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f); xRight=0.5+amount*(1.0+MIN(0.0,stereoPan)); xLeft=0.5-amount*(1.0-MAX(0.0,stereoPan)); break;