From 9e72d4580f08182b2d36584505f2c0b6bc9df98b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Jun 2021 02:49:43 -0500 Subject: [PATCH] FINALLY SOUND --- src/engine/platform/pce.cpp | 186 ++++++++------------------ src/engine/platform/pce.h | 22 +-- src/engine/platform/sound/pce_psg.cpp | 12 +- 3 files changed, 81 insertions(+), 139 deletions(-) diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index d9f327169..a3fd2ccbb 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -3,80 +3,50 @@ #include //#define rWrite(a,v) pendingWrites[a]=v; -#define rWrite(a,v) pce->Write(cycles,a,v); +#define rWrite(a,v) writes.emplace(a,v); +#define chWrite(c,a,v) \ + if (curChan!=c) { \ + curChan=c; \ + rWrite(0,curChan); \ + } \ + rWrite(a,v); -#define FREQ_BASE 8015.85f +#define FREQ_BASE 1712.0f void DivPlatformPCE::acquire(int& l, int& r) { - pce->Update(++cycles); + if (!writes.empty() && --delay<0) { + QueuedWrite w=writes.front(); + pce->Write(cycles,w.addr,w.val); + writes.pop(); + delay=2; + } + tempL=0; tempR=0; + pce->Update(2); + pce->ResetTS(0); + + //printf("tempL: %d tempR: %d\n",tempL,tempR); l=tempL; r=tempR; } -void DivPlatformPCE::updateWave() { +void DivPlatformPCE::updateWave(int ch) { DivWavetable* wt=parent->getWave(chan[2].wave); - rWrite(0x1a,0); - for (int i=0; i<16; i++) { - unsigned char next=((wt->data[i*2]&15)<<4)|(wt->data[1+i*2]&15); - rWrite(0x30+i,next); + chWrite(ch,0x04,0x1f); + chWrite(ch,0x04,0x5f); + for (int i=0; i<32; i++) { + chWrite(ch,0x06,wt->data[i]&31); } } -static unsigned char gbVolMap[16]={ - 0x00, 0x00, 0x00, 0x00, - 0x60, 0x60, 0x60, 0x60, - 0x40, 0x40, 0x40, 0x40, - 0x20, 0x20, 0x20, 0x20 -}; - -static unsigned char noiseTable[256]={ - 0, - 0xf7, 0xf6, 0xf5, 0xf4, - 0xe7, 0xe6, 0xe5, 0xe4, - 0xd7, 0xd6, 0xd5, 0xd4, - 0xc7, 0xc6, 0xc5, 0xc4, - 0xb7, 0xb6, 0xb5, 0xb4, - 0xa7, 0xa6, 0xa5, 0xa4, - 0x97, 0x96, 0x95, 0x94, - 0x87, 0x86, 0x85, 0x84, - 0x77, 0x76, 0x75, 0x74, - 0x67, 0x66, 0x65, 0x64, - 0x57, 0x56, 0x55, 0x54, - 0x47, 0x46, 0x45, 0x44, - 0x37, 0x36, 0x35, 0x34, - 0x27, 0x26, 0x25, 0x24, - 0x17, 0x16, 0x15, 0x14, - 0x07, 0x06, 0x05, 0x04, - 0x03, 0x02, 0x01, 0x00, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - void DivPlatformPCE::tick() { - for (int i=0; i<4; i++) { + for (int i=0; i<6; i++) { chan[i].std.next(); if (chan[i].std.hadArp) { - if (i==3) { // noise + if (!chan[i].inPorta) { if (chan[i].std.arpMode) { - chan[i].baseFreq=chan[i].std.arp+24; + chan[i].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(chan[i].std.arp+24)/12.0f))); } else { - chan[i].baseFreq=chan[i].note+chan[i].std.arp-12; - } - if (chan[i].baseFreq>255) chan[i].baseFreq=255; - if (chan[i].baseFreq<0) chan[i].baseFreq=0; - } else { - if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(chan[i].std.arp+24)/12.0f))); - } else { - chan[i].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(chan[i].note+chan[i].std.arp-12)/12.0f))); - } + chan[i].baseFreq=round(FREQ_BASE/pow(2.0f,((float)(chan[i].note+chan[i].std.arp-12)/12.0f))); } } chan[i].freqChanged=true; @@ -88,61 +58,32 @@ void DivPlatformPCE::tick() { } if (chan[i].std.hadDuty) { chan[i].duty=chan[i].std.duty; - DivInstrument* ins=parent->getIns(chan[i].ins); - if (i!=2) { - rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); - } + //DivInstrument* ins=parent->getIns(chan[i].ins); } if (chan[i].std.hadWave) { if (chan[i].wave!=chan[i].std.wave) { chan[i].wave=chan[i].std.wave; - if (i==2) { - updateWave(); - if (!chan[i].keyOff) chan[i].keyOn=true; - } - } - } - if (chan[i].sweepChanged) { - chan[i].sweepChanged=false; - if (i==0) { - rWrite(16+i*5,chan[i].sweep); + updateWave(i); + if (!chan[i].keyOff) chan[i].keyOn=true; } } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - DivInstrument* ins=parent->getIns(chan[i].ins); - if (i==3) { // noise - chan[i].freq=noiseTable[chan[i].baseFreq]; - } else { - chan[i].freq=(chan[i].baseFreq*(ONE_SEMITONE-chan[i].pitch))/ONE_SEMITONE; - if (chan[i].freq>2047) chan[i].freq=2047; - } + //DivInstrument* ins=parent->getIns(chan[i].ins); + chan[i].freq=(chan[i].baseFreq*(ONE_SEMITONE-chan[i].pitch))/ONE_SEMITONE; + if (chan[i].freq>4095) chan[i].freq=4095; if (chan[i].note>0x5d) chan[i].freq=0x01; + chWrite(i,0x02,chan[i].freq&0xff); + chWrite(i,0x03,chan[i].freq>>8); if (chan[i].keyOn) { - if (i==2) { // wave - if (chan[i].wave<0) { - chan[i].wave=0; - updateWave(); - } - rWrite(16+i*5,0x80); - rWrite(16+i*5+2,gbVolMap[chan[i].vol]); - } else { - rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); - rWrite(16+i*5+2,((chan[i].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3)); + if (chan[i].wave<0) { + chan[i].wave=0; + updateWave(i); } + //rWrite(16+i*5,0x80); + chWrite(i,0x04,0x80|chan[i].vol); } if (chan[i].keyOff) { - if (i==2) { - rWrite(16+i*5+2,0); - } else { - rWrite(16+i*5+2,8); - } - } - if (i==3) { // noise - rWrite(16+i*5+3,(chan[i].freq&0xff)|(chan[i].duty?8:0)); - rWrite(16+i*5+4,((chan[i].keyOn||chan[i].keyOff)?0x80:0x00)|((ins->gb.soundLen<64)<<6)); - } else { - rWrite(16+i*5+3,(2048-chan[i].freq)&0xff); - rWrite(16+i*5+4,(((2048-chan[i].freq)>>8)&7)|((chan[i].keyOn||chan[i].keyOff)?0x80:0x00)|((ins->gb.soundLen<63)<<6)); + chWrite(i,0x04,0); } if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOff) chan[i].keyOff=false; @@ -154,11 +95,7 @@ void DivPlatformPCE::tick() { int DivPlatformPCE::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: - if (c.chan==3) { // noise - chan[c.chan].baseFreq=c.value; - } else { - chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); - } + chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; chan[c.chan].active=true; @@ -173,16 +110,11 @@ int DivPlatformPCE::dispatch(DivCommand c) { case DIV_CMD_INSTRUMENT: if (chan[c.chan].ins!=c.value) { chan[c.chan].ins=c.value; - if (c.chan!=2) { - chan[c.chan].vol=parent->getIns(chan[c.chan].ins)->gb.envVol; - } } break; case DIV_CMD_VOLUME: chan[c.chan].vol=c.value; - if (c.chan==2) { - rWrite(16+c.chan*5+2,gbVolMap[chan[c.chan].vol]); - } + //rWrite(16+c.chan*5+2,gbVolMap[chan[c.chan].vol]); break; case DIV_CMD_GET_VOLUME: return chan[c.chan].vol; @@ -194,7 +126,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { case DIV_CMD_WAVE: if (c.chan!=2) break; chan[c.chan].wave=c.value; - updateWave(); + updateWave(c.chan); chan[c.chan].keyOn=true; break; case DIV_CMD_NOTE_PORTA: { @@ -224,18 +156,17 @@ int DivPlatformPCE::dispatch(DivCommand c) { chan[c.chan].duty=c.value; if (c.chan!=2) { chan[c.chan].freqChanged=true; - rWrite(16+c.chan*5+1,((chan[c.chan].duty&3)<<6)|(63-(parent->getIns(chan[c.chan].ins)->gb.soundLen&63))); + // TODO } break; case DIV_CMD_PANNING: { lastPan&=~(0x11<getIns(chan[c.chan].ins)); chan[c.chan].inPorta=c.value; break; - case DIV_CMD_GB_SWEEP_DIR: - chan[c.chan].sweep&=0xf7; - if (c.value&1) { - chan[c.chan].sweep|=8; - } - chan[c.chan].sweepChanged=true; - break; - case DIV_CMD_GB_SWEEP_TIME: - chan[c.chan].sweep&=8; - chan[c.chan].sweep|=c.value&0x77; - chan[c.chan].sweepChanged=true; - break; case DIV_CMD_GET_VOLMAX: - return 15; + return 31; break; case DIV_ALWAYS_SET_VOLUME: return 1; @@ -276,5 +195,14 @@ int DivPlatformPCE::init(DivEngine* p, int channels, int sugRate) { tempL=0; tempR=0; cycles=0; + curChan=-1; + // set global volume + rWrite(0,0); + rWrite(0x01,0xff); + // set per-channel initial panning + for (int i=0; i<6; i++) { + chWrite(i,0x05,chan[i].pan); + } + delay=500; return 6; } diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 6ac6db819..25ebab0bf 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -2,14 +2,15 @@ #define _PCE_H #include "../dispatch.h" +#include #include "../macroInt.h" #include "sound/pce_psg.h" class DivPlatformPCE: public DivDispatch { struct Channel { int freq, baseFreq, pitch; - unsigned char ins, note, duty, sweep; - bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta; + unsigned char ins, note, duty, pan; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; signed char vol, outVol, wave; DivMacroInt std; Channel(): @@ -19,23 +20,28 @@ class DivPlatformPCE: public DivDispatch { ins(-1), note(0), duty(0), - sweep(0), + pan(255), active(false), insChanged(true), freqChanged(false), - sweepChanged(false), keyOn(false), keyOff(false), inPorta(false), - vol(15), + vol(31), wave(-1) {} }; - Channel chan[4]; + Channel chan[6]; + struct QueuedWrite { + unsigned char addr; + unsigned char val; + QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {} + }; + std::queue writes; unsigned char lastPan; - int tempL, tempR, cycles; + int tempL, tempR, cycles, curChan, delay; PCE_PSG* pce; - void updateWave(); + void updateWave(int ch); public: void acquire(int& l, int& r); int dispatch(DivCommand c); diff --git a/src/engine/platform/sound/pce_psg.cpp b/src/engine/platform/sound/pce_psg.cpp index 4561ba14c..5894e3056 100644 --- a/src/engine/platform/sound/pce_psg.cpp +++ b/src/engine/platform/sound/pce_psg.cpp @@ -21,6 +21,7 @@ // additional modifications by tildearrow for furnace #include "pce_psg.h" +#include #include #include #include @@ -75,6 +76,10 @@ static const int16_t Phase_Filter[2][7] = inline void PCE_PSG::UpdateOutputSub(const int32_t timestamp, psg_channel *ch, const int32_t samp0, const int32_t samp1) { + if (samp0!=0) + HRBufs[0][0]+=samp0; + HRBufs[1][0]+=samp1; + /* int32_t delta[2]; delta[0] = samp0 - ch->blip_prev_samp[0]; @@ -101,6 +106,7 @@ inline void PCE_PSG::UpdateOutputSub(const int32_t timestamp, psg_channel *ch, c ch->blip_prev_samp[0] = samp0; ch->blip_prev_samp[1] = samp1; + */ } void PCE_PSG::UpdateOutput_Norm(const int32_t timestamp, psg_channel *ch) @@ -476,7 +482,7 @@ void PCE_PSG::Write(int32_t timestamp, uint8_t A, uint8_t V) psg_channel *ch = &channel[select]; //if(A == 0x01 || select == 5) - // printf("Write Ch: %d %04x %02x, %d\n", select, A, V, timestamp); + printf("Write Ch: %d %04x %02x, %d\n", select, A, V, timestamp); switch(A) { @@ -600,8 +606,9 @@ void PCE_PSG::RunChannel(int chc, int32_t timestamp, const bool LFO_On) ch->lastts = timestamp; - if(!run_time) + if(!run_time) { return; + } (this->*ch->UpdateOutput)(running_timestamp, ch); @@ -792,6 +799,7 @@ void PCE_PSG::Power(const int32_t timestamp) channel[ch].control = 0x00; channel[ch].balance = 0; memset(channel[ch].waveform, 0, 32); + channel[ch].waveform[3]=10; channel[ch].samp_accum = 0; channel[ch].waveform_index = 0;