Explorar o código

audio: improve cycle accuracy of SN76496+YM2612

kub %!s(int64=4) %!d(string=hai) anos
pai
achega
09b96f9940
Modificáronse 4 ficheiros con 32 adicións e 56 borrados
  1. 3 4
      pico/memory.c
  2. 6 6
      pico/pico_int.h
  3. 1 1
      pico/sms.c
  4. 22 45
      pico/sound/sound.c

+ 3 - 4
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);
 }
 

+ 6 - 6
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

+ 1 - 1
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;

+ 22 - 45
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<<stereo);
@@ -297,16 +273,19 @@ static int PsndRender(int offset, int length)
   if (length-daclen > 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);