diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 12831b5fb..127ffc18c 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -1,6 +1,8 @@ #ifndef _DISPATCH_H #define _DISPATCH_H +#include + #define ONE_SEMITONE 2200 enum DivDispatchCmds { @@ -83,7 +85,7 @@ class DivDispatch { * the engine shall resample to the output rate. */ int rate; - virtual void acquire(int& l, int& r); + virtual void acquire(short** buf, size_t start, size_t len); virtual int dispatch(DivCommand c); virtual void tick(); diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 360d5d5b6..6d663664e 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -738,6 +738,10 @@ bool DivEngine::init() { bbOut[0]=new short[got.bufsize]; bbOut[1]=new short[got.bufsize]; + bbIn[0]=new short[32768]; + bbIn[1]=new short[32768]; + bbInLen=32768; + for (int i=0; i<64; i++) { vibTable[i]=127*sin(((double)i/64.0)*(2*M_PI)); } diff --git a/src/engine/engine.h b/src/engine/engine.h index 47c17ff62..79f0d948d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -67,7 +67,9 @@ class DivEngine { short vibTable[64]; blip_buffer_t* bb[2]; + size_t bbInLen; int temp[2], prevSample[2]; + short* bbIn[2]; short* bbOut[2]; int dispatchCmd(DivCommand c); @@ -117,6 +119,7 @@ class DivEngine { cmdsPerSecond(0), view(DIV_STATUS_PATTERN), audioEngine(DIV_AUDIO_SDL), + bbInLen(0), temp{0,0}, prevSample{0,0} {} }; diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index 344e1c230..52a100756 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -1,8 +1,6 @@ #include "../dispatch.h" -void DivDispatch::acquire(int& l, int& r) { - l=0; - r=0; +void DivDispatch::acquire(short** buf, size_t start, size_t len) { } void DivDispatch::tick() { diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index f5052f0cc..11fb8cb63 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -4,10 +4,12 @@ #define FREQ_BASE 277.0f -void DivPlatformC64::acquire(int& l, int& r) { - sid.clock(); - l=sid.output(); - r=l; +void DivPlatformC64::acquire(short** buf, size_t start, size_t len) { + for (size_t i=start; i #include -void DivPlatformDummy::acquire(int& l, int& r) { - l=0; - for (unsigned char i=0; i=0x8000)?chan[i].vol:-chan[i].vol)*chan[i].amp; - - chan[i].pos+=chan[i].freq; +void DivPlatformDummy::acquire(short** buf, size_t start, size_t len) { + for (size_t i=start; i=0x8000)?chan[j].vol:-chan[j].vol)*chan[j].amp; + chan[j].pos+=chan[j].freq; + } } + buf[1][i]=buf[0][i]; } - r=l; } void DivPlatformDummy::tick() { diff --git a/src/engine/platform/dummy.h b/src/engine/platform/dummy.h index 333389d90..f220e35a5 100644 --- a/src/engine/platform/dummy.h +++ b/src/engine/platform/dummy.h @@ -15,7 +15,7 @@ class DivPlatformDummy: public DivDispatch { Channel chan[17]; unsigned char chans; public: - void acquire(int& l, int& r); + void acquire(short** buf, size_t start, size_t len); int dispatch(DivCommand c); void tick(); int init(DivEngine* parent, int channels, int sugRate); diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 36e234f52..90385cd24 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -7,10 +7,12 @@ #define FREQ_BASE 8015.85f -void DivPlatformGB::acquire(int& l, int& r) { - GB_advance_cycles(gb,16); - l=gb->apu_output.final_sample.left<<2; - r=gb->apu_output.final_sample.right<<2; +void DivPlatformGB::acquire(short** buf, size_t start, size_t len) { + for (int i=start; iapu_output.final_sample.left<<2; + buf[1][i]=gb->apu_output.final_sample.right<<2; + } } void DivPlatformGB::updateWave() { diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index 404017d44..19e4f519d 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -36,7 +36,7 @@ class DivPlatformGB: public DivDispatch { GB_gameboy_t* gb; void updateWave(); public: - void acquire(int& l, int& r); + void acquire(short** buf, size_t start, size_t len); int dispatch(DivCommand c); void tick(); int init(DivEngine* parent, int channels, int sugRate); diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 7bbad5c20..6aa1b0862 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -12,59 +12,60 @@ static unsigned char konOffs[6]={ 0, 1, 2, 4, 5, 6 }; -void DivPlatformGenesis::acquire(int& l, int& r) { +void DivPlatformGenesis::acquire(short** buf, size_t start, size_t len) { static short o[2]; static int os[2]; - if (dacMode && dacSample!=-1) { - dacPeriod-=6; - if (dacPeriod<1) { - DivSample* s=parent->song.sample[dacSample]; - if (s->depth==8) { - writes.emplace(0x2a,(unsigned char)s->rendData[dacPos++]+0x80); - } else { - writes.emplace(0x2a,((unsigned short)s->rendData[dacPos++]+0x8000)>>8); + for (size_t h=start; hsong.sample[dacSample]; + if (s->depth==8) { + writes.emplace(0x2a,(unsigned char)s->rendData[dacPos++]+0x80); + } else { + writes.emplace(0x2a,((unsigned short)s->rendData[dacPos++]+0x8000)>>8); + } + if (dacPos>=s->rendLength) { + dacSample=-1; + } + dacPeriod+=dacRate; } - if (dacPos>=s->rendLength) { - dacSample=-1; - } - dacPeriod+=dacRate; } - } - - os[0]=0; os[1]=0; - for (int i=0; i<6; i++) { - if (!writes.empty() && --delay<0) { - delay=0; - QueuedWrite& w=writes.front(); - if (w.addrOrVal) { - OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val); - //printf("write: %x = %.2x\n",w.addr,w.val); - lastBusy=0; - writes.pop(); - } else { - lastBusy++; - if (fm.write_busy==0) { - //printf("busycounter: %d\n",lastBusy); - OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr); - w.addrOrVal=true; + + os[0]=0; os[1]=0; + for (int i=0; i<6; i++) { + if (!writes.empty() && --delay<0) { + delay=0; + QueuedWrite& w=writes.front(); + if (w.addrOrVal) { + OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val); + //printf("write: %x = %.2x\n",w.addr,w.val); + lastBusy=0; + writes.pop(); + } else { + lastBusy++; + if (fm.write_busy==0) { + //printf("busycounter: %d\n",lastBusy); + OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr); + w.addrOrVal=true; + } } } - } + + OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1]; + //OPN2_Write(&fm,0,0); + } - OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1]; - //OPN2_Write(&fm,0,0); - } + psgClocks+=223722; + while (psgClocks>=rate) { + psgOut=(psg.acquireOne()*3)>>3; + psgClocks-=rate; + } - psgClocks+=223722; - while (psgClocks>=rate) { - psg.acquire(psgOut,psgOut); - psgClocks-=rate; - psgOut=(psgOut>>2)+(psgOut>>3); + buf[0][h]=(os[0]<<5)+psgOut; + buf[1][h]=(os[1]<<5)+psgOut; } - - l=(os[0]<<5)+psgOut; - r=(os[1]<<5)+psgOut; } void DivPlatformGenesis::tick() { diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 62dfcc58f..522c002fb 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -48,7 +48,7 @@ class DivPlatformGenesis: public DivDispatch { int toFreq(int freq); public: - void acquire(int& l, int& r); + void acquire(short** buf, size_t start, size_t len); int dispatch(DivCommand c); void tick(); int init(DivEngine* parent, int channels, int sugRate); diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 504a6f98b..185d48ae0 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -5,30 +5,32 @@ #define FREQ_BASE 3424.0f -void DivPlatformNES::acquire(int& l, int& r) { - if (dacSample!=-1) { - dacPeriod+=dacRate; - if (dacPeriod>=rate) { - DivSample* s=parent->song.sample[dacSample]; - if (s->depth==8) { - apu_wr_reg(0x4011,((unsigned char)s->rendData[dacPos++]+0x80)>>1); - } else { - apu_wr_reg(0x4011,((unsigned short)s->rendData[dacPos++]+0x8000)>>9); +void DivPlatformNES::acquire(short** buf, size_t start, size_t len) { + for (size_t i=start; i=rate) { + DivSample* s=parent->song.sample[dacSample]; + if (s->depth==8) { + apu_wr_reg(0x4011,((unsigned char)s->rendData[dacPos++]+0x80)>>1); + } else { + apu_wr_reg(0x4011,((unsigned short)s->rendData[dacPos++]+0x8000)>>9); + } + if (dacPos>=s->rendLength) { + dacSample=-1; + } + dacPeriod-=rate; } - if (dacPos>=s->rendLength) { - dacSample=-1; - } - dacPeriod-=rate; } - } - - apu_tick(NULL); - apu.odd_cycle=!apu.odd_cycle; - if (apu.clocked) { - apu.clocked=false; - l=(pulse_output()+tnd_output())*30; - r=l; - //printf("output value: %d\n",l); + + apu_tick(NULL); + apu.odd_cycle=!apu.odd_cycle; + if (apu.clocked) { + apu.clocked=false; + buf[0][i]=(pulse_output()+tnd_output())*30; + buf[1][i]=buf[0][i]; + //printf("output value: %d\n",l); + } } } diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index eacfc21ea..2e1859ac4 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -36,7 +36,7 @@ class DivPlatformNES: public DivDispatch { void updateWave(); public: - void acquire(int& l, int& r); + void acquire(short** buf, size_t start, size_t len); int dispatch(DivCommand c); void tick(); int init(DivEngine* parent, int channels, int sugRate); diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 57db7b5d0..ff6f7c602 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -13,41 +13,43 @@ #define FREQ_BASE 1712.0f*2 -void DivPlatformPCE::acquire(int& l, int& r) { - // PCM part - for (int i=0; i<6; i++) { - if (chan[i].pcm && chan[i].dacSample!=-1) { - if (--chan[i].dacPeriod<1) { - DivSample* s=parent->song.sample[chan[i].dacSample]; - chWrite(i,0x07,0); - if (s->depth==8) { - chWrite(i,0x04,0xdf); - chWrite(i,0x06,(((unsigned char)s->rendData[chan[i].dacPos++]+0x80)>>3)); - } else { - chWrite(i,0x04,0xdf); - chWrite(i,0x06,(((unsigned short)s->rendData[chan[i].dacPos++]+0x8000)>>11)); +void DivPlatformPCE::acquire(short** buf, size_t start, size_t len) { + for (size_t h=start; hsong.sample[chan[i].dacSample]; + chWrite(i,0x07,0); + if (s->depth==8) { + chWrite(i,0x04,0xdf); + chWrite(i,0x06,(((unsigned char)s->rendData[chan[i].dacPos++]+0x80)>>3)); + } else { + chWrite(i,0x04,0xdf); + chWrite(i,0x06,(((unsigned short)s->rendData[chan[i].dacPos++]+0x8000)>>11)); + } + if (chan[i].dacPos>=s->rendLength) { + chan[i].dacSample=-1; + } + chan[i].dacPeriod=chan[i].dacRate; } - if (chan[i].dacPos>=s->rendLength) { - chan[i].dacSample=-1; - } - chan[i].dacPeriod=chan[i].dacRate; } } - } - - // PCE part - while (!writes.empty()) { - QueuedWrite w=writes.front(); - pce->Write(cycles,w.addr,w.val); - writes.pop(); - } - tempL=0; tempR=0; - pce->Update(4); - pce->ResetTS(0); - //printf("tempL: %d tempR: %d\n",tempL,tempR); - l=tempL; - r=tempR; + // PCE part + while (!writes.empty()) { + QueuedWrite w=writes.front(); + pce->Write(cycles,w.addr,w.val); + writes.pop(); + } + tempL=0; tempR=0; + pce->Update(4); + pce->ResetTS(0); + + //printf("tempL: %d tempR: %d\n",tempL,tempR); + buf[0][h]=tempL; + buf[1][h]=tempR; + } } void DivPlatformPCE::updateWave(int ch) { diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 689c04955..2775dc0bb 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -50,7 +50,7 @@ class DivPlatformPCE: public DivDispatch { PCE_PSG* pce; void updateWave(int ch); public: - void acquire(int& l, int& r); + void acquire(short** buf, size_t start, size_t len); int dispatch(DivCommand c); void tick(); int init(DivEngine* parent, int channels, int sugRate); diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index b88415229..99cc2a89f 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -2,11 +2,15 @@ #include "../engine.h" #include -void DivPlatformSMS::acquire(int& l, int& r) { +void DivPlatformSMS::acquire(short** buf, size_t start, size_t len) { + sn->sound_stream_update(buf[0]+start,len); + memcpy(buf[1]+start,buf[0]+start,sizeof(short)*len); +} + +int DivPlatformSMS::acquireOne() { short v; sn->sound_stream_update(&v,1); - l=v; - r=v; + return v; } void DivPlatformSMS::tick() { diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index c6e6f261e..a390ca909 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -30,7 +30,8 @@ class DivPlatformSMS: public DivDispatch { bool updateSNMode; sn76496_device* sn; public: - void acquire(int& l, int& r); + int acquireOne(); + void acquire(short** buf, size_t start, size_t len); int dispatch(DivCommand c); void tick(); int init(DivEngine* parent, int channels, int sugRate); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 33bf419b6..d98339b13 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -604,15 +604,39 @@ void DivEngine::nextTick() { void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size) { size_t runtotal=blip_clocks_needed(bb[0],size); - for (size_t i=0; iacquire(temp[0],temp[1]); + if (runtotal>bbInLen) { + delete bbIn[0]; + delete bbIn[1]; + bbIn[0]=new short[runtotal+256]; + bbIn[1]=new short[runtotal+256]; + bbInLen=runtotal+256; + } + + size_t runLeft=runtotal; + size_t runPos=0; + while (runLeft) { + if (runLeft>=cycles) { + runLeft-=cycles; + dispatch->acquire(bbIn,runPos,cycles); + runPos+=cycles; + nextTick(); + } else { + dispatch->acquire(bbIn,runPos,runLeft); + cycles-=runLeft; + break; + } + } + + for (size_t i=0; i