1 /*
2  * PicoDrive
3  * (c) Copyright Dave, 2004
4  * (C) notaz, 2006-2009
5  *
6  * This work is licensed under the terms of MAME license.
7  * See COPYING file in the top-level directory.
8  */
9 
10 #include <string.h>
11 #include "ym2612.h"
12 #include "sn76496.h"
13 #include "../pico_int.h"
14 #include "../cd/cue.h"
15 #include "mix.h"
16 #include "emu2413/emu2413.h"
17 
18 void (*PsndMix_32_to_16l)(short *dest, int *src, int count) = mix_32_to_16l_stereo;
19 
20 // master int buffer to mix to
21 static int PsndBuffer[2*(44100+100)/50];
22 
23 // cdda output buffer
24 short cdda_out_buffer[2*1152];
25 
26 // sn76496
27 extern int *sn76496_regs;
28 
29 // ym2413
30 #define YM2413_CLK 3579545
31 OPLL old_opll;
32 static OPLL *opll = NULL;
33 unsigned YM2413_reg;
34 
35 
PsndInit(void)36 PICO_INTERNAL void PsndInit(void)
37 {
38   opll = OPLL_new(YM2413_CLK, PicoIn.sndRate);
39   OPLL_setChipType(opll,0);
40   OPLL_reset(opll);
41 }
42 
PsndExit(void)43 PICO_INTERNAL void PsndExit(void)
44 {
45   OPLL_delete(opll);
46   opll = NULL;
47 }
48 
PsndReset(void)49 PICO_INTERNAL void PsndReset(void)
50 {
51   // PsndRerate calls YM2612Init, which also resets
52   PsndRerate(0);
53   timers_reset();
54 
55   mix_reset(PicoIn.sndFilter ? PicoIn.sndFilterRange : 0);
56 }
57 
58 
59 // to be called after changing sound rate or chips
PsndRerate(int preserve_state)60 void PsndRerate(int preserve_state)
61 {
62   void *state = NULL;
63   int target_fps = Pico.m.pal ? 50 : 60;
64   int target_lines = Pico.m.pal ? 313 : 262;
65 
66   if (preserve_state) {
67     state = malloc(0x204);
68     if (state == NULL) return;
69     ym2612_pack_state();
70     memcpy(state, YM2612GetRegs(), 0x204);
71   }
72   YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PicoIn.sndRate, !(PicoIn.opt&POPT_DIS_FM_SSGEG));
73   if (preserve_state) {
74     // feed it back it's own registers, just like after loading state
75     memcpy(YM2612GetRegs(), state, 0x204);
76     ym2612_unpack_state();
77   }
78 
79   if (preserve_state) memcpy(state, sn76496_regs, 28*4); // remember old state
80   SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PicoIn.sndRate);
81   if (preserve_state) memcpy(sn76496_regs, state, 28*4); // restore old state
82 
83   if(opll != NULL){
84     if (preserve_state) memcpy(&old_opll, opll, sizeof(OPLL)); // remember old state
85     OPLL_setRate(opll, PicoIn.sndRate);
86     OPLL_reset(opll);
87   }
88 
89   if (state)
90     free(state);
91 
92   // calculate Pico.snd.len
93   Pico.snd.len = PicoIn.sndRate / target_fps;
94   Pico.snd.len_e_add = ((PicoIn.sndRate - Pico.snd.len * target_fps) << 16) / target_fps;
95   Pico.snd.len_e_cnt = 0; // Q16
96 
97   // samples per line (Q16)
98   Pico.snd.smpl_mult = 65536LL * PicoIn.sndRate / (target_fps*target_lines);
99   // samples per z80 clock (Q20)
100   Pico.snd.clkl_mult = 16 * Pico.snd.smpl_mult * 15/7 / 488;
101 
102   // clear all buffers
103   memset32(PsndBuffer, 0, sizeof(PsndBuffer)/4);
104   memset(cdda_out_buffer, 0, sizeof(cdda_out_buffer));
105   if (PicoIn.sndOut)
106     PsndClear();
107 
108   // set mixer
109   PsndMix_32_to_16l = (PicoIn.opt & POPT_EN_STEREO) ? mix_32_to_16l_stereo : mix_32_to_16_mono;
110 
111   if (PicoIn.AHW & PAHW_PICO)
112     PicoReratePico();
113 }
114 
115 
PsndStartFrame(void)116 PICO_INTERNAL void PsndStartFrame(void)
117 {
118   // compensate for float part of Pico.snd.len
119   Pico.snd.len_use = Pico.snd.len;
120   Pico.snd.len_e_cnt += Pico.snd.len_e_add;
121   if (Pico.snd.len_e_cnt >= 0x10000) {
122     Pico.snd.len_e_cnt -= 0x10000;
123     Pico.snd.len_use++;
124   }
125 }
126 
PsndDoDAC(int cyc_to)127 PICO_INTERNAL void PsndDoDAC(int cyc_to)
128 {
129   int pos, len;
130   int dout = ym2612.dacout;
131 
132   // number of samples to fill in buffer (Q20)
133   len = (cyc_to * Pico.snd.clkl_mult) - Pico.snd.dac_pos;
134 
135   // update position and calculate buffer offset and length
136   pos = (Pico.snd.dac_pos+0x80000) >> 20;
137   Pico.snd.dac_pos += len;
138   len = ((Pico.snd.dac_pos+0x80000) >> 20) - pos;
139 
140   // avoid loss of the 1st sample of a new block (Q rounding issues)
141   if (pos+len == 0)
142     len = 1, Pico.snd.dac_pos += 0x80000;
143   if (len <= 0)
144     return;
145 
146   if (!PicoIn.sndOut)
147     return;
148 
149   // fill buffer, applying a rather weak order 1 bessel IIR on the way
150   // y[n] = (x[n] + x[n-1])*(1/2) (3dB cutoff at 11025 Hz, no gain)
151   // 1 sample delay for correct IIR filtering over audio frame boundaries
152   if (PicoIn.opt & POPT_EN_STEREO) {
153     short *d = PicoIn.sndOut + pos*2;
154     // left channel only, mixed ro right channel in mixing phase
155     *d++ += Pico.snd.dac_val2; d++;
156     while (--len) *d++ += Pico.snd.dac_val, d++;
157   } else {
158     short *d = PicoIn.sndOut + pos;
159     *d++ += Pico.snd.dac_val2;
160     while (--len) *d++ += Pico.snd.dac_val;
161   }
162   Pico.snd.dac_val2 = (Pico.snd.dac_val + dout) >> 1;
163   Pico.snd.dac_val = dout;
164 }
165 
PsndDoPSG(int line_to)166 PICO_INTERNAL void PsndDoPSG(int line_to)
167 {
168   int pos, len;
169   int stereo = 0;
170 
171   // Q16, number of samples since last call
172   len = ((line_to+1) * Pico.snd.smpl_mult) - Pico.snd.psg_pos;
173   if (len <= 0)
174     return;
175 
176   // update position and calculate buffer offset and length
177   pos = (Pico.snd.psg_pos+0x8000) >> 16;
178   Pico.snd.psg_pos += len;
179   len = ((Pico.snd.psg_pos+0x8000) >> 16) - pos;
180 
181   if (!PicoIn.sndOut || !(PicoIn.opt & POPT_EN_PSG))
182     return;
183 
184   if (PicoIn.opt & POPT_EN_STEREO) {
185     stereo = 1;
186     pos <<= 1;
187   }
188   SN76496Update(PicoIn.sndOut + pos, len, stereo);
189 }
190 
191 #if 0
192 PICO_INTERNAL void PsndDoYM2413(int line_to)
193 {
194   int pos, len;
195   int stereo = 0;
196   short *buf;
197 
198   // Q16, number of samples since last call
199   len = ((line_to+1) * Pico.snd.smpl_mult) - Pico.snd.ym2413_pos;
200   if (len <= 0)
201     return;
202 
203   // update position and calculate buffer offset and length
204   pos = (Pico.snd.ym2413_pos+0x8000) >> 16;
205   Pico.snd.ym2413_pos += len;
206   len = ((Pico.snd.ym2413_pos+0x8000) >> 16) - pos;
207 
208   if (!PicoIn.sndOut || !(PicoIn.opt & POPT_EN_YM2413))
209     return;
210 
211   if (PicoIn.opt & POPT_EN_STEREO) {
212     stereo = 1;
213     pos <<= 1;
214   }
215 
216   buf = PicoIn.sndOut + pos;
217   while (len-- > 0) {
218     int16_t getdata = OPLL_calc(opll) * 3;
219     *buf++ += getdata;
220     buf += stereo; // only left for stereo, to be mixed to right later
221   }
222 }
223 #endif
224 
YM2413_regWrite(unsigned data)225 void YM2413_regWrite(unsigned data){
226   OPLL_writeIO(opll,0,data);
227 }
YM2413_dataWrite(unsigned data)228 void YM2413_dataWrite(unsigned data){
229   OPLL_writeIO(opll,1,data);
230 }
231 
232 
PsndDoFM(int cyc_to)233 PICO_INTERNAL void PsndDoFM(int cyc_to)
234 {
235   int pos, len;
236   int stereo = 0;
237 
238   // Q16, number of samples since last call
239   len = (cyc_to * Pico.snd.clkl_mult) - Pico.snd.fm_pos;
240 
241   // don't do this too often (about once every canline)
242   if (len >> 16 <= PicoIn.sndRate >> 10)
243     return;
244 
245   // update position and calculate buffer offset and length
246   pos = (Pico.snd.fm_pos+0x80000) >> 20;
247   Pico.snd.fm_pos += len;
248   len = ((Pico.snd.fm_pos+0x80000) >> 20) - pos;
249 
250   // fill buffer
251   if (PicoIn.opt & POPT_EN_STEREO) {
252     stereo = 1;
253     pos <<= 1;
254   }
255   if (PicoIn.opt & POPT_EN_FM)
256     YM2612UpdateOne(PsndBuffer + pos, len, stereo, 1);
257 }
258 
259 // cdda
cdda_raw_update(int * buffer,int length)260 static void cdda_raw_update(int *buffer, int length)
261 {
262   int ret, cdda_bytes, mult = 1;
263 
264   cdda_bytes = length*4;
265   if (PicoIn.sndRate <= 22050 + 100) mult = 2;
266   if (PicoIn.sndRate <  22050 - 100) mult = 4;
267   cdda_bytes *= mult;
268 
269   ret = pm_read(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream);
270   if (ret < cdda_bytes) {
271     memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret);
272     Pico_mcd->cdda_stream = NULL;
273     return;
274   }
275 
276   // now mix
277   switch (mult) {
278     case 1: mix_16h_to_32(buffer, cdda_out_buffer, length*2); break;
279     case 2: mix_16h_to_32_s1(buffer, cdda_out_buffer, length*2); break;
280     case 4: mix_16h_to_32_s2(buffer, cdda_out_buffer, length*2); break;
281   }
282 }
283 
cdda_start_play(int lba_base,int lba_offset,int lb_len)284 void cdda_start_play(int lba_base, int lba_offset, int lb_len)
285 {
286   if (Pico_mcd->cdda_type == CT_MP3)
287   {
288     int pos1024 = 0;
289 
290     if (lba_offset)
291       pos1024 = lba_offset * 1024 / lb_len;
292 
293     mp3_start_play(Pico_mcd->cdda_stream, pos1024);
294     return;
295   }
296 
297   pm_seek(Pico_mcd->cdda_stream, (lba_base + lba_offset) * 2352, SEEK_SET);
298   if (Pico_mcd->cdda_type == CT_WAV)
299   {
300     // skip headers, assume it's 44kHz stereo uncompressed
301     pm_seek(Pico_mcd->cdda_stream, 44, SEEK_CUR);
302   }
303 }
304 
305 
PsndClear(void)306 PICO_INTERNAL void PsndClear(void)
307 {
308   int len = Pico.snd.len;
309   if (Pico.snd.len_e_add) len++;
310   if (PicoIn.opt & POPT_EN_STEREO)
311     memset32((int *) PicoIn.sndOut, 0, len); // assume PicoIn.sndOut to be aligned
312   else {
313     short *out = PicoIn.sndOut;
314     if ((uintptr_t)out & 2) { *out++ = 0; len--; }
315     memset32((int *) out, 0, len/2);
316     if (len & 1) out[len-1] = 0;
317   }
318   if (!(PicoIn.opt & POPT_EN_FM))
319     memset32(PsndBuffer, 0, PicoIn.opt & POPT_EN_STEREO ? len*2 : len);
320   // drop pos remainder to avoid rounding errors (not entirely correct though)
321   Pico.snd.dac_pos = Pico.snd.fm_pos = Pico.snd.psg_pos = Pico.snd.ym2413_pos = 0;
322 }
323 
324 
PsndRender(int offset,int length)325 static int PsndRender(int offset, int length)
326 {
327   int *buf32;
328   int stereo = (PicoIn.opt & 8) >> 3;
329   int fmlen = ((Pico.snd.fm_pos+0x80000) >> 20);
330   int daclen = ((Pico.snd.dac_pos+0x80000) >> 20);
331   int psglen = ((Pico.snd.psg_pos+0x8000) >> 16);
332 
333   buf32 = PsndBuffer+(offset<<stereo);
334 
335   pprof_start(sound);
336 
337   if (PicoIn.AHW & PAHW_PICO) {
338     PicoPicoPCMUpdate(PicoIn.sndOut+(offset<<stereo), length-offset, stereo);
339     return length;
340   }
341 
342   // Fill up DAC output in case of missing samples (Q16 rounding errors)
343   if (length-daclen > 0) {
344     short *dacbuf = PicoIn.sndOut + (daclen << stereo);
345     Pico.snd.dac_pos += (length-daclen) << 20;
346     *dacbuf++ += Pico.snd.dac_val2;
347     if (stereo) dacbuf++;
348     for (daclen++; length-daclen > 0; daclen++) {
349       *dacbuf++ += Pico.snd.dac_val;
350       if (stereo) dacbuf++;
351     }
352     Pico.snd.dac_val2 = Pico.snd.dac_val;
353   }
354 
355   // Add in parts of the PSG output not yet done
356   if (length-psglen > 0) {
357     short *psgbuf = PicoIn.sndOut + (psglen << stereo);
358     Pico.snd.psg_pos += (length-psglen) << 16;
359     if (PicoIn.opt & POPT_EN_PSG)
360       SN76496Update(psgbuf, length-psglen, stereo);
361   }
362 
363   // Add in parts of the FM buffer not yet done
364   if (length-fmlen > 0) {
365     int *fmbuf = buf32 + ((fmlen-offset) << stereo);
366     Pico.snd.fm_pos += (length-fmlen) << 20;
367     if (PicoIn.opt & POPT_EN_FM)
368       YM2612UpdateOne(fmbuf, length-fmlen, stereo, 1);
369   }
370 
371   // CD: PCM sound
372   if (PicoIn.AHW & PAHW_MCD) {
373     pcd_pcm_update(buf32, length-offset, stereo);
374   }
375 
376   // CD: CDDA audio
377   // CD mode, cdda enabled, not data track, CDC is reading
378   if ((PicoIn.AHW & PAHW_MCD) && (PicoIn.opt & POPT_EN_MCD_CDDA)
379       && Pico_mcd->cdda_stream != NULL
380       && !(Pico_mcd->s68k_regs[0x36] & 1))
381   {
382     // note: only 44, 22 and 11 kHz supported, with forced stereo
383     if (Pico_mcd->cdda_type == CT_MP3)
384       mp3_update(buf32, length-offset, stereo);
385     else
386       cdda_raw_update(buf32, length-offset);
387   }
388 
389   if ((PicoIn.AHW & PAHW_32X) && (PicoIn.opt & POPT_EN_PWM))
390     p32x_pwm_update(buf32, length-offset, stereo);
391 
392   // convert + limit to normal 16bit output
393   PsndMix_32_to_16l(PicoIn.sndOut+(offset<<stereo), buf32, length-offset);
394 
395   pprof_end(sound);
396 
397   return length;
398 }
399 
PsndGetSamples(int y)400 PICO_INTERNAL void PsndGetSamples(int y)
401 {
402   static int curr_pos = 0;
403 
404   curr_pos  = PsndRender(0, Pico.snd.len_use);
405 
406   if (PicoIn.writeSound)
407     PicoIn.writeSound(curr_pos * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
408   // clear sound buffer
409   PsndClear();
410 }
411 
PsndRenderMS(int offset,int length)412 static int PsndRenderMS(int offset, int length)
413 {
414   int stereo = (PicoIn.opt & 8) >> 3;
415   int psglen = ((Pico.snd.psg_pos+0x8000) >> 16);
416   int ym2413len = ((Pico.snd.ym2413_pos+0x8000) >> 16);
417 
418   pprof_start(sound);
419 
420   // Add in parts of the PSG output not yet done
421   if (length-psglen > 0) {
422     short *psgbuf = PicoIn.sndOut + (psglen << stereo);
423     Pico.snd.psg_pos += (length-psglen) << 16;
424     if (PicoIn.opt & POPT_EN_PSG)
425       SN76496Update(psgbuf, length-psglen, stereo);
426   }
427 
428   if (length-ym2413len > 0) {
429     short *ym2413buf = PicoIn.sndOut + (ym2413len << stereo);
430     Pico.snd.ym2413_pos += (length-ym2413len) << 16;
431     int len = (length-ym2413len);
432     if (PicoIn.opt & POPT_EN_YM2413){
433       while (len-- > 0) {
434         int16_t getdata = OPLL_calc(opll) * 3;
435         *ym2413buf += getdata;
436         ym2413buf += 1<<stereo;
437       }
438     }
439   }
440 
441   // upmix to "stereo" if needed
442   if (PicoIn.opt & POPT_EN_STEREO) {
443     int i;
444     short *p;
445     for (i = length, p = (short *)PicoIn.sndOut; i > 0; i--, p+=2)
446       *(p + 1) = *p;
447   }
448 
449   pprof_end(sound);
450 
451   return length;
452 }
453 
PsndGetSamplesMS(int y)454 PICO_INTERNAL void PsndGetSamplesMS(int y)
455 {
456   static int curr_pos = 0;
457 
458   curr_pos  = PsndRenderMS(0, Pico.snd.len_use);
459 
460   if (PicoIn.writeSound != NULL)
461     PicoIn.writeSound(curr_pos * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
462   PsndClear();
463 }
464 
465 // vim:shiftwidth=2:ts=2:expandtab
466