diff --git a/extern/opm/opm.c b/extern/opm/opm.c index 7a776fc0..79f6414c 100644 --- a/extern/opm/opm.c +++ b/extern/opm/opm.c @@ -1256,6 +1256,14 @@ static inline void OPM_Mixer(opm_t *chip) } chip->mix[0] += chip->op_mix * chip->op_mixl; chip->mix[1] += chip->op_mix * chip->op_mixr; + + if (slot<8) { + chip->op_chmix[slot&7]=0; + } + chip->op_chmix[slot&7]+=chip->op_mix*(chip->op_mixl|chip->op_mixr); + if (slot>=24) { + chip->ch_out[slot&7]=chip->op_chmix[slot&7]; + } } static inline void OPM_Noise(opm_t *chip) diff --git a/extern/opm/opm.h b/extern/opm/opm.h index fe5a1518..732f020f 100644 --- a/extern/opm/opm.h +++ b/extern/opm/opm.h @@ -141,6 +141,7 @@ typedef struct { int16_t op_fb[2]; uint8_t op_mixl; uint8_t op_mixr; + uint16_t op_chmix[8]; // Mixer @@ -161,6 +162,7 @@ typedef struct { uint8_t smp_so; uint8_t smp_sh1; uint8_t smp_sh2; + uint16_t ch_out[8]; // Noise uint32_t noise_lfsr; diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 11cff5e9..844fe67c 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -143,23 +143,29 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si static int o[2]; for (size_t h=start; hdata[oscBuf[i]->needle++]=fm.ch_out[i]; } - - OPM_Clock(&fm,NULL,NULL,NULL,NULL); - OPM_Clock(&fm,NULL,NULL,NULL,NULL); - OPM_Clock(&fm,NULL,NULL,NULL,NULL); - OPM_Clock(&fm,o,NULL,NULL,NULL); if (o[0]<-32768) o[0]=-32768; if (o[0]>32767) o[0]=32767; @@ -725,6 +731,10 @@ void* DivPlatformArcade::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformArcade::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformArcade::getRegisterPool() { return regPool; } @@ -792,10 +802,9 @@ void DivPlatformArcade::setFlags(unsigned int flags) { chipClock=COLOR_NTSC; baseFreqOff=0; } - if (useYMFM) { - rate=chipClock/64; - } else { - rate=chipClock/8; + rate=chipClock/64; + for (int i=0; i<8; i++) { + oscBuf[i]->rate=rate; } } @@ -813,6 +822,7 @@ int DivPlatformArcade::init(DivEngine* p, int channels, int sugRate, unsigned in skipRegisterWrites=false; for (int i=0; i<8; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); if (useYMFM) fm_ymfm=new ymfm::ym2151(iface); @@ -822,6 +832,9 @@ int DivPlatformArcade::init(DivEngine* p, int channels, int sugRate, unsigned in } void DivPlatformArcade::quit() { + for (int i=0; i<8; i++) { + delete oscBuf[i]; + } if (useYMFM) { delete fm_ymfm; } diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 68f6baad..6f68eeda 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -70,6 +70,7 @@ class DivPlatformArcade: public DivDispatch { chVolR(127) {} }; Channel chan[8]; + DivDispatchOscBuffer* oscBuf[8]; struct QueuedWrite { unsigned short addr; unsigned char val; @@ -108,6 +109,7 @@ class DivPlatformArcade: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); void reset(); diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index b4b92645..27efab75 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -144,7 +144,8 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1]; //OPN2_Write(&fm,0,0); - } + oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7; + } os[0]=(os[0]<<5); if (os[0]<-32768) os[0]=-32768; @@ -844,6 +845,10 @@ void* DivPlatformGenesis::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformGenesis::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformGenesis::getRegisterPool() { return regPool; } @@ -956,6 +961,9 @@ void DivPlatformGenesis::setFlags(unsigned int flags) { } else { rate=chipClock/36; } + for (int i=0; i<10; i++) { + oscBuf[i]->rate=rate; + } } int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { @@ -965,6 +973,7 @@ int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, unsigned i skipRegisterWrites=false; for (int i=0; i<10; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } fm_ymfm=NULL; setFlags(flags); @@ -974,6 +983,9 @@ int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, unsigned i } void DivPlatformGenesis::quit() { + for (int i=0; i<10; i++) { + delete oscBuf[i]; + } if (fm_ymfm!=NULL) delete fm_ymfm; } diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 0482ea0a..236e5c43 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -68,6 +68,7 @@ class DivPlatformGenesis: public DivDispatch { pan(3) {} }; Channel chan[10]; + DivDispatchOscBuffer* oscBuf[10]; bool isMuted[10]; struct QueuedWrite { unsigned short addr; @@ -110,6 +111,7 @@ class DivPlatformGenesis: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); void reset(); diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index e67c353d..d5c98a56 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -391,6 +391,12 @@ void* DivPlatformGenesisExt::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformGenesisExt::getOscBuffer(int ch) { + if (ch>=6) return oscBuf[ch-3]; + if (ch<3) return oscBuf[ch]; + return NULL; +} + void DivPlatformGenesisExt::reset() { DivPlatformGenesis::reset(); diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index c246ee3f..b482663c 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -54,6 +54,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { public: int dispatch(DivCommand c); void* getChanState(int chan); + DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); void tick(bool sysTick=true); diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 3e385434..33c59eeb 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -52,6 +52,10 @@ const unsigned short chanMapOPL2Drums[20]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 7, N, N, N, N, N, N, N, N, N }; +const unsigned char outChanMapOPL2[18]={ + 0, 1, 2, 3, 4, 5, 6, 7, 8, N, N, N, N, N, N, N, N, N +}; + const unsigned char* slotsOPL2[4]={ slotsOPL2i[0], slotsOPL2i[1], @@ -88,6 +92,10 @@ const unsigned short chanMapOPL3Drums[20]={ 0, 3, 1, 4, 2, 5, 0x100, 0x103, 0x101, 0x104, 0x102, 0x105, 0x106, 0x107, 0x108, 6, 7, 8, 8, 7 }; +const unsigned char outChanMapOPL3[18]={ + 0, 3, 1, 4, 2, 5, 9, 12, 10, 13, 11, 14, 15, 16, 17, 6, 7, 8 +}; + const unsigned char* slotsOPL3[4]={ slotsOPL3i[0], slotsOPL3i[1], @@ -208,6 +216,20 @@ void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_ } OPL3_Generate(&fm,o); os[0]+=o[0]; os[1]+=o[1]; + + for (int i=0; idata[oscBuf[i]->needle]=0; + if (fm.channel[i].out[0]!=NULL) { + oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[0]; + } + if (fm.channel[i].out[1]!=NULL) { + oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[1]; + } + oscBuf[i]->data[oscBuf[i]->needle]<<=1; + oscBuf[i]->needle++; + } if (os[0]<-32768) os[0]=-32768; if (os[0]>32767) os[0]=32767; @@ -917,6 +939,10 @@ void* DivPlatformOPL::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformOPL::getRegisterPool() { return regPool; } @@ -1034,6 +1060,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { slotsDrums=slotsOPL2Drums; slots=drums?slotsDrums:slotsNonDrums; chanMap=drums?chanMapOPL2Drums:chanMapOPL2; + outChanMap=outChanMapOPL2; chipFreqBase=9440540*0.25; chans=9; melodicChans=drums?6:9; @@ -1044,6 +1071,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) { slotsDrums=slotsOPL3Drums; slots=drums?slotsDrums:slotsNonDrums; chanMap=drums?chanMapOPL3Drums:chanMapOPL3; + outChanMap=outChanMapOPL3; chipFreqBase=9440540; chans=18; melodicChans=drums?15:18; @@ -1096,6 +1124,10 @@ void DivPlatformOPL::setFlags(unsigned int flags) { rate=48000; chipClock=rate*288; } + + for (int i=0; i<18; i++) { + oscBuf[i]->rate=rate; + } } int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { @@ -1105,6 +1137,9 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int f for (int i=0; i<20; i++) { isMuted[i]=false; } + for (int i=0; i<18; i++) { + oscBuf[i]=new DivDispatchOscBuffer; + } setFlags(flags); reset(); @@ -1112,6 +1147,9 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int f } void DivPlatformOPL::quit() { + for (int i=0; i<18; i++) { + delete oscBuf[i]; + } } DivPlatformOPL::~DivPlatformOPL() { diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index eeef111f..8f8dad37 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -62,6 +62,7 @@ class DivPlatformOPL: public DivDispatch { } }; Channel chan[20]; + DivDispatchOscBuffer* oscBuf[18]; bool isMuted[20]; struct QueuedWrite { unsigned short addr; @@ -75,6 +76,7 @@ class DivPlatformOPL: public DivDispatch { const unsigned char** slotsDrums; const unsigned char** slots; const unsigned short* chanMap; + const unsigned char* outChanMap; double chipFreqBase; int delay, oplType, chans, melodicChans, totalChans; unsigned char lastBusy; @@ -104,6 +106,7 @@ class DivPlatformOPL: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); void reset(); diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index f02ad40b..0e4e92d6 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -735,6 +735,7 @@ void* DivPlatformOPLL::getChanState(int ch) { } DivDispatchOscBuffer* DivPlatformOPLL::getOscBuffer(int ch) { + if (ch>=9) return NULL; return oscBuf[ch]; } diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index d0a19d1d..f1c66163 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -42,7 +42,16 @@ const char* DivPlatformSMS::getEffectName(unsigned char effect) { } void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len) { - sn->sound_stream_update(bufL+start,len); + for (size_t h=start; hsound_stream_update(bufL+h,1); + for (int i=0; i<4; i++) { + if (isMuted[i]) { + oscBuf[i]->data[oscBuf[i]->needle++]=0; + } else { + oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i); + } + } + } } int DivPlatformSMS::acquireOne() { @@ -287,6 +296,10 @@ void* DivPlatformSMS::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformSMS::getOscBuffer(int ch) { + return oscBuf[ch]; +} + void DivPlatformSMS::reset() { for (int i=0; i<4; i++) { chan[i]=DivPlatformSMS::Channel(); @@ -359,6 +372,9 @@ void DivPlatformSMS::setFlags(unsigned int flags) { break; } rate=chipClock/16; + for (int i=0; i<4; i++) { + oscBuf[i]->rate=rate; + } } int DivPlatformSMS::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { @@ -369,6 +385,7 @@ int DivPlatformSMS::init(DivEngine* p, int channels, int sugRate, unsigned int f oldValue=0xff; for (int i=0; i<4; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } sn=NULL; setFlags(flags); @@ -377,6 +394,9 @@ int DivPlatformSMS::init(DivEngine* p, int channels, int sugRate, unsigned int f } void DivPlatformSMS::quit() { + for (int i=0; i<4; i++) { + delete oscBuf[i]; + } if (sn!=NULL) delete sn; } diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index a79945bd..d1b52881 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -52,6 +52,7 @@ class DivPlatformSMS: public DivDispatch { outVol(15) {} }; Channel chan[4]; + DivDispatchOscBuffer* oscBuf[4]; bool isMuted[4]; unsigned char oldValue; unsigned char snNoiseMode; @@ -65,6 +66,7 @@ class DivPlatformSMS: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); void tick(bool sysTick=true); diff --git a/src/engine/platform/sound/sn76496.h b/src/engine/platform/sound/sn76496.h index 2387574d..4c24e938 100644 --- a/src/engine/platform/sound/sn76496.h +++ b/src/engine/platform/sound/sn76496.h @@ -16,6 +16,9 @@ public: void write(u8 data); void device_start(); void sound_stream_update(short* outputs, int outLen); + inline int32_t get_channel_output(int ch) { + return ((m_output[ch]!=0)?m_volume[ch]:0); + } //DECLARE_READ_LINE_MEMBER( ready_r ) { return m_ready_state ? 1 : 0; } sn76496_base_device( diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index c4924e7e..f1248ffe 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -38,8 +38,8 @@ void FurnaceGUI::drawChanOsc() { ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f)); float availY=ImGui::GetContentRegionAvail().y; if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders)) { + std::vector oscBufs; int chans=e->getTotalChannelCount(); - int rows=(chans+(chanOscCols-1))/chanOscCols; ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 waveform[512]; @@ -48,12 +48,18 @@ void FurnaceGUI::drawChanOsc() { ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_WAVE]); for (int i=0; igetOscBuffer(i); + if (buf!=NULL) oscBufs.push_back(buf); + } + int rows=(oscBufs.size()+(chanOscCols-1))/chanOscCols; + + for (size_t i=0; igetOscBuffer(i); + DivDispatchOscBuffer* buf=oscBufs[i]; if (buf==NULL) { - ImGui::Text("Not Available"); + ImGui::Text("Error!"); } else { ImVec2 size=ImGui::GetContentRegionAvail(); size.y=availY/rows;