From e1b7618348db706b3bbcf014cce2292c05efad31 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 18 Feb 2025 02:30:14 -0500 Subject: [PATCH] Virtual Boy: make it work on hardware issue #2373 --- src/engine/platform/vb.cpp | 50 ++++++++++++++++++++++++++++++++++++-- src/engine/platform/vb.h | 7 +++++- src/gui/sysConf.cpp | 16 ++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/vb.cpp b/src/engine/platform/vb.cpp index 0b806fc5f..140b14d80 100644 --- a/src/engine/platform/vb.cpp +++ b/src/engine/platform/vb.cpp @@ -127,8 +127,9 @@ void DivPlatformVB::updateWave(int ch) { if (ch>=5) return; for (int i=0; i<32; i++) { - rWrite((ch<<7)+(i<<2),chan[ch].ws.output[i]); + rWrite((ch<<7)+(i<<2),chan[ch].ws.output[(i+chan[ch].antiClickWavePos)&31]); } + chan[ch].antiClickWavePos&=31; } void DivPlatformVB::writeEnv(int ch, bool upperByteToo) { @@ -139,7 +140,17 @@ void DivPlatformVB::writeEnv(int ch, bool upperByteToo) { } void DivPlatformVB::tick(bool sysTick) { + bool mustUpdateWaves=false; + for (int i=0; i<6; i++) { + // anti-click + int actualFreq=2047-chan[i].freq; + if (antiClickEnabled && !screwThis && sysTick && actualFreq>0) { + chan[i].antiClickPeriodCount+=(chipClock/MAX(parent->getCurHz(),1.0f)); + chan[i].antiClickWavePos+=chan[i].antiClickPeriodCount/actualFreq; + chan[i].antiClickPeriodCount%=actualFreq; + } + chan[i].std.next(); if (chan[i].std.vol.had) { chan[i].outVol=VOL_SCALE_LINEAR(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15); @@ -192,10 +203,16 @@ void DivPlatformVB::tick(bool sysTick) { } if (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) { chWrite(i,0x00,0x80); + chan[i].intWritten=true; + chan[i].antiClickWavePos=0; + chan[i].antiClickPeriodCount=0; } if (chan[i].active) { if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1)) { - updateWave(i); + if (!romMode) { + chan[i].deferredWaveUpdate=true; + } + mustUpdateWaves=true; } } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { @@ -215,6 +232,32 @@ void DivPlatformVB::tick(bool sysTick) { chan[i].freqChanged=false; } } + + // trigger wave changes + if (mustUpdateWaves && !romMode) { + //rWrite(0x580,1); + if (!screwThis) { + chWrite(0,0x00,0x00); + chWrite(1,0x00,0x00); + chWrite(2,0x00,0x00); + chWrite(3,0x00,0x00); + chWrite(4,0x00,0x00); + } + for (int i=0; i<5; i++) { + //if (chan[i].deferredWaveUpdate) { + //chan[i].deferredWaveUpdate=false; + updateWave(i); + //} + } + if (!screwThis) { + // restore channel state... + for (int i=0; i<5; i++) { + if (chan[i].intWritten) { + chWrite(i,0x00,0x80); + } + } + } + } } int DivPlatformVB::dispatch(DivCommand c) { @@ -477,6 +520,7 @@ void DivPlatformVB::reset() { for (int i=0; i<6; i++) { chWrite(i,0x01,isMuted[i]?0:chan[i].pan); chWrite(i,0x05,0x00); + chan[i].intWritten=true; chWrite(i,0x00,0x80); if (romMode) { chWrite(i,0x06,0); @@ -545,6 +589,8 @@ void DivPlatformVB::setFlags(const DivConfig& flags) { } romMode=flags.getBool("romMode",false); + antiClickEnabled=!flags.getBool("noAntiClick",false); + screwThis=flags.getBool("screwThis",false); if (vb!=NULL) { delete vb; diff --git a/src/engine/platform/vb.h b/src/engine/platform/vb.h index 94598db86..11c7d9b33 100644 --- a/src/engine/platform/vb.h +++ b/src/engine/platform/vb.h @@ -27,22 +27,27 @@ class DivPlatformVB: public DivDispatch { struct Channel: public SharedChannel { + int antiClickPeriodCount, antiClickWavePos; unsigned char pan, envLow, envHigh; - bool noise, deferredWaveUpdate; + bool noise, deferredWaveUpdate, intWritten; signed short wave; DivWaveSynth ws; Channel(): SharedChannel(15), + antiClickPeriodCount(0), + antiClickWavePos(0), pan(255), envLow(0), envHigh(0), noise(false), deferredWaveUpdate(false), + intWritten(false), wave(-1) {} }; Channel chan[6]; DivDispatchOscBuffer* oscBuf[6]; bool isMuted[6]; + bool antiClickEnabled, screwThis; struct QueuedWrite { unsigned short addr; unsigned char val; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 9d6f045ac..d816aea67 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -2475,6 +2475,8 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl } case DIV_SYSTEM_VBOY: { bool romMode=flags.getBool("romMode",false); + bool noAntiClick=flags.getBool("noAntiClick",false); + bool screwThis=flags.getBool("screwThis",false); ImGui::Text(_("Waveform storage mode:")); ImGui::Indent(); @@ -2488,9 +2490,23 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl } ImGui::Unindent(); + if (!romMode) { + if (ImGui::Checkbox(_("Disable anti-phase-reset"),&noAntiClick)) { + altered=true; + } + if (ImGui::Checkbox(_("I don't care about hardware"),&screwThis)) { + altered=true; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip(_("Virtual Boy hardware requires all channels to be disabled before writing to wave memory.\nif the clicks that arise from this annoy you, use this option.\nnote that your song won't play on hardware if you do so!")); + } + } + if (altered) { e->lockSave([&]() { flags.set("romMode",romMode); + flags.set("noAntiClick",noAntiClick); + flags.set("screwThis",screwThis); }); } break;