improve 64bit portability
[picodrive.git] / pico / sound / sound.c
CommitLineData
cff531af 1/*\r
2 * PicoDrive\r
3 * (c) Copyright Dave, 2004\r
4 * (C) notaz, 2006-2009\r
5 *\r
6 * This work is licensed under the terms of MAME license.\r
7 * See COPYING file in the top-level directory.\r
8 */\r
cc68a136 9\r
10#include <string.h>\r
cc68a136 11#include "ym2612.h"\r
12#include "sn76496.h"\r
efcba75f 13#include "../pico_int.h"\r
e71fae1f 14#include "../cd/cue.h"\r
4f265db7 15#include "mix.h"\r
cc68a136 16\r
4a32f01f 17void (*PsndMix_32_to_16l)(short *dest, int *src, int count) = mix_32_to_16l_stereo;\r
18\r
4f265db7 19// master int buffer to mix to\r
02da059d 20static int PsndBuffer[2*(44100+100)/50];\r
cc68a136 21\r
5d638db0 22// dac, psg\r
4f2cdbf5 23static unsigned short dac_info[312+4]; // pos in sample buffer\r
cc68a136 24\r
c9e1affc 25// cdda output buffer\r
26short cdda_out_buffer[2*1152];\r
27\r
cc68a136 28// sn76496\r
29extern int *sn76496_regs;\r
30\r
31\r
eff55556 32static void dac_recalculate(void)\r
cc68a136 33{\r
6311a3ba 34 int lines = Pico.m.pal ? 313 : 262;\r
35 int mid = Pico.m.pal ? 68 : 93;\r
36 int i, dac_cnt, pos, len;\r
cc68a136 37\r
6311a3ba 38 if (Pico.snd.len <= lines)\r
43e6eaad 39 {\r
cc68a136 40 // shrinking algo\r
6311a3ba 41 dac_cnt = -Pico.snd.len;\r
cc68a136 42 len=1; pos=0;\r
43 dac_info[225] = 1;\r
44\r
43e6eaad 45 for(i=226; i != 225; i++)\r
46 {\r
cc68a136 47 if (i >= lines) i = 0;\r
cc68a136 48 if(dac_cnt < 0) {\r
cc68a136 49 pos++;\r
50 dac_cnt += lines;\r
51 }\r
6311a3ba 52 dac_cnt -= Pico.snd.len;\r
4f2cdbf5 53 dac_info[i] = pos;\r
cc68a136 54 }\r
43e6eaad 55 }\r
56 else\r
57 {\r
cc68a136 58 // stretching\r
6311a3ba 59 dac_cnt = Pico.snd.len;\r
cc68a136 60 pos=0;\r
43e6eaad 61 for(i = 225; i != 224; i++)\r
62 {\r
cc68a136 63 if (i >= lines) i = 0;\r
64 len=0;\r
65 while(dac_cnt >= 0) {\r
66 dac_cnt -= lines;\r
67 len++;\r
68 }\r
4f265db7 69 if (i == mid) // midpoint\r
6311a3ba 70 while(pos+len < Pico.snd.len/2) {\r
cc68a136 71 dac_cnt -= lines;\r
72 len++;\r
73 }\r
6311a3ba 74 dac_cnt += Pico.snd.len;\r
4f2cdbf5 75 pos += len;\r
76 dac_info[i] = pos;\r
cc68a136 77 }\r
cc68a136 78 }\r
4b9c5888 79 for (i = lines; i < sizeof(dac_info) / sizeof(dac_info[0]); i++)\r
4f2cdbf5 80 dac_info[i] = dac_info[0];\r
cc68a136 81}\r
82\r
83\r
9d917eea 84PICO_INTERNAL void PsndReset(void)\r
cc68a136 85{\r
af37bca8 86 // PsndRerate calls YM2612Init, which also resets\r
9d917eea 87 PsndRerate(0);\r
af37bca8 88 timers_reset();\r
cc68a136 89}\r
90\r
91\r
92// to be called after changing sound rate or chips\r
9d917eea 93void PsndRerate(int preserve_state)\r
cc68a136 94{\r
5f8c85be 95 void *state = NULL;\r
7a93adeb 96 int target_fps = Pico.m.pal ? 50 : 60;\r
cc68a136 97\r
7a93adeb 98 if (preserve_state) {\r
d8afe7b8 99 state = malloc(0x204);\r
5f8c85be 100 if (state == NULL) return;\r
d8afe7b8 101 ym2612_pack_state();\r
102 memcpy(state, YM2612GetRegs(), 0x204);\r
7a93adeb 103 }\r
6311a3ba 104 YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PicoIn.sndRate);\r
7a93adeb 105 if (preserve_state) {\r
106 // feed it back it's own registers, just like after loading state\r
d8afe7b8 107 memcpy(YM2612GetRegs(), state, 0x204);\r
453d2a6e 108 ym2612_unpack_state();\r
7a93adeb 109 }\r
cc68a136 110\r
7a93adeb 111 if (preserve_state) memcpy(state, sn76496_regs, 28*4); // remember old state\r
6311a3ba 112 SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PicoIn.sndRate);\r
7a93adeb 113 if (preserve_state) memcpy(sn76496_regs, state, 28*4); // restore old state\r
cc68a136 114\r
5f8c85be 115 if (state)\r
116 free(state);\r
117\r
6311a3ba 118 // calculate Pico.snd.len\r
119 Pico.snd.len = PicoIn.sndRate / target_fps;\r
120 Pico.snd.len_e_add = ((PicoIn.sndRate - Pico.snd.len * target_fps) << 16) / target_fps;\r
121 Pico.snd.len_e_cnt = 0;\r
cc68a136 122\r
123 // recalculate dac info\r
124 dac_recalculate();\r
4f265db7 125\r
7a93adeb 126 // clear all buffers\r
127 memset32(PsndBuffer, 0, sizeof(PsndBuffer)/4);\r
c9e1affc 128 memset(cdda_out_buffer, 0, sizeof(cdda_out_buffer));\r
6311a3ba 129 if (PicoIn.sndOut)\r
9d917eea 130 PsndClear();\r
4a32f01f 131\r
132 // set mixer\r
93f9619e 133 PsndMix_32_to_16l = (PicoIn.opt & POPT_EN_STEREO) ? mix_32_to_16l_stereo : mix_32_to_16_mono;\r
ed367a3f 134\r
93f9619e 135 if (PicoIn.AHW & PAHW_PICO)\r
ed367a3f 136 PicoReratePico();\r
cc68a136 137}\r
138\r
139\r
4f2cdbf5 140PICO_INTERNAL void PsndStartFrame(void)\r
141{\r
6311a3ba 142 // compensate for float part of Pico.snd.len\r
143 Pico.snd.len_use = Pico.snd.len;\r
144 Pico.snd.len_e_cnt += Pico.snd.len_e_add;\r
145 if (Pico.snd.len_e_cnt >= 0x10000) {\r
146 Pico.snd.len_e_cnt -= 0x10000;\r
147 Pico.snd.len_use++;\r
4f2cdbf5 148 }\r
149\r
6311a3ba 150 Pico.snd.dac_line = Pico.snd.psg_line = 0;\r
93f9619e 151 Pico.m.status &= ~1;\r
6311a3ba 152 dac_info[224] = Pico.snd.len_use;\r
4f2cdbf5 153}\r
154\r
4b9c5888 155PICO_INTERNAL void PsndDoDAC(int line_to)\r
cc68a136 156{\r
4b9c5888 157 int pos, pos1, len;\r
158 int dout = ym2612.dacout;\r
6311a3ba 159 int line_from = Pico.snd.dac_line;\r
4f265db7 160\r
e42a47e2 161 if (line_to >= 313)\r
162 line_to = 312;\r
9b5713af 163\r
4f2cdbf5 164 pos = dac_info[line_from];\r
165 pos1 = dac_info[line_to + 1];\r
166 len = pos1 - pos;\r
167 if (len <= 0)\r
168 return;\r
169\r
6311a3ba 170 Pico.snd.dac_line = line_to + 1;\r
4f265db7 171\r
6311a3ba 172 if (!PicoIn.sndOut)\r
4f2cdbf5 173 return;\r
4f265db7 174\r
93f9619e 175 if (PicoIn.opt & POPT_EN_STEREO) {\r
6311a3ba 176 short *d = PicoIn.sndOut + pos*2;\r
5d638db0 177 for (; len > 0; len--, d+=2) *d += dout;\r
4b9c5888 178 } else {\r
6311a3ba 179 short *d = PicoIn.sndOut + pos;\r
5d638db0 180 for (; len > 0; len--, d++) *d += dout;\r
cc68a136 181 }\r
4f265db7 182}\r
cc68a136 183\r
5d638db0 184PICO_INTERNAL void PsndDoPSG(int line_to)\r
185{\r
6311a3ba 186 int line_from = Pico.snd.psg_line;\r
5d638db0 187 int pos, pos1, len;\r
188 int stereo = 0;\r
189\r
e42a47e2 190 if (line_to >= 313)\r
191 line_to = 312;\r
5d638db0 192\r
193 pos = dac_info[line_from];\r
194 pos1 = dac_info[line_to + 1];\r
195 len = pos1 - pos;\r
196 //elprintf(EL_STATUS, "%3d %3d %3d %3d %3d",\r
197 // pos, pos1, len, line_from, line_to);\r
198 if (len <= 0)\r
199 return;\r
200\r
6311a3ba 201 Pico.snd.psg_line = line_to + 1;\r
5d638db0 202\r
6311a3ba 203 if (!PicoIn.sndOut || !(PicoIn.opt & POPT_EN_PSG))\r
5d638db0 204 return;\r
205\r
93f9619e 206 if (PicoIn.opt & POPT_EN_STEREO) {\r
5d638db0 207 stereo = 1;\r
208 pos <<= 1;\r
209 }\r
6311a3ba 210 SN76496Update(PicoIn.sndOut + pos, len, stereo);\r
5d638db0 211}\r
212\r
c9e1affc 213// cdda\r
c9e1affc 214static void cdda_raw_update(int *buffer, int length)\r
215{\r
02da059d 216 int ret, cdda_bytes, mult = 1;\r
c9e1affc 217\r
218 cdda_bytes = length*4;\r
6311a3ba 219 if (PicoIn.sndRate <= 22050 + 100) mult = 2;\r
220 if (PicoIn.sndRate < 22050 - 100) mult = 4;\r
02da059d 221 cdda_bytes *= mult;\r
c9e1affc 222\r
274fcc35 223 ret = pm_read(cdda_out_buffer, cdda_bytes, Pico_mcd->cdda_stream);\r
c9e1affc 224 if (ret < cdda_bytes) {\r
225 memset((char *)cdda_out_buffer + ret, 0, cdda_bytes - ret);\r
274fcc35 226 Pico_mcd->cdda_stream = NULL;\r
c9e1affc 227 return;\r
228 }\r
229\r
230 // now mix\r
02da059d 231 switch (mult) {\r
232 case 1: mix_16h_to_32(buffer, cdda_out_buffer, length*2); break;\r
233 case 2: mix_16h_to_32_s1(buffer, cdda_out_buffer, length*2); break;\r
234 case 4: mix_16h_to_32_s2(buffer, cdda_out_buffer, length*2); break;\r
c9e1affc 235 }\r
236}\r
237\r
274fcc35 238void cdda_start_play(int lba_base, int lba_offset, int lb_len)\r
c9e1affc 239{\r
274fcc35 240 if (Pico_mcd->cdda_type == CT_MP3)\r
c9e1affc 241 {\r
242 int pos1024 = 0;\r
243\r
c9e1affc 244 if (lba_offset)\r
274fcc35 245 pos1024 = lba_offset * 1024 / lb_len;\r
c9e1affc 246\r
274fcc35 247 mp3_start_play(Pico_mcd->cdda_stream, pos1024);\r
c9e1affc 248 return;\r
249 }\r
250\r
274fcc35 251 pm_seek(Pico_mcd->cdda_stream, (lba_base + lba_offset) * 2352, SEEK_SET);\r
252 if (Pico_mcd->cdda_type == CT_WAV)\r
0bccafeb 253 {\r
254 // skip headers, assume it's 44kHz stereo uncompressed\r
274fcc35 255 pm_seek(Pico_mcd->cdda_stream, 44, SEEK_CUR);\r
0bccafeb 256 }\r
c9e1affc 257}\r
258\r
cc68a136 259\r
9d917eea 260PICO_INTERNAL void PsndClear(void)\r
4f265db7 261{\r
6311a3ba 262 int len = Pico.snd.len;\r
263 if (Pico.snd.len_e_add) len++;\r
93f9619e 264 if (PicoIn.opt & POPT_EN_STEREO)\r
6311a3ba 265 memset32((int *) PicoIn.sndOut, 0, len); // assume PicoIn.sndOut to be aligned\r
88b3d7c1 266 else {\r
6311a3ba 267 short *out = PicoIn.sndOut;\r
48c9e01b 268 if ((uintptr_t)out & 2) { *out++ = 0; len--; }\r
88b3d7c1 269 memset32((int *) out, 0, len/2);\r
270 if (len & 1) out[len-1] = 0;\r
271 }\r
cc68a136 272}\r
273\r
274\r
7b3f44c6 275static int PsndRender(int offset, int length)\r
cc68a136 276{\r
85f8e929 277 int buf32_updated = 0;\r
4f265db7 278 int *buf32 = PsndBuffer+offset;\r
93f9619e 279 int stereo = (PicoIn.opt & 8) >> 3;\r
33be04ca 280\r
cc68a136 281 offset <<= stereo;\r
282\r
f6c49d38 283 pprof_start(sound);\r
284\r
93f9619e 285 if (PicoIn.AHW & PAHW_PICO) {\r
6311a3ba 286 PicoPicoPCMUpdate(PicoIn.sndOut+offset, length, stereo);\r
ef4eb506 287 return length;\r
288 }\r
289\r
cc68a136 290 // Add in the stereo FM buffer\r
93f9619e 291 if (PicoIn.opt & POPT_EN_FM) {\r
85f8e929 292 buf32_updated = YM2612UpdateOne(buf32, length, stereo, 1);\r
3ec29f01 293 } else\r
fa1e5e29 294 memset32(buf32, 0, length<<stereo);\r
85f8e929 295\r
296//printf("active_chs: %02x\n", buf32_updated);\r
e743be20 297 (void)buf32_updated;\r
4f265db7 298\r
7a93adeb 299 // CD: PCM sound\r
93f9619e 300 if (PicoIn.AHW & PAHW_MCD) {\r
33be04ca 301 pcd_pcm_update(buf32, length, stereo);\r
85f8e929 302 //buf32_updated = 1;\r
303 }\r
4f265db7 304\r
7a93adeb 305 // CD: CDDA audio\r
da42200b 306 // CD mode, cdda enabled, not data track, CDC is reading\r
93f9619e 307 if ((PicoIn.AHW & PAHW_MCD) && (PicoIn.opt & POPT_EN_MCD_CDDA)\r
274fcc35 308 && Pico_mcd->cdda_stream != NULL\r
309 && !(Pico_mcd->s68k_regs[0x36] & 1))\r
c9e1affc 310 {\r
311 // note: only 44, 22 and 11 kHz supported, with forced stereo\r
274fcc35 312 if (Pico_mcd->cdda_type == CT_MP3)\r
c9e1affc 313 mp3_update(buf32, length, stereo);\r
314 else\r
315 cdda_raw_update(buf32, length);\r
316 }\r
4f265db7 317\r
93f9619e 318 if ((PicoIn.AHW & PAHW_32X) && (PicoIn.opt & POPT_EN_PWM))\r
db1d3564 319 p32x_pwm_update(buf32, length, stereo);\r
320\r
4f265db7 321 // convert + limit to normal 16bit output\r
6311a3ba 322 PsndMix_32_to_16l(PicoIn.sndOut+offset, buf32, length);\r
cc68a136 323\r
f6c49d38 324 pprof_end(sound);\r
325\r
7a93adeb 326 return length;\r
cc68a136 327}\r
328\r
7b3f44c6 329// to be called on 224 or line_sample scanlines only\r
330PICO_INTERNAL void PsndGetSamples(int y)\r
331{\r
7b3f44c6 332 static int curr_pos = 0;\r
333\r
6311a3ba 334 if (ym2612.dacen && Pico.snd.dac_line < y)\r
4f2cdbf5 335 PsndDoDAC(y - 1);\r
5d638db0 336 PsndDoPSG(y - 1);\r
4f2cdbf5 337\r
7b3f44c6 338 if (y == 224)\r
339 {\r
93f9619e 340 if (Pico.m.status & 2)\r
6311a3ba 341 curr_pos += PsndRender(curr_pos, Pico.snd.len-Pico.snd.len/2);\r
342 else curr_pos = PsndRender(0, Pico.snd.len_use);\r
93f9619e 343 if (Pico.m.status & 1)\r
344 Pico.m.status |= 2;\r
345 else Pico.m.status &= ~2;\r
6311a3ba 346 if (PicoIn.writeSound)\r
347 PicoIn.writeSound(curr_pos * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));\r
7b3f44c6 348 // clear sound buffer\r
349 PsndClear();\r
6311a3ba 350 Pico.snd.dac_line = 224;\r
4f2cdbf5 351 dac_info[224] = 0;\r
7b3f44c6 352 }\r
93f9619e 353 else if (Pico.m.status & 3) {\r
354 Pico.m.status |= 2;\r
355 Pico.m.status &= ~1;\r
6311a3ba 356 curr_pos = PsndRender(0, Pico.snd.len/2);\r
7b3f44c6 357 }\r
7b3f44c6 358}\r
359\r
2ec9bec5 360PICO_INTERNAL void PsndGetSamplesMS(void)\r
361{\r
6311a3ba 362 int length = Pico.snd.len_use;\r
2ec9bec5 363\r
075672bf 364 PsndDoPSG(223);\r
2ec9bec5 365\r
19954be1 366 // upmix to "stereo" if needed\r
075672bf 367 if (PicoIn.opt & POPT_EN_STEREO) {\r
8a19f430 368 int i, *p;\r
6311a3ba 369 for (i = length, p = (void *)PicoIn.sndOut; i > 0; i--, p++)\r
19954be1 370 *p |= *p << 16;\r
371 }\r
2ec9bec5 372\r
6311a3ba 373 if (PicoIn.writeSound != NULL)\r
374 PicoIn.writeSound(length * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));\r
2ec9bec5 375 PsndClear();\r
075672bf 376\r
377 dac_info[224] = 0;\r
2ec9bec5 378}\r
379\r
4f2cdbf5 380// vim:shiftwidth=2:ts=2:expandtab\r