diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 1b16943d6..d3c8b6807 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -207,6 +207,179 @@ void DivPlatformAmiga::acquire(short** buf, size_t len) { } } +void DivPlatformAmiga::acquireDirect(blip_buffer_t** bb, size_t off, size_t len) { + thread_local int outL, outR, output; + + for (int i=0; i<4; i++) { + oscBuf[i]->begin(len); + } + + size_t pos=off; + int runCount=1; + for (size_t h=0; h=228",amiga.hPos,runCount); + runCount=1; + break; + } + } + if (runCount>0) { + pos+=runCount-1; + h+=runCount-1; + } else { + runCount=1; + } + //logV("runCount: %d",runCount); + + delay-=runCount; + if (delay<0) delay=0; + if (!writes.empty() && delay<=0) { + QueuedWrite w=writes.front(); + + //logV("THE WRITE %x = %x",w.addr,w.val); + + if (w.addr==0x96 && !(w.val&0x8000)) delay=6144; + + amiga.write(w.addr,w.val); + writes.pop(); + } + + bool hsync=bypassLimits; + outL=0; + outR=0; + + // TODO: + // - improve DMA overrun behavior + // - does V/P mod really work like that? + if (!bypassLimits) { + amiga.hPos+=runCount; + if (amiga.hPos>=228) { + amiga.hPos-=228; + hsync=true; + } + } + for (int i=0; i<4; i++) { + // run DMA + if (amiga.audEn[i]) amiga.mustDMA[i]=true; + if (amiga.dmaEn && amiga.mustDMA[i] && !amiga.audIr[i]) { + amiga.audTick[i]-=runCount; + if (amiga.audTick[i]<0) { + amiga.audTick[i]+=MAX(runCount,amiga.audPer[i]); + if (amiga.audByte[i]) { + // read next samples + if (!amiga.incLoc[i]) { + amiga.audDat[0][i]=sampleMem[(amiga.dmaLoc[i])&chipMask]; + amiga.audDat[1][i]=sampleMem[(amiga.dmaLoc[i]+1)&chipMask]; + amiga.incLoc[i]=true; + } + + amiga.audWord[i]=!amiga.audWord[i]; + } + + amiga.mustDMA[i]=amiga.audEn[i]; + + amiga.audByte[i]=!amiga.audByte[i]; + if (!amiga.audByte[i] && (amiga.useV[i] || amiga.useP[i])) { + amiga.nextOut2[i]=((unsigned char)amiga.audDat[0][i])<<8|((unsigned char)amiga.audDat[1][i]); + if (i<3) { + if (amiga.useV[i] && amiga.useP[i]) { + if (amiga.audWord[i]) { + amiga.audPer[i+1]=amiga.nextOut2[i]; + } else { + amiga.audVol[i+1]=amiga.nextOut2[i]; + } + } else if (amiga.useV[i]) { + amiga.audVol[i+1]=amiga.nextOut2[i]; + } else { + amiga.audPer[i+1]=amiga.nextOut2[i]; + } + } + } else if (!amiga.useV[i] && !amiga.useP[i]) { + amiga.nextOut[i]=amiga.audDat[amiga.audByte[i]][i]; + } + } + + if (hsync) { + if (amiga.incLoc[i]) { + amiga.incLoc[i]=false; + amiga.dmaLoc[i]+=2; + // check for length + if ((--amiga.dmaLen[i])==0) { + if (amiga.audInt[i]) { + amiga.audIr[i]=true; + irq(i); + } + amiga.dmaLoc[i]=amiga.audLoc[i]; + amiga.dmaLen[i]=amiga.audLen[i]; + } + } + } + } + + // output + if (!isMuted[i]) { + if ((amiga.audVol[i]&127)>=64) { + output=amiga.nextOut[i]<<6; + } else if ((amiga.audVol[i]&127)==0) { + output=0; + } else { + output=amiga.nextOut[i]*amiga.audVol[i]; + } + if (i==0 || i==3) { + outL+=(output*sep1)>>7; + outR+=(output*sep2)>>7; + } else { + outL+=(output*sep2)>>7; + outR+=(output*sep1)>>7; + } + oscBuf[i]->putSample(h,(amiga.nextOut[i]*MIN(64,amiga.audVol[i]&127))<<1); + } else { + // TODO: we can remove this! + oscBuf[i]->putSample(h,0); + } + } + + if (outL!=oldOut[0]) { + blip_add_delta(bb[0],pos,outL-oldOut[0]); + oldOut[0]=outL; + } + if (outR!=oldOut[1]) { + blip_add_delta(bb[1],pos,outR-oldOut[1]); + oldOut[1]=outR; + } + + pos++; + } + + for (int i=0; i<4; i++) { + oscBuf[i]->end(len); + } +} + void DivPlatformAmiga::irq(int ch) { // disable interrupt rWrite(0x9a,128<setRate(rate); } diff --git a/src/engine/platform/amiga.h b/src/engine/platform/amiga.h index fa3efb5ed..02ec035c9 100644 --- a/src/engine/platform/amiga.h +++ b/src/engine/platform/amiga.h @@ -61,6 +61,7 @@ class DivPlatformAmiga: public DivDispatch { bool filterOn; bool updateADKCon; short delay; + short oldOut[2]; struct Amiga { // register state @@ -138,6 +139,7 @@ class DivPlatformAmiga: public DivDispatch { public: void acquire(short** buf, size_t len); + void acquireDirect(blip_buffer_t** bb, size_t off, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); @@ -150,6 +152,7 @@ class DivPlatformAmiga: public DivDispatch { void muteChannel(int ch, bool mute); int getOutputCount(); bool keyOffAffectsArp(int ch); + bool hasAcquireDirect(); DivMacroInt* getChanMacroInt(int ch); DivSamplePos getSamplePos(int ch); void setFlags(const DivConfig& flags);