yeah
This commit is contained in:
parent
332b449f0e
commit
efb89f7f94
|
@ -28,7 +28,7 @@ struct _nla_table nla_table;
|
|||
|
||||
#define CHIP_DIVIDER 16
|
||||
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {doWrite(a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} }
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite((a),v)); if (dumpWrites) {addWrite((a),v);} }
|
||||
|
||||
const char* regCheatSheetNES[]={
|
||||
"S0Volume", "4000",
|
||||
|
@ -86,10 +86,10 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
|
|||
unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; \
|
||||
if (dacAntiClickOn && dacAntiClick<next) { \
|
||||
dacAntiClick+=8; \
|
||||
rWrite(0x4011,dacAntiClick); \
|
||||
doWrite(0x4011,dacAntiClick); \
|
||||
} else { \
|
||||
dacAntiClickOn=false; \
|
||||
rWrite(0x4011,next); \
|
||||
doWrite(0x4011,next); \
|
||||
} \
|
||||
} \
|
||||
dacPos++; \
|
||||
|
@ -108,6 +108,14 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
|
|||
void DivPlatformNES::acquire_puNES(short** buf, size_t len) {
|
||||
for (size_t i=0; i<len; i++) {
|
||||
doPCM;
|
||||
|
||||
if (!writes.empty())
|
||||
{
|
||||
QueuedWrite w=writes.front();
|
||||
doWrite(w.addr,w.val);
|
||||
regPool[w.addr&0x1f]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
apu_tick(nes,NULL);
|
||||
nes->apu.odd_cycle=!nes->apu.odd_cycle;
|
||||
|
@ -134,6 +142,14 @@ void DivPlatformNES::acquire_NSFPlay(short** buf, size_t len) {
|
|||
int out2[2];
|
||||
for (size_t i=0; i<len; i++) {
|
||||
doPCM;
|
||||
|
||||
if (!writes.empty())
|
||||
{
|
||||
QueuedWrite w=writes.front();
|
||||
doWrite(w.addr,w.val);
|
||||
regPool[w.addr&0x1f]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
nes1_NP->Tick(8);
|
||||
nes2_NP->TickFrameSequence(8);
|
||||
|
@ -400,6 +416,35 @@ void DivPlatformNES::tick(bool sysTick) {
|
|||
logV("switching bank to %d",dpcmBank);
|
||||
if (dumpWrites) addWrite(0xffff0004,dpcmBank);
|
||||
}
|
||||
//sample custom loop point...
|
||||
|
||||
DivSample* lsamp = parent->getSample(dacSample);
|
||||
|
||||
//how it works:
|
||||
//when the initial sample info is written (see above) and playback is launched,
|
||||
//the parameters (start point in memory and length) are locked until sample end
|
||||
//is reached.
|
||||
|
||||
//thus, if we write new data after just several APU clock cycles, it will be used only when
|
||||
//sample finishes one full loop.
|
||||
|
||||
//thus we can write sample's loop point as "start address" and sample's looped part length
|
||||
//as "full sample length".
|
||||
|
||||
//APU will play full sample once and then repeatedly cycle through the looped part.
|
||||
|
||||
//sources:
|
||||
//https://www.nesdev.org/wiki/APU_DMC
|
||||
//https://www.youtube.com/watch?v=vB4P8x2Am6Y
|
||||
|
||||
if(lsamp->loopEnd > lsamp->loopStart && goingToLoop)
|
||||
{
|
||||
int loop_start_addr = (sampleOffDPCM[dacSample] + lsamp->loopStart) / 8;
|
||||
int loop_len = (lsamp->loopEnd - lsamp->loopStart) / 8;
|
||||
|
||||
rWrite(0x4012,(loop_start_addr >> 6)&0xff);
|
||||
rWrite(0x4013,(loop_len >> 4)&0xff);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (nextDPCMFreq>=0) {
|
||||
|
@ -790,6 +835,7 @@ float DivPlatformNES::getPostAmp() {
|
|||
}
|
||||
|
||||
void DivPlatformNES::reset() {
|
||||
while (!writes.empty()) writes.pop();
|
||||
for (int i=0; i<5; i++) {
|
||||
chan[i]=DivPlatformNES::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "sound/nes_nsfplay/nes_apu.h"
|
||||
#include "sound/nes_nsfplay/5e01_apu.h"
|
||||
#include "../../fixedQueue.h"
|
||||
|
||||
class DivPlatformNES: public DivDispatch {
|
||||
struct Channel: public SharedChannel<signed char> {
|
||||
|
@ -44,6 +45,13 @@ class DivPlatformNES: public DivDispatch {
|
|||
Channel chan[5];
|
||||
DivDispatchOscBuffer* oscBuf[5];
|
||||
bool isMuted[5];
|
||||
struct QueuedWrite {
|
||||
unsigned short addr;
|
||||
unsigned char val;
|
||||
QueuedWrite(): addr(0), val(0) {}
|
||||
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v) {}
|
||||
};
|
||||
FixedQueue<QueuedWrite,128> writes;
|
||||
int dacPeriod, dacRate, dpcmPos;
|
||||
unsigned int dacPos, dacAntiClick;
|
||||
int dacSample;
|
||||
|
|
|
@ -254,15 +254,26 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
break;
|
||||
case DIV_SYSTEM_NES:
|
||||
{
|
||||
if (sample->loop) {
|
||||
if (sample->loopStart!=0 || sample->loopEnd!=(int)(sample->samples)) {
|
||||
SAMPLE_WARN(warnLoopPos,_("NES: loop point ignored on DPCM (may only loop entire sample)"));
|
||||
if (sample->loopStart&511) {
|
||||
int tryWith=(sample->loopStart)&(~511);
|
||||
if (tryWith>(int)sample->samples) tryWith-=512;
|
||||
String alignHint=fmt::sprintf(_("NES: loop start must be a multiple of 512 (try with %d)"),tryWith);
|
||||
SAMPLE_WARN(warnLoopStart,alignHint);
|
||||
}
|
||||
if ((sample->loopEnd)&127) {
|
||||
int tryWith=(sample->loopEnd + 1)&(~127); //+1 bc of how sample length is treated: https://www.nesdev.org/wiki/APU_DMC
|
||||
if (tryWith>(int)sample->samples) tryWith-=128;
|
||||
String alignHint=fmt::sprintf(_("NES: loop end must be a multiple of 128 (try with %d)"),tryWith);
|
||||
SAMPLE_WARN(warnLoopEnd,alignHint);
|
||||
}
|
||||
}
|
||||
if (sample->samples>32648) {
|
||||
SAMPLE_WARN(warnLength,_("NES: maximum DPCM sample length is 32648"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_X1_010:
|
||||
if (sample->loop) {
|
||||
SAMPLE_WARN(warnLoop,_("X1-010: samples can't loop"));
|
||||
|
|
Loading…
Reference in a new issue