MMC5: acquireDirect(), part 1

no samples
also fixed chan osc
This commit is contained in:
tildearrow 2025-03-07 03:07:52 -05:00
parent 86fb92595a
commit 1070fb5d10
5 changed files with 133 additions and 37 deletions

View file

@ -24,7 +24,7 @@
#define CHIP_DIVIDER 16
#define rWrite(a,v) if (!skipRegisterWrites) {extcl_cpu_wr_mem_MMC5(mmc5,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* regCheatSheetMMC5[]={
"S0Volume", "5000",
@ -43,12 +43,27 @@ const char** DivPlatformMMC5::getRegisterSheet() {
return regCheatSheetMMC5;
}
void DivPlatformMMC5::acquire(short** buf, size_t len) {
void DivPlatformMMC5::acquireDirect(blip_buffer_t** bb, size_t len) {
for (int i=0; i<3; i++) {
oscBuf[i]->begin(len);
mmc5->oscBuf[i]=oscBuf[i];
}
mmc5->bb=bb[0];
mmc5->timestamp=0;
while (!writes.empty()) {
QueuedWrite w=writes.front();
regPool[(w.addr)&0x7f]=w.val;
extcl_cpu_wr_mem_MMC5(mmc5,0,w.addr,w.val);
writes.pop();
}
// TODO: does this matter?
extcl_envelope_clock_MMC5(mmc5);
extcl_length_clock_MMC5(mmc5);
for (size_t i=0; i<len; i++) {
/*
if (dacSample!=-1) {
dacPeriod+=dacRate;
if (dacPeriod>=rate) {
@ -69,10 +84,12 @@ void DivPlatformMMC5::acquire(short** buf, size_t len) {
}
}
}
*/
extcl_envelope_clock_MMC5(mmc5);
extcl_length_clock_MMC5(mmc5);
extcl_apu_tick_MMC5(mmc5);
extcl_apu_tick_MMC5(mmc5,len);
break;
/*
if (mmc5->clocked) {
mmc5->clocked=false;
}
@ -92,7 +109,7 @@ void DivPlatformMMC5::acquire(short** buf, size_t len) {
oscBuf[0]->putSample(i,isMuted[0]?0:((mmc5->S3.output)<<11));
oscBuf[1]->putSample(i,isMuted[1]?0:((mmc5->S4.output)<<11));
oscBuf[2]->putSample(i,isMuted[2]?0:((mmc5->pcm.output)<<7));
}
}*/
}
for (int i=0; i<3; i++) {
@ -364,6 +381,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
void DivPlatformMMC5::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
mmc5->muted[ch]=mute;
}
void DivPlatformMMC5::forceIns() {
@ -415,6 +433,10 @@ void DivPlatformMMC5::reset() {
map_init_MMC5(mmc5);
memset(regPool,0,128);
mmc5->muted[0]=isMuted[0];
mmc5->muted[1]=isMuted[1];
mmc5->muted[2]=isMuted[2];
rWrite(0x5015,0x03);
rWrite(0x5010,0x00);
}
@ -423,6 +445,10 @@ bool DivPlatformMMC5::keyOffAffectsArp(int ch) {
return true;
}
bool DivPlatformMMC5::hasAcquireDirect() {
return true;
}
void DivPlatformMMC5::setFlags(const DivConfig& flags) {
int clockSel=flags.getInt("clockSel",0);
if (clockSel==2) { // Dendy

View file

@ -39,6 +39,13 @@ class DivPlatformMMC5: public DivDispatch {
Channel chan[5];
DivDispatchOscBuffer* oscBuf[3];
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;
unsigned int dacPos;
int dacSample;
@ -51,7 +58,7 @@ class DivPlatformMMC5: public DivDispatch {
friend void putDispatchChan(void*,int,int);
public:
void acquire(short** buf, size_t len);
void acquireDirect(blip_buffer_t** bb, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
@ -63,6 +70,7 @@ class DivPlatformMMC5: public DivDispatch {
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
bool hasAcquireDirect();
float getPostAmp();
void setFlags(const DivConfig& flags);
void notifyInsDeletion(void* ins);

View file

@ -60,6 +60,8 @@ void apu_tick(struct NESAPU* a, int len) {
}
if (advance<1) advance=1;
int postTS=a->timestamp+advance-1;
/* sottraggo il numero di cicli eseguiti */
a->apu.cycles-=advance;
/*
@ -220,7 +222,7 @@ void apu_tick(struct NESAPU* a, int len) {
square_output(a->S1, 0)
a->S1.frequency = (a->S1.timer + 1) << 1;
a->S1.sequencer = (a->S1.sequencer + 1) & 0x07;
a->oscBuf[0]->putSample(a->timestamp,a->muted[0]?0:(a->S1.output<<11));
a->oscBuf[0]->putSample(postTS,a->muted[0]?0:(a->S1.output<<11));
}
// SQUARE 2 TICK
@ -228,7 +230,7 @@ void apu_tick(struct NESAPU* a, int len) {
square_output(a->S2, 0)
a->S2.frequency = (a->S2.timer + 1) << 1;
a->S2.sequencer = (a->S2.sequencer + 1) & 0x07;
a->oscBuf[1]->putSample(a->timestamp,a->muted[1]?0:(a->S2.output<<11));
a->oscBuf[1]->putSample(postTS,a->muted[1]?0:(a->S2.output<<11));
}
// TRIANGLE TICK
@ -237,7 +239,7 @@ void apu_tick(struct NESAPU* a, int len) {
if (a->TR.length.value && a->TR.linear.value) {
a->TR.sequencer = (a->TR.sequencer + 1) & 0x1F;
triangle_output()
a->oscBuf[2]->putSample(a->timestamp,a->muted[2]?0:(a->TR.output<<11));
a->oscBuf[2]->putSample(postTS,a->muted[2]?0:(a->TR.output<<11));
}
}
@ -251,7 +253,7 @@ void apu_tick(struct NESAPU* a, int len) {
a->NS.shift &= 0x7FFF;
noise_output()
a->NS.frequency = noise_timer[a->apu.type][a->NS.timer];
a->oscBuf[3]->putSample(a->timestamp,a->muted[3]?0:(a->NS.output<<11));
a->oscBuf[3]->putSample(postTS,a->muted[3]?0:(a->NS.output<<11));
}
// DMC TICK
@ -280,7 +282,7 @@ void apu_tick(struct NESAPU* a, int len) {
}
}
a->DMC.frequency = dmc_rate[a->apu.type][a->DMC.rate_index];
a->oscBuf[4]->putSample(a->timestamp,a->muted[4]?0:(a->DMC.output<<8));
a->oscBuf[4]->putSample(postTS,a->muted[4]?0:(a->DMC.output<<8));
}
if (a->DMC.empty && a->DMC.remain) {
BYTE tick = 4;
@ -323,7 +325,7 @@ void apu_tick(struct NESAPU* a, int len) {
}
// output sample
a->timestamp+=advance-1;
a->timestamp=postTS;
int sample=(pulse_output(a)+tnd_output(a))<<6;
if (sample!=a->lastSample) {
blip_add_delta(a->bb,a->timestamp,sample-a->lastSample);

View file

@ -35,12 +35,21 @@ void map_init_MMC5(struct _mmc5* mmc5) {
mmc5->S3.length.value = 0;
mmc5->S4.length.enabled = 0;
mmc5->S4.length.value = 0;
mmc5->timestamp = 0;
mmc5->lastSample = 0;
mmc5->bb = NULL;
mmc5->oscBuf[0] = NULL;
mmc5->oscBuf[1] = NULL;
mmc5->oscBuf[2] = NULL;
}
void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, WORD address, BYTE value) {
void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, int ts, WORD address, BYTE value) {
if (address < 0x5000) {
return;
}
extcl_apu_tick_MMC5(mmc5,ts);
switch (address) {
case 0x5000:
square_reg0(mmc5->S3);
@ -71,16 +80,18 @@ void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, WORD address, BYTE value) {
mmc5->pcm.output = 0;
if (mmc5->pcm.enabled) {
mmc5->pcm.output = mmc5->pcm.amp;
mmc5->oscBuf[2]->putSample(mmc5->timestamp,mmc5->muted[2]?0:(mmc5->pcm.output<<7));
}
mmc5->clocked = TRUE;
//mmc5->clocked = TRUE;
return;
case 0x5011:
mmc5->pcm.amp = value;
mmc5->pcm.output = 0;
if (mmc5->pcm.enabled) {
mmc5->pcm.output = mmc5->pcm.amp;
mmc5->oscBuf[2]->putSample(mmc5->timestamp,mmc5->muted[2]?0:(mmc5->pcm.output<<7));
}
mmc5->clocked = TRUE;
//mmc5->clocked = TRUE;
return;
case 0x5015:
if (!(mmc5->S3.length.enabled = value & 0x01)) {
@ -100,20 +111,70 @@ void extcl_envelope_clock_MMC5(struct _mmc5* mmc5) {
envelope_run(mmc5->S3)
envelope_run(mmc5->S4)
}
void extcl_apu_tick_MMC5(struct _mmc5* mmc5) {
// SQUARE 3 TICK
if (!(--mmc5->S3.frequency)) {
square_output(mmc5->S3, 0)
mmc5->S3.frequency = (mmc5->S3.timer + 1) << 1;
mmc5->S3.sequencer = (mmc5->S3.sequencer + 1) & 0x07;
mmc5->clocked = TRUE;
void extcl_apu_tick_MMC5(struct _mmc5* mmc5, int len) {
if (len<=mmc5->timestamp) return;
int rem=len-mmc5->timestamp;
if (rem>1) {
// output now just in case
int sample=mmc5->muted[0]?0:(mmc5->S3.output*10);
if (!mmc5->muted[1]) {
sample+=mmc5->S4.output*10;
}
if (!mmc5->muted[2]) {
sample+=mmc5->pcm.output*2;
}
if (sample!=mmc5->lastSample) {
blip_add_delta(mmc5->bb,mmc5->timestamp,sample-mmc5->lastSample);
mmc5->lastSample=sample;
}
}
// SQUARE 4 TICK
if (!(--mmc5->S4.frequency)) {
square_output(mmc5->S4, 0)
mmc5->S4.frequency = (mmc5->S4.timer + 1) << 1;
mmc5->S4.sequencer = (mmc5->S4.sequencer + 1) & 0x07;
mmc5->clocked = TRUE;
while (rem>0) {
// predict advance
int advance=rem;
if (advance>mmc5->S3.frequency) {
advance=mmc5->S3.frequency;
}
if (advance>mmc5->S4.frequency) {
advance=mmc5->S4.frequency;
}
if (advance<1) advance=1;
int postTS=mmc5->timestamp+advance-1;
// SQUARE 3 TICK
if (!(mmc5->S3.frequency-=advance)) {
square_output(mmc5->S3, 0)
mmc5->S3.frequency = (mmc5->S3.timer + 1) << 1;
mmc5->S3.sequencer = (mmc5->S3.sequencer + 1) & 0x07;
mmc5->oscBuf[0]->putSample(postTS,mmc5->muted[0]?0:(mmc5->S3.output<<11));
}
// SQUARE 4 TICK
if (!(mmc5->S4.frequency-=advance)) {
square_output(mmc5->S4, 0)
mmc5->S4.frequency = (mmc5->S4.timer + 1) << 1;
mmc5->S4.sequencer = (mmc5->S4.sequencer + 1) & 0x07;
mmc5->oscBuf[1]->putSample(postTS,mmc5->muted[1]?0:(mmc5->S4.output<<11));
}
// output sample
mmc5->timestamp=postTS;
int sample=mmc5->muted[0]?0:(mmc5->S3.output*10);
if (!mmc5->muted[1]) {
sample+=mmc5->S4.output*10;
}
if (!mmc5->muted[2]) {
sample+=mmc5->pcm.output*2;
}
if (sample!=mmc5->lastSample) {
blip_add_delta(mmc5->bb,mmc5->timestamp,sample-mmc5->lastSample);
mmc5->lastSample=sample;
}
rem-=advance;
mmc5->timestamp++;
}
mmc5->timestamp=len;
}

View file

@ -54,19 +54,18 @@ struct _mmc5 {
BYTE output;
BYTE amp;
} pcm;
BYTE filler[50];
int timestamp;
int lastSample;
BYTE muted[3];
/* ------------------------------------------------------- */
/* questi valori non e' necessario salvarli nei savestates */
/* ------------------------------------------------------- */
/* */ BYTE clocked; /* */
/* ------------------------------------------------------- */
blip_buffer_t* bb;
DivDispatchOscBuffer* oscBuf[5];
};
void map_init_MMC5(struct _mmc5* mmc5);
void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, WORD address, BYTE value);
void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, int ts, WORD address, BYTE value);
void extcl_length_clock_MMC5(struct _mmc5* mmc5);
void extcl_envelope_clock_MMC5(struct _mmc5* mmc5);
void extcl_apu_tick_MMC5(struct _mmc5* mmc5);
void extcl_apu_tick_MMC5(struct _mmc5* mmc5, int len);
#endif /* MAPPER_MMC5_H_ */