From 09b96f9940533dc94d04f415332626ba3b72ebb5 Mon Sep 17 00:00:00 2001 From: kub Date: Wed, 22 Apr 2020 20:41:51 +0200 Subject: [PATCH] audio: improve cycle accuracy of SN76496+YM2612 --- pico/memory.c | 7 +++-- pico/pico_int.h | 12 ++++----- pico/sms.c | 2 +- pico/sound/sound.c | 67 +++++++++++++++------------------------------- 4 files changed, 32 insertions(+), 56 deletions(-) diff --git a/pico/memory.c b/pico/memory.c index 0fa7b8de..e1afb4db 100644 --- a/pico/memory.c +++ b/pico/memory.c @@ -391,7 +391,7 @@ static int get_scanline(int is_from_z80); static void psg_write_68k(u32 d) { // look for volume write and update if needed - if ((d & 0x90) == 0x90 && Pico.snd.psg_line < Pico.m.scanline) + if ((d & 0x90) == 0x90) PsndDoPSG(Pico.m.scanline); SN76496Write(d); @@ -401,8 +401,7 @@ static void psg_write_z80(u32 d) { if ((d & 0x90) == 0x90) { int scanline = get_scanline(1); - if (Pico.snd.psg_line < scanline) - PsndDoPSG(scanline); + PsndDoPSG(scanline); } SN76496Write(d); @@ -1061,7 +1060,7 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80) if (PicoIn.opt & POPT_EXT_FM) return YM2612Write_940(a, d, get_scanline(is_from_z80)); #endif - PsndDoFM(get_scanline(is_from_z80)); + PsndDoFM(is_from_z80 ? z80_cyclesDone() : z80_cycles_from_68k()); return YM2612Write_(a, d); } diff --git a/pico/pico_int.h b/pico/pico_int.h index 8a4aa309..7539379a 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -436,12 +436,12 @@ struct PicoSound short len_use; // adjusted int len_e_add; // for non-int samples/frame int len_e_cnt; - int dac_val, dac_val2; // last DAC sample - unsigned int dac_mult; // z80 clocks per line in Q16 - unsigned int dac_pos; // last DAC position in Q16 - short psg_line; - unsigned int fm_mult; // samples per line in Q16 - unsigned int fm_pos; // last FM position in Q16 + unsigned int clkl_mult; // z80 clocks per line in Q20 + unsigned int smpl_mult; // samples per line in Q16 + short dac_val, dac_val2; // last DAC sample + unsigned int dac_pos; // last DAC position in Q20 + unsigned int fm_pos; // last FM position in Q20 + unsigned int psg_pos; // last PSG position in Q16 }; // run tools/mkoffsets pico/pico_int_offs.h if you change these diff --git a/pico/sms.c b/pico/sms.c index b016f197..901f2f55 100644 --- a/pico/sms.c +++ b/pico/sms.c @@ -152,7 +152,7 @@ static void z80_sms_out(unsigned short a, unsigned char d) case 0x40: case 0x41: - if ((d & 0x90) == 0x90 && Pico.snd.psg_line < Pico.m.scanline) + if ((d & 0x90) == 0x90); PsndDoPSG(Pico.m.scanline); SN76496Write(d); break; diff --git a/pico/sound/sound.c b/pico/sound/sound.c index 57d9c2e5..eb10f36b 100644 --- a/pico/sound/sound.c +++ b/pico/sound/sound.c @@ -19,9 +19,6 @@ void (*PsndMix_32_to_16l)(short *dest, int *src, int count) = mix_32_to_16l_ster // master int buffer to mix to static int PsndBuffer[2*(44100+100)/50]; -// dac, psg -static unsigned short dac_info[312+4]; // pos in sample buffer - // cdda output buffer short cdda_out_buffer[2*1152]; @@ -29,23 +26,6 @@ short cdda_out_buffer[2*1152]; extern int *sn76496_regs; -static void dac_recalculate(void) -{ - int lines = Pico.m.pal ? 313 : 262; - int i, pos; - - pos = 0; // Q16 - - for(i = 0; i <= lines; i++) - { - dac_info[i] = ((pos+0x8000) >> 16); // round to nearest - pos += Pico.snd.fm_mult; - } - for (i = lines+1; i < sizeof(dac_info) / sizeof(dac_info[0]); i++) - dac_info[i] = dac_info[i-1]; -} - - PICO_INTERNAL void PsndReset(void) { // PsndRerate calls YM2612Init, which also resets @@ -88,12 +68,9 @@ void PsndRerate(int preserve_state) Pico.snd.len_e_cnt = 0; // Q16 // samples per line (Q16) - Pico.snd.fm_mult = 65536LL * PicoIn.sndRate / (target_fps*target_lines); + Pico.snd.smpl_mult = 65536LL * PicoIn.sndRate / (target_fps*target_lines); // samples per z80 clock (Q20) - Pico.snd.dac_mult = 16 * Pico.snd.fm_mult * 15/7 / 488; - - // recalculate dac info - dac_recalculate(); + Pico.snd.clkl_mult = 16 * Pico.snd.smpl_mult * 15/7 / 488; // clear all buffers memset32(PsndBuffer, 0, sizeof(PsndBuffer)/4); @@ -118,8 +95,6 @@ PICO_INTERNAL void PsndStartFrame(void) Pico.snd.len_e_cnt -= 0x10000; Pico.snd.len_use++; } - - Pico.snd.psg_line = 0; } PICO_INTERNAL void PsndDoDAC(int cyc_to) @@ -128,7 +103,7 @@ PICO_INTERNAL void PsndDoDAC(int cyc_to) int dout = ym2612.dacout; // number of samples to fill in buffer (Q20) - len = (cyc_to * Pico.snd.dac_mult) - Pico.snd.dac_pos; + len = (cyc_to * Pico.snd.clkl_mult) - Pico.snd.dac_pos; // update position and calculate buffer offset and length pos = (Pico.snd.dac_pos+0x80000) >> 20; @@ -163,17 +138,18 @@ PICO_INTERNAL void PsndDoDAC(int cyc_to) PICO_INTERNAL void PsndDoPSG(int line_to) { - int line_from = Pico.snd.psg_line; - int pos, pos1, len; + int pos, len; int stereo = 0; - pos = dac_info[line_from]; - pos1 = dac_info[line_to + 1]; - len = pos1 - pos; + // Q16, number of samples since last call + len = ((line_to+1) * Pico.snd.smpl_mult) - Pico.snd.psg_pos; if (len <= 0) return; - Pico.snd.psg_line = line_to + 1; + // update position and calculate buffer offset and length + pos = (Pico.snd.psg_pos+0x8000) >> 16; + Pico.snd.psg_pos += len; + len = ((Pico.snd.psg_pos+0x8000) >> 16) - pos; if (!PicoIn.sndOut || !(PicoIn.opt & POPT_EN_PSG)) return; @@ -185,22 +161,22 @@ PICO_INTERNAL void PsndDoPSG(int line_to) SN76496Update(PicoIn.sndOut + pos, len, stereo); } -PICO_INTERNAL void PsndDoFM(int line_to) +PICO_INTERNAL void PsndDoFM(int cyc_to) { int pos, len; int stereo = 0; // Q16, number of samples since last call - len = ((line_to-1) * Pico.snd.fm_mult) - Pico.snd.fm_pos; + len = (cyc_to * Pico.snd.clkl_mult) - Pico.snd.fm_pos; // don't do this too often (about every 4th scanline) - if (len >> 16 <= PicoIn.sndRate >> 12) + if (len >> 20 <= PicoIn.sndRate >> 12) return; // update position and calculate buffer offset and length - pos = (Pico.snd.fm_pos+0x8000) >> 16; + pos = (Pico.snd.fm_pos+0x80000) >> 20; Pico.snd.fm_pos += len; - len = ((Pico.snd.fm_pos+0x8000) >> 16) - pos; + len = ((Pico.snd.fm_pos+0x80000) >> 20) - pos; // fill buffer if (PicoIn.opt & POPT_EN_STEREO) { @@ -273,7 +249,7 @@ PICO_INTERNAL void PsndClear(void) if (!(PicoIn.opt & POPT_EN_FM)) memset32(PsndBuffer, 0, PicoIn.opt & POPT_EN_STEREO ? len*2 : len); // drop pos remainder to avoid rounding errors (not entirely correct though) - Pico.snd.dac_pos = Pico.snd.fm_pos = 0; + Pico.snd.dac_pos = Pico.snd.fm_pos = Pico.snd.psg_pos = 0; } @@ -281,7 +257,7 @@ static int PsndRender(int offset, int length) { int *buf32; int stereo = (PicoIn.opt & 8) >> 3; - int fmlen = ((Pico.snd.fm_pos+0x8000) >> 16); + int fmlen = ((Pico.snd.fm_pos+0x80000) >> 20); int daclen = ((Pico.snd.dac_pos+0x80000) >> 20); buf32 = PsndBuffer+(offset< 0) { short *dacbuf = PicoIn.sndOut + (daclen << stereo); Pico.snd.dac_pos += (length-daclen) << 20; - for (; length-daclen > 0; daclen++) { + *dacbuf++ += Pico.snd.dac_val2; + if (stereo) dacbuf++; + for (daclen++; length-daclen > 0; daclen++) { *dacbuf++ += Pico.snd.dac_val; if (stereo) dacbuf++; } + Pico.snd.dac_val2 = Pico.snd.dac_val; } // Add in parts of the FM buffer not yet done if (length-fmlen > 0) { int *fmbuf = buf32 + ((fmlen-offset) << stereo); - Pico.snd.fm_pos += (length-fmlen) << 16; + Pico.snd.fm_pos += (length-fmlen) << 20; if (PicoIn.opt & POPT_EN_FM) YM2612UpdateOne(fmbuf, length-fmlen, stereo, 1); } @@ -344,8 +323,6 @@ PICO_INTERNAL void PsndGetSamples(int y) { static int curr_pos = 0; - if (ym2612.dacen) - PsndDoDAC(cycles_68k_to_z80(Pico.t.m68c_aim - Pico.t.m68c_frame_start)); PsndDoPSG(y - 1); curr_pos = PsndRender(0, Pico.snd.len_use); -- 2.39.2