From a9a01bad4a130b48a50c32dbda7060cab7d97ff9 Mon Sep 17 00:00:00 2001 From: Natt Akuma <77432377+akumanatt@users.noreply.github.com> Date: Fri, 29 Apr 2022 16:32:30 +0700 Subject: [PATCH 01/16] Have host sound chip appear before expansions So that they are consistent with NES expansions. For X16, the VERA is more integral to the system and has lower I/O address than YM2151 and YM2151 was once an expansion chip during development. --- src/gui/presets.cpp | 46 ++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index d6e439a68..77bd9b10c 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -366,29 +366,29 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "Commodore 64 (6581 SID + Sound Expander)", { - DIV_SYSTEM_OPL, 64, 0, 0, DIV_SYSTEM_C64_6581, 64, 0, 1, + DIV_SYSTEM_OPL, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Commodore 64 (6581 SID + Sound Expander with drums mode)", { - DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, DIV_SYSTEM_C64_6581, 64, 0, 1, + DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Commodore 64 (8580 SID + Sound Expander)", { - DIV_SYSTEM_OPL, 64, 0, 0, DIV_SYSTEM_C64_8580, 64, 0, 1, + DIV_SYSTEM_OPL, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Commodore 64 (8580 SID + Sound Expander with drums mode)", { - DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, DIV_SYSTEM_C64_8580, 64, 0, 1, + DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, 0 } )); @@ -406,22 +406,22 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "MSX + SFG-01", { - DIV_SYSTEM_YM2151, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 16, + DIV_SYSTEM_YM2151, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "MSX + MSX-MUSIC", { - DIV_SYSTEM_OPLL, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 16, + DIV_SYSTEM_OPLL, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "MSX + MSX-MUSIC (drums mode)", { - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 16, + DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, 0 } )); @@ -463,101 +463,101 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "PC + Covox Sound Master", { - DIV_SYSTEM_AY8930, 64, 0, 3, DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_AY8930, 64, 0, 3, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + SSI 2001", { - DIV_SYSTEM_C64_6581, 64, 0, 2, DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_C64_6581, 64, 0, 2, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Game Blaster", { - DIV_SYSTEM_SAA1099, 64, 0, 1, - DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_SAA1099, 64, 0, 1, + DIV_SYSTEM_SAA1099, 64, 0, 1, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + AdLib/Sound Blaster", { - DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_OPL2, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + AdLib/Sound Blaster (drums mode)", { - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster w/Game Blaster Compatible", { + DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, - DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster w/Game Blaster Compatible (drums mode)", { + DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, - DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro", { + DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL2, 64, -127, 0, DIV_SYSTEM_OPL2, 64, 127, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro (drums mode)", { + DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL2_DRUMS, 64, -127, 0, DIV_SYSTEM_OPL2_DRUMS, 64, 127, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro 2", { - DIV_SYSTEM_OPL3, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_OPL3, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro 2 (drums mode)", { - DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + PC-FXGA", { - DIV_SYSTEM_PCE, 64, 0, 0, // HuC6230 (WSG from HuC6280 but with built in 2 OKI ADPCM playback engines) DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_PCE, 64, 0, 0, // HuC6230 (WSG from HuC6280 but with built in 2 OKI ADPCM playback engines) 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + SAAYM", { + DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_YM2151, 64, 0, 0, // 3.58MHz or 4MHz selectable via jumper DIV_SYSTEM_SAA1099, 64, 0, 1, // 7.16MHz or 8MHz selectable via jumper DIV_SYSTEM_SAA1099, 64, 0, 1, // "" - DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -584,8 +584,8 @@ void FurnaceGUI::initSystemPresets() { ));*/ cat.systems.push_back(FurnaceGUISysDef( "Commander X16", { - DIV_SYSTEM_YM2151, 64, 0, 0, DIV_SYSTEM_VERA, 64, 0, 0, + DIV_SYSTEM_YM2151, 64, 0, 0, 0 } )); @@ -651,8 +651,8 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "Seta 1 + FM addon", { - DIV_SYSTEM_YM2612, 64, 0, 2, // Discrete YM3438 DIV_SYSTEM_X1_010, 64, 0, 0, + DIV_SYSTEM_YM2612, 64, 0, 2, // Discrete YM3438 0 } )); From 9f49504891fce169100fa7de1a71d759f357411d Mon Sep 17 00:00:00 2001 From: Natt Akuma <77432377+akumanatt@users.noreply.github.com> Date: Sat, 30 Apr 2022 11:59:47 +0700 Subject: [PATCH 02/16] Revert PC speaker presets --- src/gui/presets.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 77bd9b10c..3dd24e0af 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -463,101 +463,101 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "PC + Covox Sound Master", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_AY8930, 64, 0, 3, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + SSI 2001", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_C64_6581, 64, 0, 2, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Game Blaster", { + DIV_SYSTEM_SAA1099, 64, 0, 1, + DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_PCSPKR, 64, 0, 0, - DIV_SYSTEM_SAA1099, 64, 0, 1, - DIV_SYSTEM_SAA1099, 64, 0, 1, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + AdLib/Sound Blaster", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL2, 64, 0, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + AdLib/Sound Blaster (drums mode)", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster w/Game Blaster Compatible", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster w/Game Blaster Compatible (drums mode)", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL2, 64, -127, 0, DIV_SYSTEM_OPL2, 64, 127, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro (drums mode)", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL2_DRUMS, 64, -127, 0, DIV_SYSTEM_OPL2_DRUMS, 64, 127, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro 2", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL3, 64, 0, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro 2 (drums mode)", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + PC-FXGA", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_PCE, 64, 0, 0, // HuC6230 (WSG from HuC6280 but with built in 2 OKI ADPCM playback engines) + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "PC + SAAYM", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_YM2151, 64, 0, 0, // 3.58MHz or 4MHz selectable via jumper DIV_SYSTEM_SAA1099, 64, 0, 1, // 7.16MHz or 8MHz selectable via jumper DIV_SYSTEM_SAA1099, 64, 0, 1, // "" + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); From c738ece3746f334edbbaaec1eb618f15ca0dee88 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 30 Apr 2022 14:36:12 -0500 Subject: [PATCH 03/16] per-channel oscilloscope, part 2 AY8930, K00, C64 and NES --- src/engine/platform/ay8930.cpp | 20 +++++++++++++++++++- src/engine/platform/ay8930.h | 2 ++ src/engine/platform/bubsyswsg.cpp | 19 +++++++++++++++++-- src/engine/platform/bubsyswsg.h | 2 ++ src/engine/platform/c64.cpp | 18 ++++++++++++++++++ src/engine/platform/c64.h | 3 +++ src/engine/platform/nes.cpp | 20 ++++++++++++++++++++ src/engine/platform/nes.h | 3 +++ src/engine/platform/sound/c64/sid.cc | 18 ++++++++++++++++-- src/engine/platform/sound/c64/sid.h | 2 ++ 10 files changed, 102 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index e0cbd9803..13308698c 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -149,6 +149,12 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l 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]; + } + } } void DivPlatformAY8930::updateOutSel(bool immediate) { @@ -523,6 +529,10 @@ void* DivPlatformAY8930::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformAY8930::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformAY8930::getRegisterPool() { return regPool; } @@ -629,6 +639,10 @@ void DivPlatformAY8930::setFlags(unsigned int flags) { break; } rate=chipClock/8; + for (int i=0; i<3; i++) { + oscBuf[i]->rate=rate; + } + stereo=flags>>6; } @@ -638,6 +652,7 @@ int DivPlatformAY8930::init(DivEngine* p, int channels, int sugRate, unsigned in skipRegisterWrites=false; for (int i=0; i<3; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); ay=new ay8930_device(rate); @@ -649,6 +664,9 @@ int DivPlatformAY8930::init(DivEngine* p, int channels, int sugRate, unsigned in } void DivPlatformAY8930::quit() { - for (int i=0; i<3; i++) delete[] ayBuf[i]; + for (int i=0; i<3; i++) { + delete oscBuf[i]; + delete[] ayBuf[i]; + } delete ay; } diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index ced107fcf..ff992bb5e 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -52,6 +52,7 @@ class DivPlatformAY8930: public DivDispatch { }; std::queue writes; ay8930_device* ay; + DivDispatchOscBuffer* oscBuf[3]; unsigned char regPool[32]; unsigned char ayNoiseAnd, ayNoiseOr; bool bank; @@ -79,6 +80,7 @@ class DivPlatformAY8930: 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/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 3224bfee9..2c09cf23d 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -49,6 +49,7 @@ const char* DivPlatformBubSysWSG::getEffectName(unsigned char effect) { } void DivPlatformBubSysWSG::acquire(short* bufL, short* bufR, size_t start, size_t len) { + int chanOut=0; for (size_t h=start; haddr(i)]*(regPool[2+i]&0xf); + if (isMuted[i]) { + oscBuf[i]->data[oscBuf[i]->needle++]=0; + continue; + } else { + chanOut=chan[i].waveROM[k005289->addr(i)]*(regPool[2+i]&0xf); + out+=chanOut; + oscBuf[i]->data[oscBuf[i]->needle++]=chanOut; + } } out<<=6; // scale output to 16 bit @@ -267,6 +274,10 @@ void* DivPlatformBubSysWSG::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformBubSysWSG::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformBubSysWSG::getRegisterPool() { return (unsigned char*)regPool; } @@ -335,6 +346,7 @@ int DivPlatformBubSysWSG::init(DivEngine* p, int channels, int sugRate, unsigned skipRegisterWrites=false; for (int i=0; i<2; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); k005289=new k005289_core(); @@ -343,6 +355,9 @@ int DivPlatformBubSysWSG::init(DivEngine* p, int channels, int sugRate, unsigned } void DivPlatformBubSysWSG::quit() { + for (int i=0; i<2; i++) { + delete oscBuf[i]; + } delete k005289; } diff --git a/src/engine/platform/bubsyswsg.h b/src/engine/platform/bubsyswsg.h index a28b4ac1d..8eb6726fa 100644 --- a/src/engine/platform/bubsyswsg.h +++ b/src/engine/platform/bubsyswsg.h @@ -56,6 +56,7 @@ class DivPlatformBubSysWSG: public DivDispatch { wave(-1) {} }; Channel chan[2]; + DivDispatchOscBuffer* oscBuf[2]; bool isMuted[2]; k005289_core* k005289; @@ -66,6 +67,7 @@ class DivPlatformBubSysWSG: 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(); int getRegisterPoolDepth(); diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 7e9cf4d18..63f1b4709 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -112,6 +112,12 @@ void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len) for (size_t i=start; i=8) { + writeOscBuf=0; + oscBuf[0]->data[oscBuf[0]->needle++]=sid.last_chan_out[0]; + oscBuf[1]->data[oscBuf[1]->needle++]=sid.last_chan_out[1]; + oscBuf[2]->data[oscBuf[2]->needle++]=sid.last_chan_out[2]; + } } } @@ -485,6 +491,10 @@ void* DivPlatformC64::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformC64::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformC64::getRegisterPool() { return regPool; } @@ -545,14 +555,19 @@ void DivPlatformC64::setFlags(unsigned int flags) { break; } chipClock=rate; + for (int i=0; i<3; i++) { + oscBuf[i]->rate=rate/16; + } } int DivPlatformC64::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { parent=p; dumpWrites=false; skipRegisterWrites=false; + writeOscBuf=0; for (int i=0; i<3; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); @@ -562,6 +577,9 @@ int DivPlatformC64::init(DivEngine* p, int channels, int sugRate, unsigned int f } void DivPlatformC64::quit() { + for (int i=0; i<3; i++) { + delete oscBuf[i]; + } } DivPlatformC64::~DivPlatformC64() { diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index a4968fee5..495da461d 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -70,9 +70,11 @@ class DivPlatformC64: public DivDispatch { vol(15) {} }; Channel chan[3]; + DivDispatchOscBuffer* oscBuf[3]; bool isMuted[3]; unsigned char filtControl, filtRes, vol; + unsigned char writeOscBuf; int filtCut, resetTime; SID sid; @@ -85,6 +87,7 @@ class DivPlatformC64: 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/nes.cpp b/src/engine/platform/nes.cpp index f7a290662..ca528d82a 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -115,6 +115,14 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) if (sample>32767) sample=32767; if (sample<-32768) sample=-32768; bufL[i]=sample; + if (++writeOscBuf>=32) { + writeOscBuf=0; + oscBuf[0]->data[oscBuf[0]->needle++]=nes->S1.output<<7; + oscBuf[1]->data[oscBuf[1]->needle++]=nes->S2.output<<7; + oscBuf[2]->data[oscBuf[2]->needle++]=nes->TR.output<<7; + oscBuf[3]->data[oscBuf[3]->needle++]=nes->NS.output<<7; + oscBuf[4]->data[oscBuf[4]->needle++]=nes->DMC.output<<7; + } } } @@ -474,6 +482,10 @@ void* DivPlatformNES::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformNES::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformNES::getRegisterPool() { return regPool; } @@ -533,6 +545,9 @@ void DivPlatformNES::setFlags(unsigned int flags) { nes->apu.type=apuType; } chipClock=rate; + for (int i=0; i<5; i++) { + oscBuf[i]->rate=rate/32; + } } void DivPlatformNES::notifyInsDeletion(void* ins) { @@ -555,9 +570,11 @@ int DivPlatformNES::init(DivEngine* p, int channels, int sugRate, unsigned int f dumpWrites=false; skipRegisterWrites=false; nes=new struct NESAPU; + writeOscBuf=0; for (int i=0; i<5; i++) { isMuted[i]=false; nes->muted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); @@ -567,6 +584,9 @@ int DivPlatformNES::init(DivEngine* p, int channels, int sugRate, unsigned int f } void DivPlatformNES::quit() { + for (int i=0; i<5; i++) { + delete oscBuf[i]; + } delete nes; } diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index d88b447f4..abd23da99 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -57,11 +57,13 @@ class DivPlatformNES: public DivDispatch { wave(-1) {} }; Channel chan[5]; + DivDispatchOscBuffer* oscBuf[5]; bool isMuted[5]; int dacPeriod, dacRate; unsigned int dacPos, dacAntiClick; int dacSample; unsigned char sampleBank; + unsigned char writeOscBuf; unsigned char apuType; bool dacAntiClickOn; struct NESAPU* nes; @@ -73,6 +75,7 @@ class DivPlatformNES: 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/sound/c64/sid.cc b/src/engine/platform/sound/c64/sid.cc index d33a0d350..d6ebbb449 100644 --- a/src/engine/platform/sound/c64/sid.cc +++ b/src/engine/platform/sound/c64/sid.cc @@ -44,6 +44,10 @@ SID::SID() isMuted[0]=false; isMuted[1]=false; isMuted[2]=false; + + last_chan_out[0]=0; + last_chan_out[1]=0; + last_chan_out[2]=0; } @@ -638,8 +642,13 @@ void SID::clock() voice[i].wave.synchronize(); } + // write voice output + last_chan_out[0]=isMuted[0]?0:voice[0].output(); + last_chan_out[1]=isMuted[1]?0:voice[1].output(); + last_chan_out[2]=isMuted[2]?0:voice[2].output(); + // Clock filter. - filter.clock(isMuted[0]?0:voice[0].output(), isMuted[1]?0:voice[1].output(), isMuted[2]?0:voice[2].output(), ext_in); + filter.clock(last_chan_out[0], last_chan_out[1], last_chan_out[2], ext_in); // Clock external filter. extfilt.clock(filter.output()); @@ -717,9 +726,14 @@ void SID::clock(cycle_count delta_t) delta_t_osc -= delta_t_min; } + // write voice output + last_chan_out[0]=isMuted[0]?0:voice[0].output(); + last_chan_out[1]=isMuted[1]?0:voice[1].output(); + last_chan_out[2]=isMuted[2]?0:voice[2].output(); + // Clock filter. filter.clock(delta_t, - isMuted[0]?0:voice[0].output(), isMuted[1]?0:voice[1].output(), isMuted[2]?0:voice[2].output(), ext_in); + last_chan_out[0], last_chan_out[1], last_chan_out[2], ext_in); // Clock external filter. extfilt.clock(delta_t, filter.output()); diff --git a/src/engine/platform/sound/c64/sid.h b/src/engine/platform/sound/c64/sid.h index 6dbe6c599..f6b392713 100644 --- a/src/engine/platform/sound/c64/sid.h +++ b/src/engine/platform/sound/c64/sid.h @@ -32,6 +32,8 @@ public: SID(); ~SID(); + sound_sample last_chan_out[3]; + void set_is_muted(int ch, bool val); void set_chip_model(chip_model model); void enable_filter(bool enable); From 312a0378160af7cf8af191f0b2f875ea26bec368 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 30 Apr 2022 17:50:38 -0500 Subject: [PATCH 04/16] GUI: add missing actions to settings --- src/gui/settings.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 9eeeeae9d..152f94b8c 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1412,6 +1412,7 @@ void FurnaceGUI::drawSettings() { UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_MIXER); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_DEBUG); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_OSCILLOSCOPE); + UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_CHAN_OSC); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_VOL_METER); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_STATS); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_COMPAT_FLAGS); @@ -1517,6 +1518,10 @@ void FurnaceGUI::drawSettings() { UI_KEYBIND_CONFIG(GUI_ACTION_PAT_NOTE_DOWN); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_OCTAVE_UP); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_OCTAVE_DOWN); + UI_KEYBIND_CONFIG(GUI_ACTION_PAT_VALUE_UP); + UI_KEYBIND_CONFIG(GUI_ACTION_PAT_VALUE_DOWN); + UI_KEYBIND_CONFIG(GUI_ACTION_PAT_VALUE_UP_COARSE); + UI_KEYBIND_CONFIG(GUI_ACTION_PAT_VALUE_DOWN_COARSE); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_SELECT_ALL); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_CUT); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_COPY); From 1c3dcae05e9aa98e0ec6cded73578d4ddba62418 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 30 Apr 2022 18:33:12 -0500 Subject: [PATCH 05/16] per-channel oscilloscope, part 3 K00/C64/NES fixed FDS, Game Boy and Sound Unit --- src/engine/platform/bubsyswsg.cpp | 10 +++++++++- src/engine/platform/bubsyswsg.h | 1 + src/engine/platform/c64.cpp | 6 +++--- src/engine/platform/fds.cpp | 12 ++++++++++++ src/engine/platform/fds.h | 3 +++ src/engine/platform/gb.cpp | 17 +++++++++++++++-- src/engine/platform/gb.h | 2 ++ src/engine/platform/nes.cpp | 10 +++++----- src/engine/platform/sound/su.h | 6 ++++++ src/engine/platform/su.cpp | 14 ++++++++++++++ src/engine/platform/su.h | 2 ++ 11 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 2c09cf23d..b12a92ed4 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -63,10 +63,14 @@ void DivPlatformBubSysWSG::acquire(short* bufL, short* bufR, size_t start, size_ } else { chanOut=chan[i].waveROM[k005289->addr(i)]*(regPool[2+i]&0xf); out+=chanOut; - oscBuf[i]->data[oscBuf[i]->needle++]=chanOut; + if (writeOscBuf==0) { + oscBuf[i]->data[oscBuf[i]->needle++]=chanOut<<7; + } } } + if (++writeOscBuf>=64) writeOscBuf=0; + out<<=6; // scale output to 16 bit if (out<-32768) out=-32768; @@ -330,6 +334,9 @@ void DivPlatformBubSysWSG::notifyInsDeletion(void* ins) { void DivPlatformBubSysWSG::setFlags(unsigned int flags) { chipClock=COLOR_NTSC; rate=chipClock; + for (int i=0; i<2; i++) { + oscBuf[i]->rate=rate/64; + } } void DivPlatformBubSysWSG::poke(unsigned int addr, unsigned short val) { @@ -344,6 +351,7 @@ int DivPlatformBubSysWSG::init(DivEngine* p, int channels, int sugRate, unsigned parent=p; dumpWrites=false; skipRegisterWrites=false; + writeOscBuf=0; for (int i=0; i<2; i++) { isMuted[i]=false; oscBuf[i]=new DivDispatchOscBuffer; diff --git a/src/engine/platform/bubsyswsg.h b/src/engine/platform/bubsyswsg.h index 8eb6726fa..cb30d85c0 100644 --- a/src/engine/platform/bubsyswsg.h +++ b/src/engine/platform/bubsyswsg.h @@ -58,6 +58,7 @@ class DivPlatformBubSysWSG: public DivDispatch { Channel chan[2]; DivDispatchOscBuffer* oscBuf[2]; bool isMuted[2]; + unsigned char writeOscBuf; k005289_core* k005289; unsigned short regPool[4]; diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 63f1b4709..c0efdd6f2 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -114,9 +114,9 @@ void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len) bufL[i]=sid.output(); if (++writeOscBuf>=8) { writeOscBuf=0; - oscBuf[0]->data[oscBuf[0]->needle++]=sid.last_chan_out[0]; - oscBuf[1]->data[oscBuf[1]->needle++]=sid.last_chan_out[1]; - oscBuf[2]->data[oscBuf[2]->needle++]=sid.last_chan_out[2]; + oscBuf[0]->data[oscBuf[0]->needle++]=sid.last_chan_out[0]>>5; + oscBuf[1]->data[oscBuf[1]->needle++]=sid.last_chan_out[1]>>5; + oscBuf[2]->data[oscBuf[2]->needle++]=sid.last_chan_out[2]>>5; } } } diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index f1e2bfdec..4c8e92b38 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -85,6 +85,10 @@ void DivPlatformFDS::acquire(short* bufL, short* bufR, size_t start, size_t len) if (sample>32767) sample=32767; if (sample<-32768) sample=-32768; bufL[i]=sample; + if (++writeOscBuf>=32) { + writeOscBuf=0; + oscBuf->data[oscBuf->needle++]=sample<<1; + } } } @@ -396,6 +400,10 @@ void* DivPlatformFDS::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformFDS::getOscBuffer(int ch) { + return oscBuf; +} + unsigned char* DivPlatformFDS::getRegisterPool() { return regPool; } @@ -436,6 +444,7 @@ void DivPlatformFDS::setFlags(unsigned int flags) { rate=COLOR_NTSC/2.0; } chipClock=rate; + oscBuf->rate=rate/32; } void DivPlatformFDS::notifyInsDeletion(void* ins) { @@ -457,7 +466,9 @@ int DivPlatformFDS::init(DivEngine* p, int channels, int sugRate, unsigned int f apuType=flags; dumpWrites=false; skipRegisterWrites=false; + writeOscBuf=0; fds=new struct _fds; + oscBuf=new DivDispatchOscBuffer; for (int i=0; i<1; i++) { isMuted[i]=false; } @@ -468,6 +479,7 @@ int DivPlatformFDS::init(DivEngine* p, int channels, int sugRate, unsigned int f } void DivPlatformFDS::quit() { + delete oscBuf; delete fds; } diff --git a/src/engine/platform/fds.h b/src/engine/platform/fds.h index ed0c77d72..c7c53aea2 100644 --- a/src/engine/platform/fds.h +++ b/src/engine/platform/fds.h @@ -64,9 +64,11 @@ class DivPlatformFDS: public DivDispatch { } }; Channel chan[1]; + DivDispatchOscBuffer* oscBuf; bool isMuted[1]; DivWaveSynth ws; unsigned char apuType; + unsigned char writeOscBuf; struct _fds* fds; unsigned char regPool[128]; @@ -78,6 +80,7 @@ class DivPlatformFDS: 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/gb.cpp b/src/engine/platform/gb.cpp index e55e703ef..1fc2b278e 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -87,6 +87,10 @@ void DivPlatformGB::acquire(short* bufL, short* bufR, size_t start, size_t len) GB_advance_cycles(gb,16); bufL[i]=gb->apu_output.final_sample.left; bufR[i]=gb->apu_output.final_sample.right; + + for (int i=0; i<4; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=(gb->apu_output.current_sample[i].left+gb->apu_output.current_sample[i].right)<<6; + } } } @@ -429,6 +433,10 @@ void* DivPlatformGB::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformGB::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformGB::getRegisterPool() { return regPool; } @@ -495,20 +503,25 @@ void DivPlatformGB::poke(std::vector& wlist) { } int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { + chipClock=4194304; + rate=chipClock/16; for (int i=0; i<4; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; + oscBuf[i]->rate=rate; } parent=p; dumpWrites=false; skipRegisterWrites=false; - chipClock=4194304; - rate=chipClock/16; gb=new GB_gameboy_t; reset(); return 4; } void DivPlatformGB::quit() { + for (int i=0; i<4; i++) { + delete oscBuf[i]; + } delete gb; } diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index 2cdbc7858..cce1ffb6c 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -57,6 +57,7 @@ class DivPlatformGB: public DivDispatch { wave(-1) {} }; Channel chan[4]; + DivDispatchOscBuffer* oscBuf[4]; bool isMuted[4]; unsigned char lastPan; DivWaveSynth ws; @@ -71,6 +72,7 @@ class DivPlatformGB: 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/nes.cpp b/src/engine/platform/nes.cpp index ca528d82a..7f35dc5bd 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -117,11 +117,11 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) bufL[i]=sample; if (++writeOscBuf>=32) { writeOscBuf=0; - oscBuf[0]->data[oscBuf[0]->needle++]=nes->S1.output<<7; - oscBuf[1]->data[oscBuf[1]->needle++]=nes->S2.output<<7; - oscBuf[2]->data[oscBuf[2]->needle++]=nes->TR.output<<7; - oscBuf[3]->data[oscBuf[3]->needle++]=nes->NS.output<<7; - oscBuf[4]->data[oscBuf[4]->needle++]=nes->DMC.output<<7; + oscBuf[0]->data[oscBuf[0]->needle++]=nes->S1.output<<11; + oscBuf[1]->data[oscBuf[1]->needle++]=nes->S2.output<<11; + oscBuf[2]->data[oscBuf[2]->needle++]=nes->TR.output<<11; + oscBuf[3]->data[oscBuf[3]->needle++]=nes->NS.output<<11; + oscBuf[4]->data[oscBuf[4]->needle++]=nes->DMC.output<<8; } } } diff --git a/src/engine/platform/sound/su.h b/src/engine/platform/sound/su.h index 972d5343e..3152e8568 100644 --- a/src/engine/platform/sound/su.h +++ b/src/engine/platform/sound/su.h @@ -88,6 +88,12 @@ class SoundUnit { bool muted[8]; void Write(unsigned char addr, unsigned char data); void NextSample(short* l, short* r); + inline int GetSample(int ch) { + int ret=(nsL[ch]+nsR[ch])>>1; + if (ret<-32768) ret=-32768; + if (ret>32767) ret=32767; + return ret; + } void Init(); void Reset(); SoundUnit(); diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 3a6003cb8..a75b7c0b8 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -99,6 +99,9 @@ void DivPlatformSoundUnit::acquire(short* bufL, short* bufR, size_t start, size_ writes.pop(); } su->NextSample(&bufL[h],&bufR[h]); + for (int i=0; i<8; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=su->GetSample(i); + } } } @@ -313,6 +316,10 @@ void* DivPlatformSoundUnit::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformSoundUnit::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformSoundUnit::getRegisterPool() { return (unsigned char*)su->chan; } @@ -365,6 +372,9 @@ void DivPlatformSoundUnit::setFlags(unsigned int flags) { chipClock=1236000; } rate=chipClock/4; + for (int i=0; i<8; i++) { + oscBuf[i]->rate=rate; + } } void DivPlatformSoundUnit::poke(unsigned int addr, unsigned short val) { @@ -381,6 +391,7 @@ int DivPlatformSoundUnit::init(DivEngine* p, int channels, int sugRate, unsigned skipRegisterWrites=false; for (int i=0; i<8; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); su=new SoundUnit(); @@ -390,6 +401,9 @@ int DivPlatformSoundUnit::init(DivEngine* p, int channels, int sugRate, unsigned } void DivPlatformSoundUnit::quit() { + for (int i=0; i<8; i++) { + delete oscBuf[i]; + } delete su; } diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index 7315f49a3..7ff3e8709 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -71,6 +71,7 @@ class DivPlatformSoundUnit: public DivDispatch { wave(0) {} }; Channel chan[8]; + DivDispatchOscBuffer* oscBuf[8]; bool isMuted[8]; struct QueuedWrite { unsigned char addr; @@ -94,6 +95,7 @@ class DivPlatformSoundUnit: 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(); From ddcd486c618aaf9253f0e8877113f1e92d0efc91 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 30 Apr 2022 20:52:48 -0500 Subject: [PATCH 06/16] YM2612: fix Furnace DAC mode glitching slides --- src/engine/platform/genesis.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 98dce6cff..b4b926454 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -647,7 +647,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { - if (c.chan==5 && chan[c.chan].furnaceDac) { + if (c.chan==5 && chan[c.chan].furnaceDac && dacMode) { int destFreq=parent->calcBaseFreq(1,1,c.value2,false); bool return2=false; if (destFreq>chan[c.chan].baseFreq) { @@ -724,7 +724,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } break; case DIV_CMD_LEGATO: { - if (c.chan==5 && chan[c.chan].furnaceDac) { + if (c.chan==5 && chan[c.chan].furnaceDac && dacMode) { chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); } else { chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); From e1fd16637c4ac0d72adad70eba0e12b39c353bb1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 30 Apr 2022 22:59:26 -0500 Subject: [PATCH 07/16] per-channel oscilloscope, part 4 OPM, OPN2, OPLL and SN plus hide unimplemented channels --- extern/opm/opm.c | 8 +++++ extern/opm/opm.h | 2 ++ src/engine/platform/arcade.cpp | 51 ++++++++++++++++++----------- src/engine/platform/arcade.h | 2 ++ src/engine/platform/genesis.cpp | 14 +++++++- src/engine/platform/genesis.h | 2 ++ src/engine/platform/genesisext.cpp | 6 ++++ src/engine/platform/genesisext.h | 1 + src/engine/platform/opl.cpp | 38 +++++++++++++++++++++ src/engine/platform/opl.h | 3 ++ src/engine/platform/opll.cpp | 1 + src/engine/platform/sms.cpp | 22 ++++++++++++- src/engine/platform/sms.h | 2 ++ src/engine/platform/sound/sn76496.h | 3 ++ src/gui/chanOsc.cpp | 12 +++++-- 15 files changed, 143 insertions(+), 24 deletions(-) diff --git a/extern/opm/opm.c b/extern/opm/opm.c index 7a776fc06..79f6414cb 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 fe5a1518b..732f020fe 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 11cff5e94..844fe67cf 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 68f6baad3..6f68eedad 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 b4b926454..27efab759 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 0482ea0a0..236e5c43f 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 e67c353d4..d5c98a56c 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 c246ee3f3..b482663c2 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 3e385434e..33c59eeb2 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 eeef111f0..8f8dad372 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 f02ad40b8..0e4e92d61 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 d0a19d1db..f1c661634 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 a79945bdd..d1b528818 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 2387574d1..4c24e938c 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 c4924e7ef..f1248ffe9 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; From dadfd7efeeacd498105b72f8b19ac29da068f8a2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 1 May 2022 00:58:10 -0500 Subject: [PATCH 08/16] but PCE supports samples! --- src/engine/sysDef.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 1f7920d7c..8f280847c 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -375,7 +375,8 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6"}, {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6"}, {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE} + {DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE}, + {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} ); sysDefs[DIV_SYSTEM_NES]=new DivSysDef( From c0e9b48b5b949cf8acc09ad55c3867638835c7ab Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 1 May 2022 02:40:03 -0500 Subject: [PATCH 09/16] per-channel oscilloscope, part 5 SAA1099 (SAASound and MAME), Lynx, MMC5, N163, PC Engine, PC Speaker, PET, QSound, WonderSwan, VERA, VIC-20, VRC6 and X1-010! --- extern/SAASound/src/SAADevice.cpp | 8 ++++- extern/SAASound/src/SAADevice.h | 2 +- extern/SAASound/src/SAAImpl.cpp | 4 +-- extern/SAASound/src/SAAImpl.h | 2 +- extern/SAASound/src/SAASndC.cpp | 2 +- extern/SAASound/src/SAASound.h | 4 ++- extern/SAASound/src/types.h | 2 ++ src/engine/platform/lynx.cpp | 14 ++++++++- src/engine/platform/lynx.h | 2 ++ src/engine/platform/mmc5.cpp | 31 +++++++++++++++---- src/engine/platform/mmc5.h | 3 ++ src/engine/platform/n163.cpp | 15 ++++++++++ src/engine/platform/n163.h | 2 ++ src/engine/platform/pce.cpp | 15 ++++++++++ src/engine/platform/pce.h | 2 ++ src/engine/platform/pcspkr.cpp | 33 ++++++++++++++++++++- src/engine/platform/pcspkr.h | 2 ++ src/engine/platform/pet.cpp | 12 ++++++++ src/engine/platform/pet.h | 3 ++ src/engine/platform/qsound.cpp | 25 ++++++++++++++-- src/engine/platform/qsound.h | 2 ++ src/engine/platform/saa.cpp | 16 ++++++++-- src/engine/platform/saa.h | 2 ++ src/engine/platform/sound/lynx/Mikey.cpp | 14 +++++++-- src/engine/platform/sound/lynx/Mikey.hpp | 5 +++- src/engine/platform/sound/n163/n163.cpp | 7 ++++- src/engine/platform/sound/n163/n163.hpp | 7 +++++ src/engine/platform/sound/pce_psg.cpp | 3 +- src/engine/platform/sound/pce_psg.h | 4 +-- src/engine/platform/sound/saa1099.cpp | 13 +++++--- src/engine/platform/sound/saa1099.h | 4 ++- src/engine/platform/sound/swan.h | 4 +-- src/engine/platform/sound/vera_psg.c | 6 ++++ src/engine/platform/sound/vera_psg.h | 1 + src/engine/platform/sound/vrcvi/vrcvi.cpp | 15 ++++++++-- src/engine/platform/sound/vrcvi/vrcvi.hpp | 3 ++ src/engine/platform/sound/x1_010/x1_010.hpp | 1 + src/engine/platform/swan.cpp | 12 ++++++++ src/engine/platform/swan.h | 2 ++ src/engine/platform/vera.cpp | 21 ++++++++++++- src/engine/platform/vera.h | 2 ++ src/engine/platform/vic20.cpp | 14 +++++++++ src/engine/platform/vic20.h | 2 ++ src/engine/platform/vrc6.cpp | 20 +++++++++++++ src/engine/platform/vrc6.h | 3 ++ src/engine/platform/x1_010.cpp | 15 ++++++++++ src/engine/platform/x1_010.h | 2 ++ 47 files changed, 345 insertions(+), 38 deletions(-) diff --git a/extern/SAASound/src/SAADevice.cpp b/extern/SAASound/src/SAADevice.cpp index 5cfb17b22..9064dcab9 100644 --- a/extern/SAASound/src/SAADevice.cpp +++ b/extern/SAASound/src/SAADevice.cpp @@ -307,7 +307,7 @@ BYTE CSAADevice::_ReadData(void) } #endif -void CSAADevice::_TickAndOutputStereo(unsigned int& left_mixed, unsigned int& right_mixed) +void CSAADevice::_TickAndOutputStereo(unsigned int& left_mixed, unsigned int& right_mixed, DivDispatchOscBuffer** oscBuf) { unsigned int temp_left, temp_right; unsigned int accum_left = 0, accum_right = 0; @@ -316,21 +316,27 @@ void CSAADevice::_TickAndOutputStereo(unsigned int& left_mixed, unsigned int& ri m_Noise0.Tick(); m_Noise1.Tick(); m_Amp0.TickAndOutputStereo(temp_left, temp_right); + oscBuf[0]->data[oscBuf[0]->needle++]=(temp_left+temp_right)<<4; accum_left += temp_left; accum_right += temp_right; m_Amp1.TickAndOutputStereo(temp_left, temp_right); + oscBuf[1]->data[oscBuf[1]->needle++]=(temp_left+temp_right)<<4; accum_left += temp_left; accum_right += temp_right; m_Amp2.TickAndOutputStereo(temp_left, temp_right); + oscBuf[2]->data[oscBuf[2]->needle++]=(temp_left+temp_right)<<4; accum_left += temp_left; accum_right += temp_right; m_Amp3.TickAndOutputStereo(temp_left, temp_right); + oscBuf[3]->data[oscBuf[3]->needle++]=(temp_left+temp_right)<<4; accum_left += temp_left; accum_right += temp_right; m_Amp4.TickAndOutputStereo(temp_left, temp_right); + oscBuf[4]->data[oscBuf[4]->needle++]=(temp_left+temp_right)<<4; accum_left += temp_left; accum_right += temp_right; m_Amp5.TickAndOutputStereo(temp_left, temp_right); + oscBuf[5]->data[oscBuf[5]->needle++]=(temp_left+temp_right)<<4; accum_left += temp_left; accum_right += temp_right; } diff --git a/extern/SAASound/src/SAADevice.h b/extern/SAASound/src/SAADevice.h index 639d90620..fe4339305 100644 --- a/extern/SAASound/src/SAADevice.h +++ b/extern/SAASound/src/SAADevice.h @@ -53,7 +53,7 @@ public: void _SetClockRate(unsigned int nClockRate); void _SetSampleRate(unsigned int nSampleRate); void _SetOversample(unsigned int nOversample); - void _TickAndOutputStereo(unsigned int& left_mixed, unsigned int& right_mixed); + void _TickAndOutputStereo(unsigned int& left_mixed, unsigned int& right_mixed, DivDispatchOscBuffer** oscBuf); void _TickAndOutputSeparate(unsigned int& left_mixed, unsigned int& right_mixed, unsigned int& left0, unsigned int& right0, unsigned int& left1, unsigned int& right1, diff --git a/extern/SAASound/src/SAAImpl.cpp b/extern/SAASound/src/SAAImpl.cpp index 455a6a18b..6602feee9 100644 --- a/extern/SAASound/src/SAAImpl.cpp +++ b/extern/SAASound/src/SAAImpl.cpp @@ -298,7 +298,7 @@ void scale_for_output(unsigned int left_input, unsigned int right_input, *pBuffer++ = (right_output >> 8) & 0x00ff; } -void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples) +void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples, DivDispatchOscBuffer** oscBuf) { unsigned int left_mixed, right_mixed; static double filterout_z1_left_mixed = 0, filterout_z1_right_mixed = 0; @@ -376,7 +376,7 @@ void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples) #endif while (nSamples--) { - m_chip._TickAndOutputStereo(left_mixed, right_mixed); + m_chip._TickAndOutputStereo(left_mixed, right_mixed, oscBuf); scale_for_output(left_mixed, right_mixed, oversample, m_bHighpass, nBoost, filterout_z1_left_mixed, filterout_z1_right_mixed, pBuffer); } diff --git a/extern/SAASound/src/SAAImpl.h b/extern/SAASound/src/SAAImpl.h index 61fa79c58..f5f58d556 100755 --- a/extern/SAASound/src/SAAImpl.h +++ b/extern/SAASound/src/SAAImpl.h @@ -68,7 +68,7 @@ public: unsigned short GetCurrentBytesPerSample(void); static unsigned short GetBytesPerSample(SAAPARAM uParam); - void GenerateMany(BYTE * pBuffer, unsigned long nSamples); + void GenerateMany(BYTE * pBuffer, unsigned long nSamples, DivDispatchOscBuffer** oscBuf); }; diff --git a/extern/SAASound/src/SAASndC.cpp b/extern/SAASound/src/SAASndC.cpp index f03e82114..747c70a73 100755 --- a/extern/SAASound/src/SAASndC.cpp +++ b/extern/SAASound/src/SAASndC.cpp @@ -81,7 +81,7 @@ unsigned long SAAAPI SAASNDGetSampleRate(SAAPARAM uParam) void SAAAPI SAASNDGenerateMany(SAASND object, BYTE * pBuffer, unsigned long nSamples) { - ((LPCSAASOUND)(object))->GenerateMany(pBuffer, nSamples); + ((LPCSAASOUND)(object))->GenerateMany(pBuffer, nSamples, NULL); } void SAAAPI SAASNDSetSampleRate(SAASND object, unsigned int nSampleRate) diff --git a/extern/SAASound/src/SAASound.h b/extern/SAASound/src/SAASound.h index c80831484..7496cc360 100644 --- a/extern/SAASound/src/SAASound.h +++ b/extern/SAASound/src/SAASound.h @@ -61,6 +61,8 @@ typedef unsigned long SAAPARAM; #ifdef __cplusplus +#include "../../src/engine/dispatch.h" + class CSAASound { public: @@ -79,7 +81,7 @@ public: virtual unsigned short GetCurrentBytesPerSample () = 0; static unsigned short GetBytesPerSample (SAAPARAM uParam); - virtual void GenerateMany (BYTE * pBuffer, unsigned long nSamples) = 0; + virtual void GenerateMany (BYTE * pBuffer, unsigned long nSamples, DivDispatchOscBuffer** oscBuf) = 0; virtual void SetClockRate(unsigned int nClockRate) = 0; virtual void SetSampleRate(unsigned int nSampleRate) = 0; diff --git a/extern/SAASound/src/types.h b/extern/SAASound/src/types.h index 4eb62f485..8cce21247 100755 --- a/extern/SAASound/src/types.h +++ b/extern/SAASound/src/types.h @@ -12,8 +12,10 @@ defined(__arm__) || \ (defined(__mips__) && defined(__MIPSEL__)) #else +#ifndef __BIG_ENDIAN #define __BIG_ENDIAN #endif +#endif #ifndef NULL diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 18a9b72fa..095710612 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -142,7 +142,7 @@ const char* DivPlatformLynx::getEffectName(unsigned char effect) { } void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len) { - mikey->sampleAudio( bufL + start, bufR + start, len ); + mikey->sampleAudio( bufL + start, bufR + start, len, oscBuf ); } void DivPlatformLynx::tick(bool sysTick) { @@ -342,6 +342,10 @@ void* DivPlatformLynx::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformLynx::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformLynx::getRegisterPool() { return const_cast( mikey->getRegisterPool() ); @@ -398,16 +402,24 @@ int DivPlatformLynx::init(DivEngine* p, int channels, int sugRate, unsigned int for (int i=0; i<4; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } chipClock = 16000000; rate = chipClock/128; + for (int i=0; i<4; i++) { + oscBuf[i]->rate=rate; + } + reset(); return 4; } void DivPlatformLynx::quit() { + for (int i=0; i<4; i++) { + delete oscBuf[i]; + } mikey.reset(); } diff --git a/src/engine/platform/lynx.h b/src/engine/platform/lynx.h index 5200fbd9c..fab8b0f82 100644 --- a/src/engine/platform/lynx.h +++ b/src/engine/platform/lynx.h @@ -74,6 +74,7 @@ class DivPlatformLynx: public DivDispatch { outVol(127) {} }; Channel chan[4]; + DivDispatchOscBuffer* oscBuf[4]; bool isMuted[4]; std::unique_ptr mikey; friend void putDispatchChan(void*,int,int); @@ -81,6 +82,7 @@ class DivPlatformLynx: 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/mmc5.cpp b/src/engine/platform/mmc5.cpp index e2aa915ed..66bead9da 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -59,7 +59,7 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len if (dacPeriod>=rate) { DivSample* s=parent->getSample(dacSample); if (s->samples>0) { - if (!isMuted[4]) { + if (!isMuted[2]) { rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80)); } if (++dacPos>=s->samples) { @@ -92,6 +92,13 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len if (sample>32767) sample=32767; if (sample<-32768) sample=-32768; bufL[i]=sample; + + if (++writeOscBuf>=32) { + writeOscBuf=0; + oscBuf[0]->data[oscBuf[0]->needle++]=isMuted[0]?0:((mmc5->S3.output*10)<<7); + oscBuf[1]->data[oscBuf[1]->needle++]=isMuted[1]?0:((mmc5->S4.output*10)<<7); + oscBuf[2]->data[oscBuf[2]->needle++]=isMuted[2]?0:((mmc5->pcm.output*2)<<6); + } } } @@ -164,18 +171,18 @@ void DivPlatformMMC5::tick(bool sysTick) { } // PCM - if (chan[4].freqChanged) { - chan[4].freq=parent->calcFreq(chan[4].baseFreq,chan[4].pitch,false); - if (chan[4].furnaceDac) { + if (chan[2].freqChanged) { + chan[2].freq=parent->calcFreq(chan[2].baseFreq,chan[2].pitch,false); + if (chan[2].furnaceDac) { double off=1.0; if (dacSample>=0 && dacSamplesong.sampleLen) { DivSample* s=parent->getSample(dacSample); off=(double)s->centerRate/8363.0; } - dacRate=MIN(chan[4].freq*off,32000); + dacRate=MIN(chan[2].freq*off,32000); if (dumpWrites) addWrite(0xffff0001,dacRate); } - chan[4].freqChanged=false; + chan[2].freqChanged=false; } } @@ -342,6 +349,10 @@ void* DivPlatformMMC5::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformMMC5::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformMMC5::getRegisterPool() { return regPool; } @@ -389,6 +400,9 @@ void DivPlatformMMC5::setFlags(unsigned int flags) { rate=COLOR_NTSC/2.0; } chipClock=rate; + for (int i=0; i<3; i++) { + oscBuf[i]->rate=rate/32; + } } void DivPlatformMMC5::notifyInsDeletion(void* ins) { @@ -410,9 +424,11 @@ int DivPlatformMMC5::init(DivEngine* p, int channels, int sugRate, unsigned int apuType=flags; dumpWrites=false; skipRegisterWrites=false; + writeOscBuf=0; mmc5=new struct _mmc5; for (int i=0; i<3; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; //mmc5->muted[i]=false; // TODO } setFlags(flags); @@ -423,6 +439,9 @@ int DivPlatformMMC5::init(DivEngine* p, int channels, int sugRate, unsigned int } void DivPlatformMMC5::quit() { + for (int i=0; i<3; i++) { + delete oscBuf[i]; + } delete mmc5; } diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index bf7eeaad5..2213b995f 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -57,12 +57,14 @@ class DivPlatformMMC5: public DivDispatch { wave(-1) {} }; Channel chan[5]; + DivDispatchOscBuffer* oscBuf[3]; bool isMuted[5]; int dacPeriod, dacRate; unsigned int dacPos; int dacSample; unsigned char sampleBank; unsigned char apuType; + unsigned char writeOscBuf; struct _mmc5* mmc5; unsigned char regPool[128]; @@ -72,6 +74,7 @@ class DivPlatformMMC5: 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/n163.cpp b/src/engine/platform/n163.cpp index 5d3c9c201..ef368203b 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -161,6 +161,10 @@ void DivPlatformN163::acquire(short* bufL, short* bufR, size_t start, size_t len if (out<-32768) out=-32768; bufL[i]=bufR[i]=out; + if (n163.voice_cycle()==0x78) for (int i=0; i<8; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=n163.chan_out(i)<<7; + } + // command queue while (!writes.empty()) { QueuedWrite w=writes.front(); @@ -619,6 +623,10 @@ void* DivPlatformN163::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformN163::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformN163::getRegisterPool() { for (int i=0; i<128; i++) { regPool[i]=n163.reg(i); @@ -678,6 +686,9 @@ void DivPlatformN163::setFlags(unsigned int flags) { rate/=15; n163.set_multiplex(multiplex); rWrite(0x7f,initChanMax<<4); + for (int i=0; i<8; i++) { + oscBuf[i]->rate=rate/(initChanMax+1); + } } int DivPlatformN163::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { @@ -686,6 +697,7 @@ int DivPlatformN163::init(DivEngine* p, int channels, int sugRate, unsigned int skipRegisterWrites=false; for (int i=0; i<8; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); @@ -695,6 +707,9 @@ int DivPlatformN163::init(DivEngine* p, int channels, int sugRate, unsigned int } void DivPlatformN163::quit() { + for (int i=0; i<8; i++) { + delete oscBuf[i]; + } } DivPlatformN163::~DivPlatformN163() { diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index d01030848..6ecb1e0c5 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -70,6 +70,7 @@ class DivPlatformN163: public DivDispatch { resVol(15) {} }; Channel chan[8]; + DivDispatchOscBuffer* oscBuf[8]; bool isMuted[8]; struct QueuedWrite { unsigned char addr; @@ -94,6 +95,7 @@ class DivPlatformN163: 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/pce.cpp b/src/engine/platform/pce.cpp index a56732bef..c28b81db7 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -116,6 +116,10 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len) pce->Update(24); pce->ResetTS(0); + for (int i=0; i<6; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=(pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1])<<1; + } + tempL[0]=(tempL[0]>>1)+(tempL[0]>>2); tempR[0]=(tempR[0]>>1)+(tempR[0]>>2); @@ -469,6 +473,10 @@ void* DivPlatformPCE::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformPCE::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformPCE::getRegisterPool() { return regPool; } @@ -541,6 +549,9 @@ void DivPlatformPCE::setFlags(unsigned int flags) { chipClock=COLOR_NTSC; } rate=chipClock/12; + for (int i=0; i<6; i++) { + oscBuf[i]->rate=rate; + } } void DivPlatformPCE::poke(unsigned int addr, unsigned short val) { @@ -557,6 +568,7 @@ int DivPlatformPCE::init(DivEngine* p, int channels, int sugRate, unsigned int f skipRegisterWrites=false; for (int i=0; i<6; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); pce=new PCE_PSG(tempL,tempR,PCE_PSG::REVISION_HUC6280A); @@ -565,6 +577,9 @@ int DivPlatformPCE::init(DivEngine* p, int channels, int sugRate, unsigned int f } void DivPlatformPCE::quit() { + for (int i=0; i<6; i++) { + delete oscBuf[i]; + } delete pce; } diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index b1b140383..58fa6600a 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -67,6 +67,7 @@ class DivPlatformPCE: public DivDispatch { wave(-1) {} }; Channel chan[6]; + DivDispatchOscBuffer* oscBuf[6]; bool isMuted[6]; struct QueuedWrite { unsigned char addr; @@ -88,6 +89,7 @@ class DivPlatformPCE: 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/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 5da1923cf..434ab10b4 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -50,6 +50,7 @@ const float cut=0.05; const float reso=0.06; void DivPlatformPCSpeaker::acquire_unfilt(short* bufL, short* bufR, size_t start, size_t len) { + int out=0; for (size_t i=start; i(freq>>1) && !isMuted[0])?32767:0; + out=(pos>(freq>>1) && !isMuted[0])?32767:0; + bufL[i]=out; + oscBuf->data[oscBuf->needle++]=out; } else { bufL[i]=0; + oscBuf->data[oscBuf->needle++]=0; } } } @@ -87,8 +91,10 @@ void DivPlatformPCSpeaker::acquire_cone(short* bufL, short* bufR, size_t start, if (out>1.0) out=1.0; if (out<-1.0) out=-1.0; bufL[i]=out*32767; + oscBuf->data[oscBuf->needle++]=out*32767; } else { bufL[i]=0; + oscBuf->data[oscBuf->needle++]=0; } } } @@ -112,8 +118,10 @@ void DivPlatformPCSpeaker::acquire_piezo(short* bufL, short* bufR, size_t start, if (out>1.0) out=1.0; if (out<-1.0) out=-1.0; bufL[i]=out*32767; + oscBuf->data[oscBuf->needle++]=out*32767; } else { bufL[i]=0; + oscBuf->data[oscBuf->needle++]=0; } } } @@ -140,12 +148,28 @@ void DivPlatformPCSpeaker::beepFreq(int freq) { } void DivPlatformPCSpeaker::acquire_real(short* bufL, short* bufR, size_t start, size_t len) { + int out=0; if (lastOn!=on || lastFreq!=freq) { lastOn=on; lastFreq=freq; beepFreq((on && !isMuted[0])?freq:0); } for (size_t i=start; ifreq) pos=freq; + while (pos<0) { + if (freq<1) { + pos=1; + } else { + pos+=freq; + } + } + out=(pos>(freq>>1) && !isMuted[0])?32767:0; + oscBuf->data[oscBuf->needle++]=out; + } else { + oscBuf->data[oscBuf->needle++]=0; + } bufL[i]=0; } } @@ -321,6 +345,10 @@ void* DivPlatformPCSpeaker::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformPCSpeaker::getOscBuffer(int ch) { + return oscBuf; +} + unsigned char* DivPlatformPCSpeaker::getRegisterPool() { if (on) { regPool[0]=freq; @@ -379,6 +407,7 @@ void DivPlatformPCSpeaker::setFlags(unsigned int flags) { chipClock=COLOR_NTSC/3.0; rate=chipClock/PCSPKR_DIVIDER; speakerType=flags&3; + oscBuf->rate=rate; } void DivPlatformPCSpeaker::notifyInsDeletion(void* ins) { @@ -407,6 +436,7 @@ int DivPlatformPCSpeaker::init(DivEngine* p, int channels, int sugRate, unsigned for (int i=0; i<1; i++) { isMuted[i]=false; } + oscBuf=new DivDispatchOscBuffer; setFlags(flags); reset(); @@ -420,6 +450,7 @@ void DivPlatformPCSpeaker::quit() { #ifdef __linux__ if (beepFD>=0) close(beepFD); #endif + delete oscBuf; } DivPlatformPCSpeaker::~DivPlatformPCSpeaker() { diff --git a/src/engine/platform/pcspkr.h b/src/engine/platform/pcspkr.h index d2c01454e..155416bb8 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -56,6 +56,7 @@ class DivPlatformPCSpeaker: public DivDispatch { wave(-1) {} }; Channel chan[1]; + DivDispatchOscBuffer* oscBuf; bool isMuted[1]; bool on, flip, lastOn; int pos, speakerType, beepFD; @@ -78,6 +79,7 @@ class DivPlatformPCSpeaker: 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/pet.cpp b/src/engine/platform/pet.cpp index 5a7efe1f9..8ddee9e86 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -64,12 +64,14 @@ void DivPlatformPET::acquire(short* bufL, short* bufR, size_t start, size_t len) } bufL[h]=chan.out; bufR[h]=chan.out; + oscBuf->data[oscBuf->needle++]=chan.out; } } else { chan.out=0; for (size_t h=start; hdata[oscBuf->needle++]=0; } } } @@ -244,6 +246,10 @@ void* DivPlatformPET::getChanState(int ch) { return &chan; } +DivDispatchOscBuffer* DivPlatformPET::getOscBuffer(int ch) { + return oscBuf; +} + unsigned char* DivPlatformPET::getRegisterPool() { return regPool; } @@ -281,9 +287,15 @@ int DivPlatformPET::init(DivEngine* p, int channels, int sugRate, unsigned int f chipClock=1000000; rate=chipClock/SAMP_DIVIDER; // = 250000kHz isMuted=false; + oscBuf=new DivDispatchOscBuffer; + oscBuf->rate=rate; reset(); return 1; } +void DivPlatformPET::quit() { + delete oscBuf; +} + DivPlatformPET::~DivPlatformPET() { } diff --git a/src/engine/platform/pet.h b/src/engine/platform/pet.h index c26ef5392..1e5e49ce5 100644 --- a/src/engine/platform/pet.h +++ b/src/engine/platform/pet.h @@ -57,6 +57,7 @@ class DivPlatformPET: public DivDispatch { out(0) {} }; Channel chan; + DivDispatchOscBuffer* oscBuf; bool isMuted; unsigned char regPool[16]; @@ -65,6 +66,7 @@ class DivPlatformPET: 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(); @@ -78,6 +80,7 @@ class DivPlatformPET: public DivDispatch { const char** getRegisterSheet(); const char* getEffectName(unsigned char effect); int init(DivEngine* parent, int channels, int sugRate, unsigned int flags); + void quit(); ~DivPlatformPET(); private: void writeOutVol(); diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index f3197f6b4..c5d003be5 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -274,6 +274,13 @@ void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t l qsound_update(&chip); bufL[h]=chip.out[0]; bufR[h]=chip.out[1]; + + for (int i=0; i<19; i++) { + int data=chip.voice_output[i]<<2; + if (data<-32768) data=-32768; + if (data>32767) data=32767; + oscBuf[i]->data[oscBuf[i]->needle++]=data; + } } } @@ -546,6 +553,10 @@ void* DivPlatformQSound::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformQSound::getOscBuffer(int ch) { + return oscBuf[ch]; +} + void DivPlatformQSound::reset() { for (int i=0; i<16; i++) { chan[i]=DivPlatformQSound::Channel(); @@ -632,9 +643,10 @@ int DivPlatformQSound::init(DivEngine* p, int channels, int sugRate, unsigned in dumpWrites=false; skipRegisterWrites=false; - //for (int i=0; i<16; i++) { - // isMuted[i]=false; - //} + for (int i=0; i<19; i++) { + oscBuf[i]=new DivDispatchOscBuffer; + //isMuted[i]=false; + } setFlags(flags); chipClock=60000000; @@ -642,8 +654,15 @@ int DivPlatformQSound::init(DivEngine* p, int channels, int sugRate, unsigned in chip.rom_data = (unsigned char*)&chip.rom_mask; chip.rom_mask = 0; reset(); + + for (int i=0; i<19; i++) { + oscBuf[i]->rate=rate; + } return 19; } void DivPlatformQSound::quit() { + for (int i=0; i<19; i++) { + delete oscBuf[i]; + } } diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index 6eb178d08..0fbce3b32 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -63,6 +63,7 @@ class DivPlatformQSound: public DivDispatch { outVol(255) {} }; Channel chan[19]; + DivDispatchOscBuffer* oscBuf[19]; int echoDelay; int echoFeedback; @@ -75,6 +76,7 @@ class DivPlatformQSound: 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(); int getRegisterPoolDepth(); diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index a083355a6..3ecf0a3ed 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -86,7 +86,7 @@ void DivPlatformSAA1099::acquire_mame(short* bufL, short* bufR, size_t start, si regPool[w.addr&0x1f]=w.val; writes.pop(); } - saa.sound_stream_update(saaBuf,len); + saa.sound_stream_update(saaBuf,len,oscBuf); for (size_t i=0; iGenerateMany((unsigned char*)saaBuf[0],len); + saa_saaSound->GenerateMany((unsigned char*)saaBuf[0],len,oscBuf); for (size_t i=0; irate=rate; + } + switch (core) { case DIV_SAA_CORE_MAME: break; @@ -516,6 +524,7 @@ int DivPlatformSAA1099::init(DivEngine* p, int channels, int sugRate, unsigned i saa_saaSound=NULL; for (int i=0; i<6; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } if (core==DIV_SAA_CORE_SAASOUND) { saa_saaSound=CreateCSAASound(); @@ -530,6 +539,9 @@ int DivPlatformSAA1099::init(DivEngine* p, int channels, int sugRate, unsigned i } void DivPlatformSAA1099::quit() { + for (int i=0; i<6; i++) { + delete oscBuf[i]; + } if (saa_saaSound!=NULL) { DestroyCSAASound(saa_saaSound); saa_saaSound=NULL; diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index 24108da79..70edaa249 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -49,6 +49,7 @@ class DivPlatformSAA1099: public DivDispatch { Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), psgMode(1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(255) {} }; Channel chan[6]; + DivDispatchOscBuffer* oscBuf[6]; bool isMuted[6]; struct QueuedWrite { unsigned short addr; @@ -90,6 +91,7 @@ class DivPlatformSAA1099: 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/sound/lynx/Mikey.cpp b/src/engine/platform/sound/lynx/Mikey.cpp index 5d12bbb86..270e21bdf 100644 --- a/src/engine/platform/sound/lynx/Mikey.cpp +++ b/src/engine/platform/sound/lynx/Mikey.cpp @@ -458,23 +458,31 @@ public: return mAudioChannels[timer].fireAction( tick ); } - AudioSample sampleAudio() const + AudioSample sampleAudio( DivDispatchOscBuffer** oscb ) const { int left{}; int right{}; for ( size_t i = 0; i < 4; ++i ) { + int oscbWrite = 0; + if ( ( mStereo & ( (uint8_t)0x01 << i ) ) == 0 ) { const int attenuation = ( mPan & ( (uint8_t)0x01 << i ) ) != 0 ? mAttenuationLeft[i] : 0x3c; left += mAudioChannels[i].getOutput() * attenuation; + oscbWrite += mAudioChannels[i].getOutput() * attenuation; } if ( ( mStereo & ( (uint8_t)0x10 << i ) ) == 0 ) { const int attenuation = ( mPan & ( (uint8_t)0x01 << i ) ) != 0 ? mAttenuationRight[i] : 0x3c; right += mAudioChannels[i].getOutput() * attenuation; + oscbWrite += mAudioChannels[i].getOutput() * attenuation; + } + + if (oscb!=NULL) { + oscb[i]->data[oscb[i]->needle++]=oscbWrite; } } @@ -534,7 +542,7 @@ void Mikey::enqueueSampling() mQueue->push( ( mNextTick & ~15 ) | 4 ); } -void Mikey::sampleAudio( int16_t* bufL, int16_t* bufR, size_t size ) +void Mikey::sampleAudio( int16_t* bufL, int16_t* bufR, size_t size, DivDispatchOscBuffer** oscb ) { size_t i = 0; while ( i < size ) @@ -549,7 +557,7 @@ void Mikey::sampleAudio( int16_t* bufL, int16_t* bufR, size_t size ) } else { - auto sample = mMikey->sampleAudio(); + auto sample = mMikey->sampleAudio( oscb ); bufL[i] = sample.left; bufR[i] = sample.right; i += 1; diff --git a/src/engine/platform/sound/lynx/Mikey.hpp b/src/engine/platform/sound/lynx/Mikey.hpp index 20b8b0868..9d0f6884e 100644 --- a/src/engine/platform/sound/lynx/Mikey.hpp +++ b/src/engine/platform/sound/lynx/Mikey.hpp @@ -3,6 +3,9 @@ #include #include +// can you forgive me +#include "../../../dispatch.h" + namespace Lynx { @@ -18,7 +21,7 @@ public: ~Mikey(); void write( uint8_t address, uint8_t value ); - void sampleAudio( int16_t* bufL, int16_t* bufR, size_t size ); + void sampleAudio( int16_t* bufL, int16_t* bufR, size_t size, DivDispatchOscBuffer** oscb = NULL ); uint8_t const* getRegisterPool(); diff --git a/src/engine/platform/sound/n163/n163.cpp b/src/engine/platform/sound/n163/n163.cpp index b18f146ba..20853963e 100644 --- a/src/engine/platform/sound/n163/n163.cpp +++ b/src/engine/platform/sound/n163/n163.cpp @@ -98,6 +98,8 @@ void n163_core::tick() m_ram[m_voice_cycle + 3] = bitfield(accum, 8, 8); m_ram[m_voice_cycle + 5] = bitfield(accum, 16, 8); + const u8 prev_voice_cycle = m_voice_cycle; + // update voice cycle bool flush = m_multiplex ? true : false; m_voice_cycle -= 0x8; @@ -109,7 +111,9 @@ void n163_core::tick() } // output 4 bit waveform and volume, multiplexed - m_acc += wave * volume; + const u8 chan_index = ((0x78-prev_voice_cycle)>>3)&7; + m_ch_out[chan_index]=wave * volume; + m_acc += m_ch_out[chan_index]; if (flush) { m_out = m_acc / (m_multiplex ? 1 : (bitfield(m_ram[0x7f], 4, 3) + 1)); @@ -127,6 +131,7 @@ void n163_core::reset() m_addr_latch.reset(); m_out = 0; m_acc = 0; + std::fill(std::begin(m_ch_out), std::end(m_ch_out), 0); } // accessor diff --git a/src/engine/platform/sound/n163/n163.hpp b/src/engine/platform/sound/n163/n163.hpp index a31827572..aa059206b 100644 --- a/src/engine/platform/sound/n163/n163.hpp +++ b/src/engine/platform/sound/n163/n163.hpp @@ -46,6 +46,12 @@ public: // sound output pin s16 out() { return m_out; } + // get channel output + s16 chan_out(u8 ch) { return m_ch_out[ch]; } + + // get voice cycle + u8 voice_cycle() { return m_voice_cycle; } + // register pool u8 reg(u8 addr) { return m_ram[addr & 0x7f]; } void set_multiplex(bool multiplex = true) { m_multiplex = multiplex; } @@ -74,6 +80,7 @@ private: u8 m_voice_cycle = 0x78; // Voice cycle for processing addr_latch_t m_addr_latch; // address latch s16 m_out = 0; // output + s16 m_ch_out[8] = {0}; // per channel output // demultiplex related bool m_multiplex = true; // multiplex flag, but less noisy = inaccurate! s16 m_acc = 0; // accumulated output diff --git a/src/engine/platform/sound/pce_psg.cpp b/src/engine/platform/sound/pce_psg.cpp index f9c1ee099..0fa9993bf 100644 --- a/src/engine/platform/sound/pce_psg.cpp +++ b/src/engine/platform/sound/pce_psg.cpp @@ -96,10 +96,11 @@ inline void PCE_PSG::UpdateOutputSub(const int32_t timestamp, psg_channel *ch, c HRBufs[1][l + 4] += delta[1] * c[4]; HRBufs[1][l + 5] += delta[1] * c[5]; HRBufs[1][l + 6] += delta[1] * c[6]; + */ ch->blip_prev_samp[0] = samp0; ch->blip_prev_samp[1] = samp1; - */ + } void PCE_PSG::UpdateOutput_Norm(const int32_t timestamp, psg_channel *ch) diff --git a/src/engine/platform/sound/pce_psg.h b/src/engine/platform/sound/pce_psg.h index 595494036..08f7f88ce 100644 --- a/src/engine/platform/sound/pce_psg.h +++ b/src/engine/platform/sound/pce_psg.h @@ -147,6 +147,8 @@ class PCE_PSG void PeekWave(const unsigned int ch, uint32_t Address, uint32_t Length, uint8_t *Buffer); void PokeWave(const unsigned int ch, uint32_t Address, uint32_t Length, const uint8_t *Buffer); + + psg_channel channel[6]; private: @@ -178,8 +180,6 @@ class PCE_PSG int32_t vol_update_vllatch; bool vol_pending; - psg_channel channel[6]; - int32_t lastts; int revision; diff --git a/src/engine/platform/sound/saa1099.cpp b/src/engine/platform/sound/saa1099.cpp index 670afb97f..918ade54c 100644 --- a/src/engine/platform/sound/saa1099.cpp +++ b/src/engine/platform/sound/saa1099.cpp @@ -164,7 +164,7 @@ void saa1099_device::device_start() // sound_stream_update - handle a stream update //------------------------------------------------- -void saa1099_device::sound_stream_update(short** outputs, int len) +void saa1099_device::sound_stream_update(short** outputs, int len, DivDispatchOscBuffer** oscBuf) { int j, ch; /* if the channels are disabled we're done */ @@ -225,9 +225,14 @@ void saa1099_device::sound_stream_update(short** outputs, int len) } if (level) { - output_l += m_channels[ch].amplitude[ LEFT] * m_channels[ch].envelope[ LEFT] / 16; - output_r += m_channels[ch].amplitude[RIGHT] * m_channels[ch].envelope[RIGHT] / 16; - } + int this_output_l = m_channels[ch].amplitude[ LEFT] * m_channels[ch].envelope[ LEFT] / 16; + int this_output_r = m_channels[ch].amplitude[RIGHT] * m_channels[ch].envelope[RIGHT] / 16; + output_l+=this_output_l; + output_r+=this_output_r; + oscBuf[ch]->data[oscBuf[ch]->needle++]=(this_output_l+this_output_r)<<1; + } else if (oscBuf!=NULL) { + oscBuf[ch]->data[oscBuf[ch]->needle++]=0; + } } for (ch = 0; ch < 2; ch++) diff --git a/src/engine/platform/sound/saa1099.h b/src/engine/platform/sound/saa1099.h index 8ebad8a30..8b7cead25 100644 --- a/src/engine/platform/sound/saa1099.h +++ b/src/engine/platform/sound/saa1099.h @@ -7,6 +7,8 @@ #ifndef MAME_SOUND_SAA1099_H #define MAME_SOUND_SAA1099_H +#include "../../dispatch.h" + //************************************************************************** // TYPE DEFINITIONS //************************************************************************** @@ -28,7 +30,7 @@ public: void device_clock_changed(); // sound stream update overrides - void sound_stream_update(short** outputs, int len); + void sound_stream_update(short** outputs, int len, DivDispatchOscBuffer** oscBuf=NULL); private: struct saa1099_channel diff --git a/src/engine/platform/sound/swan.h b/src/engine/platform/sound/swan.h index a1d01fa54..bd421a74c 100644 --- a/src/engine/platform/sound/swan.h +++ b/src/engine/platform/sound/swan.h @@ -41,6 +41,8 @@ public: void SoundUpdate(uint32_t); void RAMWrite(uint32_t, uint8_t); + + int32_t sample_cache[4][2]; private: // Blip_Synth WaveSynth; @@ -61,8 +63,6 @@ private: uint8_t sweep_counter; uint8_t SampleRAMPos; - int32_t sample_cache[4][2]; - int32_t last_v_val; uint8_t HyperVoice; diff --git a/src/engine/platform/sound/vera_psg.c b/src/engine/platform/sound/vera_psg.c index afdf69cec..19f15d4eb 100644 --- a/src/engine/platform/sound/vera_psg.c +++ b/src/engine/platform/sound/vera_psg.c @@ -86,6 +86,12 @@ render(struct VERA_PSG* psg, int16_t *left, int16_t *right) if (ch->right) { r += val; } + + if (ch->left || ch->right) { + ch->lastOut=val; + } else { + ch->lastOut=0; + } } *left = l; diff --git a/src/engine/platform/sound/vera_psg.h b/src/engine/platform/sound/vera_psg.h index 7a6a7f01d..6a3f6828b 100644 --- a/src/engine/platform/sound/vera_psg.h +++ b/src/engine/platform/sound/vera_psg.h @@ -15,6 +15,7 @@ struct VERAChannel { uint8_t waveform; unsigned phase; + int lastOut; uint8_t noiseval; }; diff --git a/src/engine/platform/sound/vrcvi/vrcvi.cpp b/src/engine/platform/sound/vrcvi/vrcvi.cpp index 19152ed74..bca3ecda3 100644 --- a/src/engine/platform/sound/vrcvi/vrcvi.cpp +++ b/src/engine/platform/sound/vrcvi/vrcvi.cpp @@ -88,13 +88,23 @@ void vrcvi_core::tick() if (!m_control.m_halt) // Halt flag { // tick per each clock + int elemIndex=0; for (auto & elem : m_pulse) { - if (elem.tick()) + if (elem.tick()) { m_out += elem.m_control.m_volume; // add 4 bit pulse output + m_ch_out[elemIndex]=elem.m_control.m_volume; + } else { + m_ch_out[elemIndex]=0; + } + elemIndex++; } - if (m_sawtooth.tick()) + if (m_sawtooth.tick()) { m_out += bitfield(m_sawtooth.m_accum, 3, 5); // add 5 bit sawtooth output + m_ch_out[2]=bitfield(m_sawtooth.m_accum, 3, 5); + } else { + m_ch_out[2]=0; + } } if (m_timer.tick()) m_timer.counter_tick(); @@ -109,6 +119,7 @@ void vrcvi_core::reset() m_timer.reset(); m_control.reset(); m_out = 0; + std::fill(std::begin(m_ch_out),std::end(m_ch_out),0); } bool vrcvi_core::alu_t::tick() diff --git a/src/engine/platform/sound/vrcvi/vrcvi.hpp b/src/engine/platform/sound/vrcvi/vrcvi.hpp index 40b4245e3..d88ba7cf9 100644 --- a/src/engine/platform/sound/vrcvi/vrcvi.hpp +++ b/src/engine/platform/sound/vrcvi/vrcvi.hpp @@ -62,6 +62,8 @@ public: // 6 bit output s8 out() { return m_out; } + // channel output + s16 chan_out(u8 ch) { return m_ch_out[ch]; } private: // Common ALU for sound channels struct alu_t @@ -233,6 +235,7 @@ private: vrcvi_intf &m_intf; s8 m_out = 0; // 6 bit output + s8 m_ch_out[3] = {0}; // per-channel output }; #endif diff --git a/src/engine/platform/sound/x1_010/x1_010.hpp b/src/engine/platform/sound/x1_010/x1_010.hpp index e8f5e3e40..f208611da 100644 --- a/src/engine/platform/sound/x1_010/x1_010.hpp +++ b/src/engine/platform/sound/x1_010/x1_010.hpp @@ -63,6 +63,7 @@ public: // getters s32 output(u8 channel) { return m_out[channel & 1]; } + s32 chan_out(u8 channel) { return (m_voice[channel].data * (m_voice[channel].vol_out[0]+m_voice[channel].vol_out[1]))<<2; } // internal state void reset(); diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 9ac07f6e6..97aa7b9ef 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -107,6 +107,9 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len ws->SoundFlush(samp, 1); bufL[h]=samp[0]; bufR[h]=samp[1]; + for (int i=0; i<4; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=(ws->sample_cache[i][0]+ws->sample_cache[i][1])<<6; + } } } @@ -457,6 +460,10 @@ void* DivPlatformSwan::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformSwan::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformSwan::getRegisterPool() { // get Random from emulator regPool[0x12]=ws->SoundRead(0x92); @@ -532,6 +539,8 @@ int DivPlatformSwan::init(DivEngine* p, int channels, int sugRate, unsigned int rate=chipClock/16; // = 192000kHz, should be enough for (int i=0; i<4; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; + oscBuf[i]->rate=rate; } ws=new WSwan(); reset(); @@ -539,6 +548,9 @@ int DivPlatformSwan::init(DivEngine* p, int channels, int sugRate, unsigned int } void DivPlatformSwan::quit() { + for (int i=0; i<4; i++) { + delete oscBuf[i]; + } delete ws; } diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index c03dd0d55..32f400e5b 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -57,6 +57,7 @@ class DivPlatformSwan: public DivDispatch { wave(-1) {} }; Channel chan[4]; + DivDispatchOscBuffer* oscBuf[4]; bool isMuted[4]; bool pcm, sweep, furnaceDac; unsigned char sampleBank, noise; @@ -78,6 +79,7 @@ class DivPlatformSwan: 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/vera.cpp b/src/engine/platform/vera.cpp index ccb819c9d..4dcc8f6c5 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -111,12 +111,20 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len } int curLen=MIN(len,128); memset(buf,0,sizeof(buf)); - psg_render(psg,buf[0],buf[1],curLen); pcm_render(pcm,buf[2],buf[3],curLen); for (int i=0; idata[oscBuf[i]->needle++]=psg->channels[i].lastOut<<4; + } + int pcmOut=buf[2][i]+buf[3][i]; + if (pcmOut<-32768) pcmOut=-32768; + if (pcmOut>32767) pcmOut=32767; + oscBuf[16]->data[oscBuf[16]->needle++]=pcmOut; } len-=curLen; } @@ -373,6 +381,10 @@ void* DivPlatformVERA::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformVERA::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformVERA::getRegisterPool() { return regPool; } @@ -426,6 +438,7 @@ void DivPlatformVERA::poke(std::vector& wlist) { int DivPlatformVERA::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { for (int i=0; i<17; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } parent=p; psg=new struct VERA_PSG; @@ -434,11 +447,17 @@ int DivPlatformVERA::init(DivEngine* p, int channels, int sugRate, unsigned int skipRegisterWrites=false; chipClock=25000000; rate=chipClock/512; + for (int i=0; i<17; i++) { + oscBuf[i]->rate=rate; + } reset(); return 17; } void DivPlatformVERA::quit() { + for (int i=0; i<17; i++) { + delete oscBuf[i]; + } delete psg; delete pcm; } diff --git a/src/engine/platform/vera.h b/src/engine/platform/vera.h index ddcbed36a..734db020b 100644 --- a/src/engine/platform/vera.h +++ b/src/engine/platform/vera.h @@ -53,6 +53,7 @@ class DivPlatformVERA: public DivDispatch { Channel(): freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), pan(0), active(false), freqChanged(false), inPorta(false), vol(0), outVol(0), accum(0), noiseval(0) {} }; Channel chan[17]; + DivDispatchOscBuffer* oscBuf[17]; bool isMuted[17]; unsigned char regPool[67]; struct VERA_PSG* psg; @@ -65,6 +66,7 @@ class DivPlatformVERA: 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/vic20.cpp b/src/engine/platform/vic20.cpp index 32b1418f2..33250bfc6 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -77,6 +77,9 @@ void DivPlatformVIC20::acquire(short* bufL, short* bufR, size_t start, size_t le vic_sound_machine_calculate_samples(vic,&samp,1,1,0,SAMP_DIVIDER); bufL[h]=samp; bufR[h]=samp; + for (int i=0; i<4; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=vic->ch[i].out?(vic->volume<<11):0; + } } } @@ -275,6 +278,10 @@ void* DivPlatformVIC20::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformVIC20::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformVIC20::getRegisterPool() { return regPool; } @@ -314,6 +321,9 @@ void DivPlatformVIC20::setFlags(unsigned int flags) { chipClock=COLOR_NTSC*2.0/7.0; } rate=chipClock/4; + for (int i=0; i<4; i++) { + oscBuf[i]->rate=rate; + } } void DivPlatformVIC20::poke(unsigned int addr, unsigned short val) { @@ -330,6 +340,7 @@ int DivPlatformVIC20::init(DivEngine* p, int channels, int sugRate, unsigned int skipRegisterWrites=false; for (int i=0; i<4; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); vic=new sound_vic20_t(); @@ -338,6 +349,9 @@ int DivPlatformVIC20::init(DivEngine* p, int channels, int sugRate, unsigned int } void DivPlatformVIC20::quit() { + for (int i=0; i<4; i++) { + delete oscBuf[i]; + } delete vic; } diff --git a/src/engine/platform/vic20.h b/src/engine/platform/vic20.h index 2b3f08e7f..f05ad8f2b 100644 --- a/src/engine/platform/vic20.h +++ b/src/engine/platform/vic20.h @@ -56,6 +56,7 @@ class DivPlatformVIC20: public DivDispatch { waveWriteCycle(-1) {} }; Channel chan[4]; + DivDispatchOscBuffer* oscBuf[4]; bool isMuted[4]; bool hasWaveWrite; @@ -67,6 +68,7 @@ class DivPlatformVIC20: 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/vrc6.cpp b/src/engine/platform/vrc6.cpp index 64c4b831c..835acf4b8 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -97,6 +97,14 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len if (sample<-32768) sample=-32768; bufL[i]=bufR[i]=sample; + // Oscilloscope buffer part + if (++writeOscBuf>=32) { + writeOscBuf=0; + for (int i=0; i<3; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=vrc6.chan_out(i)<<10; + } + } + // Command part while (!writes.empty()) { QueuedWrite w=writes.front(); @@ -427,6 +435,10 @@ void* DivPlatformVRC6::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformVRC6::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformVRC6::getRegisterPool() { return regPool; } @@ -471,6 +483,9 @@ void DivPlatformVRC6::setFlags(unsigned int flags) { rate=COLOR_NTSC/2.0; } chipClock=rate; + for (int i=0; i<3; i++) { + oscBuf[i]->rate=rate/32; + } } void DivPlatformVRC6::notifyInsDeletion(void* ins) { @@ -491,8 +506,10 @@ int DivPlatformVRC6::init(DivEngine* p, int channels, int sugRate, unsigned int parent=p; dumpWrites=false; skipRegisterWrites=false; + writeOscBuf=0; for (int i=0; i<3; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); reset(); @@ -500,6 +517,9 @@ int DivPlatformVRC6::init(DivEngine* p, int channels, int sugRate, unsigned int } void DivPlatformVRC6::quit() { + for (int i=0; i<3; i++) { + delete oscBuf[i]; + } } DivPlatformVRC6::~DivPlatformVRC6() { diff --git a/src/engine/platform/vrc6.h b/src/engine/platform/vrc6.h index 789af7f52..dd6863d5f 100644 --- a/src/engine/platform/vrc6.h +++ b/src/engine/platform/vrc6.h @@ -65,6 +65,7 @@ class DivPlatformVRC6: public DivDispatch { outVol(15) {} }; Channel chan[3]; + DivDispatchOscBuffer* oscBuf[3]; bool isMuted[3]; struct QueuedWrite { unsigned short addr; @@ -73,6 +74,7 @@ class DivPlatformVRC6: public DivDispatch { }; std::queue writes; unsigned char sampleBank; + unsigned char writeOscBuf; vrcvi_intf intf; vrcvi_core vrc6; unsigned char regPool[13]; @@ -83,6 +85,7 @@ class DivPlatformVRC6: 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/x1_010.cpp b/src/engine/platform/x1_010.cpp index 42319a29b..a2e28b518 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -252,6 +252,10 @@ void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t l //printf("tempL: %d tempR: %d\n",tempL,tempR); bufL[h]=stereo?tempL:((tempL+tempR)>>1); bufR[h]=stereo?tempR:bufL[h]; + + for (int i=0; i<16; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=x1_010->chan_out(i); + } } } @@ -822,6 +826,10 @@ void* DivPlatformX1_010::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformX1_010::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformX1_010::getRegisterPool() { for (int i=0; i<0x2000; i++) { regPool[i]=x1_010->ram_r(i); @@ -888,6 +896,9 @@ void DivPlatformX1_010::setFlags(unsigned int flags) { } rate=chipClock/512; stereo=flags&16; + for (int i=0; i<16; i++) { + oscBuf[i]->rate=rate; + } } void DivPlatformX1_010::poke(unsigned int addr, unsigned short val) { @@ -905,6 +916,7 @@ int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned in stereo=false; for (int i=0; i<16; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } setFlags(flags); intf.parent=parent; @@ -915,6 +927,9 @@ int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned in } void DivPlatformX1_010::quit() { + for (int i=0; i<16; i++) { + delete oscBuf[i]; + } delete x1_010; } diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index 8dc749842..11de4bf4a 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -112,6 +112,7 @@ class DivPlatformX1_010: public DivDispatch { waveBank(0) {} }; Channel chan[16]; + DivDispatchOscBuffer* oscBuf[16]; bool isMuted[16]; bool stereo=false; unsigned char sampleBank; @@ -126,6 +127,7 @@ class DivPlatformX1_010: 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(); From 415e490025d694a23b1bba1d151c507fe12bc924 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 1 May 2022 03:12:32 -0500 Subject: [PATCH 10/16] per-channel oscilloscope, part 6 YM2612 and OPM (ymfm)! --- src/engine/platform/arcade.cpp | 6 ++++++ src/engine/platform/genesis.cpp | 6 ++++++ src/engine/platform/sound/ymfm/ymfm_fm.h | 18 ++++++++++++++---- src/engine/platform/sound/ymfm/ymfm_fm.ipp | 8 +++++++- src/engine/platform/sound/ymfm/ymfm_opm.h | 3 +++ src/engine/platform/sound/ymfm/ymfm_opn.h | 3 +++ 6 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 844fe67cf..f36b729a1 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -181,6 +181,8 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; + ymfm::ym2151::fm_engine* fme=fm_ymfm->debug_engine(); + for (size_t h=start; hgenerate(&out_ymfm); + for (int i=0; i<8; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1)); + } + os[0]=out_ymfm.data[0]; if (os[0]<-32768) os[0]=-32768; if (os[0]>32767) os[0]=32767; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 27efab759..5325c982b 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -163,6 +163,8 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; + ymfm::ym2612::fm_engine* fme=fm_ymfm->debug_engine(); + for (size_t h=start; hdata[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6; + } if (os[0]<-32768) os[0]=-32768; if (os[0]>32767) os[0]=32767; diff --git a/src/engine/platform/sound/ymfm/ymfm_fm.h b/src/engine/platform/sound/ymfm/ymfm_fm.h index 3239880e5..352ac9464 100644 --- a/src/engine/platform/sound/ymfm/ymfm_fm.h +++ b/src/engine/platform/sound/ymfm/ymfm_fm.h @@ -301,6 +301,7 @@ public: // simple getters for debugging fm_operator *debug_operator(uint32_t index) const { return m_op[index]; } + int32_t debug_output(uint32_t index) const { return m_output[index]; } private: // helper to add values to the outputs based on channel enables @@ -313,14 +314,22 @@ private: constexpr int out2_index = 2 % RegisterType::OUTPUTS; constexpr int out3_index = 3 % RegisterType::OUTPUTS; - if (RegisterType::OUTPUTS == 1 || m_regs.ch_output_0(choffs)) + if (RegisterType::OUTPUTS == 1 || m_regs.ch_output_0(choffs)) { + m_output[out0_index]=value; output.data[out0_index] += value; - if (RegisterType::OUTPUTS >= 2 && m_regs.ch_output_1(choffs)) + } + if (RegisterType::OUTPUTS >= 2 && m_regs.ch_output_1(choffs)) { + m_output[out1_index]=value; output.data[out1_index] += value; - if (RegisterType::OUTPUTS >= 3 && m_regs.ch_output_2(choffs)) + } + if (RegisterType::OUTPUTS >= 3 && m_regs.ch_output_2(choffs)) { + m_output[out2_index]=value; output.data[out2_index] += value; - if (RegisterType::OUTPUTS >= 4 && m_regs.ch_output_3(choffs)) + } + if (RegisterType::OUTPUTS >= 4 && m_regs.ch_output_3(choffs)) { + m_output[out3_index]=value; output.data[out3_index] += value; + } } // internal state @@ -330,6 +339,7 @@ private: fm_operator *m_op[4]; // up to 4 operators RegisterType &m_regs; // direct reference to registers fm_engine_base &m_owner; // reference to the owning engine + mutable int32_t m_output[4]; }; diff --git a/src/engine/platform/sound/ymfm/ymfm_fm.ipp b/src/engine/platform/sound/ymfm/ymfm_fm.ipp index 84948aedb..4e851737a 100644 --- a/src/engine/platform/sound/ymfm/ymfm_fm.ipp +++ b/src/engine/platform/sound/ymfm/ymfm_fm.ipp @@ -808,7 +808,8 @@ fm_channel::fm_channel(fm_engine_base &owner, uint32 m_feedback_in(0), m_op{ nullptr, nullptr, nullptr, nullptr }, m_regs(owner.regs()), - m_owner(owner) + m_owner(owner), + m_output{ 0, 0, 0, 0 } { } @@ -823,6 +824,11 @@ void fm_channel::reset() // reset our data m_feedback[0] = m_feedback[1] = 0; m_feedback_in = 0; + + m_output[0] = 0; + m_output[1] = 0; + m_output[2] = 0; + m_output[3] = 0; } diff --git a/src/engine/platform/sound/ymfm/ymfm_opm.h b/src/engine/platform/sound/ymfm/ymfm_opm.h index ad657ac01..830b195e4 100644 --- a/src/engine/platform/sound/ymfm/ymfm_opm.h +++ b/src/engine/platform/sound/ymfm/ymfm_opm.h @@ -281,6 +281,9 @@ public: // generate one sample of sound void generate(output_data *output, uint32_t numsamples = 1); + // get the engine + fm_engine* debug_engine() { return &m_fm; } + protected: // variants enum opm_variant diff --git a/src/engine/platform/sound/ymfm/ymfm_opn.h b/src/engine/platform/sound/ymfm/ymfm_opn.h index f4136c731..1a2f55805 100644 --- a/src/engine/platform/sound/ymfm/ymfm_opn.h +++ b/src/engine/platform/sound/ymfm/ymfm_opn.h @@ -761,6 +761,9 @@ public: // generate one sample of sound void generate(output_data *output, uint32_t numsamples = 1); + // get the engine + fm_engine* debug_engine() { return &m_fm; } + protected: // simulate the DAC discontinuity constexpr int32_t dac_discontinuity(int32_t value) const { return (value < 0) ? (value - 2) : (value + 3); } From 47f83c047217e4e6ac40eca65c6bfb627be5edd5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 1 May 2022 03:47:04 -0500 Subject: [PATCH 11/16] per-channel oscilloscope, part 7 YM2610 and YM2610B only TIA is left --- src/engine/platform/sound/ymfm/ymfm_adpcm.h | 4 ++ src/engine/platform/sound/ymfm/ymfm_opn.h | 6 +++ src/engine/platform/sound/ymfm/ymfm_ssg.cpp | 2 + src/engine/platform/sound/ymfm/ymfm_ssg.h | 4 ++ src/engine/platform/ym2610.cpp | 43 +++++++++++++++++++++ src/engine/platform/ym2610.h | 2 + src/engine/platform/ym2610b.cpp | 38 ++++++++++++++++++ src/engine/platform/ym2610b.h | 2 + src/engine/platform/ym2610bext.cpp | 7 +++- src/engine/platform/ym2610bext.h | 1 + src/engine/platform/ym2610ext.cpp | 6 +++ src/engine/platform/ym2610ext.h | 1 + 12 files changed, 115 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/sound/ymfm/ymfm_adpcm.h b/src/engine/platform/sound/ymfm/ymfm_adpcm.h index 4b4af0fdd..b2732cb1e 100644 --- a/src/engine/platform/sound/ymfm/ymfm_adpcm.h +++ b/src/engine/platform/sound/ymfm/ymfm_adpcm.h @@ -203,11 +203,15 @@ public: // return a reference to our registers adpcm_a_registers ®s() { return m_regs; } + // debug functions + adpcm_a_channel* debug_channel(uint32_t index) const { return m_channel[index].get(); } + private: // internal state ymfm_interface &m_intf; // reference to the interface std::unique_ptr m_channel[CHANNELS]; // array of channels adpcm_a_registers m_regs; // registers + int32_t m_last_out[CHANNELS]; // last output of channels }; diff --git a/src/engine/platform/sound/ymfm/ymfm_opn.h b/src/engine/platform/sound/ymfm/ymfm_opn.h index 1a2f55805..1b47885b9 100644 --- a/src/engine/platform/sound/ymfm/ymfm_opn.h +++ b/src/engine/platform/sound/ymfm/ymfm_opn.h @@ -697,6 +697,12 @@ public: // generate one sample of sound void generate(output_data *output, uint32_t numsamples = 1); + // get the engine + fm_engine* debug_fm_engine() { return &m_fm; } + ssg_engine* debug_ssg_engine() { return &m_ssg; } + adpcm_a_engine* debug_adpcm_a_engine() { return &m_adpcm_a; } + adpcm_b_engine* debug_adpcm_b_engine() { return &m_adpcm_b; } + protected: // internal helpers void update_prescale(); diff --git a/src/engine/platform/sound/ymfm/ymfm_ssg.cpp b/src/engine/platform/sound/ymfm/ymfm_ssg.cpp index 3335d47c7..5a9a9d43e 100644 --- a/src/engine/platform/sound/ymfm/ymfm_ssg.cpp +++ b/src/engine/platform/sound/ymfm/ymfm_ssg.cpp @@ -232,6 +232,8 @@ void ssg_engine::output(output_data &output) // convert to amplitude output.data[chan] = s_amplitudes[volume]; } + + m_last_out=output; } diff --git a/src/engine/platform/sound/ymfm/ymfm_ssg.h b/src/engine/platform/sound/ymfm/ymfm_ssg.h index 9f31c92f5..55e748d6b 100644 --- a/src/engine/platform/sound/ymfm/ymfm_ssg.h +++ b/src/engine/platform/sound/ymfm/ymfm_ssg.h @@ -187,6 +187,9 @@ public: // indicate the prescale has changed void prescale_changed() { if (m_override != nullptr) m_override->ssg_prescale_changed(); } + // get the last output + void get_last_out(output_data& out) { out=m_last_out; } + private: // internal state ymfm_interface &m_intf; // reference to the interface @@ -198,6 +201,7 @@ private: uint32_t m_noise_state; // current noise state ssg_registers m_regs; // registers ssg_override *m_override; // override interface + output_data m_last_out; }; } diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index c4ae0ad80..1e5d1f2ab 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -30,6 +30,10 @@ static unsigned char konOffs[4]={ 1, 2, 5, 6 }; +static unsigned char bchOffs[4]={ + 1, 2, 4, 5 +}; + #define CHIP_DIVIDER 32 const char* regCheatSheetYM2610[]={ @@ -337,6 +341,14 @@ double DivPlatformYM2610::NOTE_ADPCMB(int note) { void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; + ymfm::ym2612::fm_engine* fme=fm->debug_fm_engine(); + ymfm::ssg_engine* ssge=fm->debug_ssg_engine(); + ymfm::adpcm_a_engine* aae=fm->debug_adpcm_a_engine(); + ymfm::adpcm_b_engine* abe=fm->debug_adpcm_b_engine(); + + ymfm::ssg_engine::output_data ssgOut; + ymfm::ymfm_output<2> adpcmOut; + for (size_t h=start; hdata[oscBuf[i]->needle++]=(fme->debug_channel(ch)->debug_output(0)+fme->debug_channel(ch)->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=7; i<13; i++) { + adpcmOut.clear(); + aae->debug_channel(i-7)->output(adpcmOut); + oscBuf[i]->data[oscBuf[i]->needle++]=adpcmOut.data[0]+adpcmOut.data[1]; + } + + adpcmOut.clear(); + abe->output(adpcmOut,1); + oscBuf[13]->data[oscBuf[13]->needle++]=adpcmOut.data[0]+adpcmOut.data[1]; } } @@ -1058,6 +1090,10 @@ void* DivPlatformYM2610::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformYM2610::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformYM2610::getRegisterPool() { return regPool; } @@ -1153,9 +1189,13 @@ int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, unsigned in skipRegisterWrites=false; for (int i=0; i<14; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } chipClock=8000000; rate=chipClock/16; + for (int i=0; i<14; i++) { + oscBuf[i]->rate=rate; + } iface.parent=parent; iface.sampleBank=0; fm=new ymfm::ym2610(iface); @@ -1168,6 +1208,9 @@ int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, unsigned in } void DivPlatformYM2610::quit() { + for (int i=0; i<14; i++) { + delete oscBuf[i]; + } ay->quit(); delete ay; delete fm; diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 56f6824d0..c46bc3c43 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -82,6 +82,7 @@ class DivPlatformYM2610: public DivDispatch { pan(3) {} }; Channel chan[14]; + DivDispatchOscBuffer* oscBuf[14]; bool isMuted[14]; struct QueuedWrite { unsigned short addr; @@ -117,6 +118,7 @@ class DivPlatformYM2610: 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/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 12e32ef8c..65b8d723d 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -401,6 +401,14 @@ double DivPlatformYM2610B::NOTE_ADPCMB(int note) { void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t len) { static int os[2]; + ymfm::ym2612::fm_engine* fme=fm->debug_fm_engine(); + ymfm::ssg_engine* ssge=fm->debug_ssg_engine(); + ymfm::adpcm_a_engine* aae=fm->debug_adpcm_a_engine(); + ymfm::adpcm_b_engine* abe=fm->debug_adpcm_b_engine(); + + ymfm::ssg_engine::output_data ssgOut; + ymfm::ymfm_output<2> adpcmOut; + for (size_t h=start; hdata[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(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=9; i<15; i++) { + adpcmOut.clear(); + aae->debug_channel(i-9)->output(adpcmOut); + oscBuf[i]->data[oscBuf[i]->needle++]=adpcmOut.data[0]+adpcmOut.data[1]; + } + + adpcmOut.clear(); + abe->output(adpcmOut,1); + oscBuf[15]->data[oscBuf[15]->needle++]=adpcmOut.data[0]+adpcmOut.data[1]; } } @@ -1121,6 +1148,10 @@ void* DivPlatformYM2610B::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformYM2610B::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformYM2610B::getRegisterPool() { return regPool; } @@ -1216,9 +1247,13 @@ int DivPlatformYM2610B::init(DivEngine* p, int channels, int sugRate, unsigned i skipRegisterWrites=false; for (int i=0; i<16; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } chipClock=8000000; rate=chipClock/16; + for (int i=0; i<16; i++) { + oscBuf[i]->rate=rate; + } iface.parent=parent; iface.sampleBank=0; fm=new ymfm::ym2610b(iface); @@ -1231,6 +1266,9 @@ int DivPlatformYM2610B::init(DivEngine* p, int channels, int sugRate, unsigned i } void DivPlatformYM2610B::quit() { + for (int i=0; i<16; i++) { + delete oscBuf[i]; + } ay->quit(); delete ay; delete fm; diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index c01b9515a..df0a83233 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -74,6 +74,7 @@ class DivPlatformYM2610B: public DivDispatch { pan(3) {} }; Channel chan[16]; + DivDispatchOscBuffer* oscBuf[16]; bool isMuted[16]; struct QueuedWrite { unsigned short addr; @@ -108,6 +109,7 @@ class DivPlatformYM2610B: 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/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 5eec24ece..87c635736 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -336,13 +336,18 @@ void DivPlatformYM2610BExt::forceIns() { } } - void* DivPlatformYM2610BExt::getChanState(int ch) { if (ch>=6) return &chan[ch-3]; if (ch>=2) return &opChan[ch-2]; return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) { + if (ch>=6) return oscBuf[ch-3]; + if (ch<3) return oscBuf[ch]; + return NULL; +} + void DivPlatformYM2610BExt::reset() { DivPlatformYM2610B::reset(); diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index 5dd98c87e..b416b5c70 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -38,6 +38,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B { 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/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index 6ae911061..013e7b954 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -343,6 +343,12 @@ void* DivPlatformYM2610Ext::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformYM2610Ext::getOscBuffer(int ch) { + if (ch>=5) return oscBuf[ch-3]; + if (ch<2) return oscBuf[ch]; + return NULL; +} + void DivPlatformYM2610Ext::reset() { DivPlatformYM2610::reset(); diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index 0ff45981e..10be6638d 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -38,6 +38,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { public: int dispatch(DivCommand c); void* getChanState(int chan); + DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); void tick(bool sysTick=true); From 3a4f120120b9b578938becea25167619ac9bb8c9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 1 May 2022 04:01:25 -0500 Subject: [PATCH 12/16] per-channel oscilloscope, part 8 TIA is done --- src/engine/platform/sound/tia/TIASnd.cpp | 7 ++++++- src/engine/platform/sound/tia/TIASnd.h | 3 ++- src/engine/platform/tia.cpp | 10 +++++++++- src/engine/platform/tia.h | 2 ++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/sound/tia/TIASnd.cpp b/src/engine/platform/sound/tia/TIASnd.cpp index f6ef80460..e2d0568c4 100644 --- a/src/engine/platform/sound/tia/TIASnd.cpp +++ b/src/engine/platform/sound/tia/TIASnd.cpp @@ -157,7 +157,7 @@ void TIASound::volume(unsigned int percent) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::process(short* buffer, unsigned int samples) +void TIASound::process(short* buffer, unsigned int samples, DivDispatchOscBuffer** oscBuf) { // Make temporary local copy unsigned char audc0 = myAUDC[0], audc1 = myAUDC[1]; @@ -339,6 +339,11 @@ void TIASound::process(short* buffer, unsigned int samples) samples--; break; } + + if (oscBuf!=NULL) { + oscBuf[0]->data[oscBuf[0]->needle++]=v0; + oscBuf[1]->data[oscBuf[1]->needle++]=v1; + } } // Save for next round diff --git a/src/engine/platform/sound/tia/TIASnd.h b/src/engine/platform/sound/tia/TIASnd.h index 14e48577a..78459426f 100644 --- a/src/engine/platform/sound/tia/TIASnd.h +++ b/src/engine/platform/sound/tia/TIASnd.h @@ -21,6 +21,7 @@ #define TIASOUND_HXX #include +#include "../../../dispatch.h" /** This class implements a fairly accurate emulation of the TIA sound @@ -87,7 +88,7 @@ class TIASound @param buffer The location to store generated samples @param samples The number of samples to generate */ - void process(short* buffer, unsigned int samples); + void process(short* buffer, unsigned int samples, DivDispatchOscBuffer** oscBuf=NULL); /** Set the volume of the samples created (0-100) diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index f6f7dd9cf..d3bd5ce2d 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -48,7 +48,7 @@ const char** DivPlatformTIA::getRegisterSheet() { } void DivPlatformTIA::acquire(short* bufL, short* bufR, size_t start, size_t len) { - tia.process(bufL+start,len); + tia.process(bufL+start,len,oscBuf); } unsigned char DivPlatformTIA::dealWithFreq(unsigned char shape, int base, int pitch) { @@ -290,6 +290,10 @@ void* DivPlatformTIA::getChanState(int ch) { return &chan[ch]; } +DivDispatchOscBuffer* DivPlatformTIA::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformTIA::getRegisterPool() { return regPool; } @@ -337,6 +341,9 @@ void DivPlatformTIA::setFlags(unsigned int flags) { rate=31468; } chipClock=rate; + for (int i=0; i<2; i++) { + oscBuf[i]->rate=rate; + } } int DivPlatformTIA::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { @@ -345,6 +352,7 @@ int DivPlatformTIA::init(DivEngine* p, int channels, int sugRate, unsigned int f skipRegisterWrites=false; for (int i=0; i<2; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; } tia.channels(1,false); setFlags(flags); diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index dc3bbfd10..76064d069 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -40,6 +40,7 @@ class DivPlatformTIA: public DivDispatch { Channel(): freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), shape(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15) {} }; Channel chan[2]; + DivDispatchOscBuffer* oscBuf[2]; bool isMuted[2]; TIASound tia; unsigned char regPool[16]; @@ -51,6 +52,7 @@ class DivPlatformTIA: 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(); From e1a02f64de5c1f15ec7e28c798702e4884d7ccbe Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 1 May 2022 04:30:04 -0500 Subject: [PATCH 13/16] attempt to fix CI --- src/engine/platform/ym2610.cpp | 1 + src/engine/platform/ym2610b.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 1e5d1f2ab..18acd074d 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -18,6 +18,7 @@ */ #include "ym2610.h" +#include "sound/ymfm/ymfm.h" #include "../engine.h" #include #include diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 65b8d723d..dde693054 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -18,6 +18,7 @@ */ #include "ym2610b.h" +#include "sound/ymfm/ymfm.h" #include "../engine.h" #include #include From 05ae7746171da96ff93262efb246fdb15b91afeb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 1 May 2022 04:49:41 -0500 Subject: [PATCH 14/16] let's hope this works --- 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 18acd074d..5154acc62 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -388,7 +388,7 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l for (int i=7; i<13; i++) { adpcmOut.clear(); - aae->debug_channel(i-7)->output(adpcmOut); + aae->debug_channel(i-7)->output<2>(adpcmOut); oscBuf[i]->data[oscBuf[i]->needle++]=adpcmOut.data[0]+adpcmOut.data[1]; } diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index dde693054..a0f1a6e3f 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -447,7 +447,7 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t for (int i=9; i<15; i++) { adpcmOut.clear(); - aae->debug_channel(i-9)->output(adpcmOut); + aae->debug_channel(i-9)->output<2>(adpcmOut); oscBuf[i]->data[oscBuf[i]->needle++]=adpcmOut.data[0]+adpcmOut.data[1]; } From 9f19b5dfc4dc2324eed40ed793a7f0d90f97715c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 1 May 2022 05:10:41 -0500 Subject: [PATCH 15/16] ok so screw you --- src/engine/platform/sound/ymfm/ymfm_adpcm.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/platform/sound/ymfm/ymfm_adpcm.cpp b/src/engine/platform/sound/ymfm/ymfm_adpcm.cpp index 0d285cd16..01f35367c 100644 --- a/src/engine/platform/sound/ymfm/ymfm_adpcm.cpp +++ b/src/engine/platform/sound/ymfm/ymfm_adpcm.cpp @@ -245,6 +245,8 @@ void adpcm_a_channel::output(ymfm_output &output) const output.data[1] += value; } +template void adpcm_a_channel::output<1>(ymfm_output<1> &output) const; +template void adpcm_a_channel::output<2>(ymfm_output<2> &output) const; //********************************************************* From 58fe971a3cb17205fe42a18d04233f7ad7ec9ecd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 1 May 2022 05:18:30 -0500 Subject: [PATCH 16/16] Clang you are so arrogant --- src/engine/platform/sound/ymfm/ymfm_adpcm.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engine/platform/sound/ymfm/ymfm_adpcm.h b/src/engine/platform/sound/ymfm/ymfm_adpcm.h index b2732cb1e..c08eeae59 100644 --- a/src/engine/platform/sound/ymfm/ymfm_adpcm.h +++ b/src/engine/platform/sound/ymfm/ymfm_adpcm.h @@ -211,7 +211,6 @@ private: ymfm_interface &m_intf; // reference to the interface std::unique_ptr m_channel[CHANNELS]; // array of channels adpcm_a_registers m_regs; // registers - int32_t m_last_out[CHANNELS]; // last output of channels };