1 #include "mix.h"
2
3 #if defined(SDL)
4 #include <SDL_audio.h>
5
6 #if defined(LINUX) || defined(FREEBSD)
7 #include "osd_linux_sdl_machine.h"
8 #elif defined(SOLARIS)
9 #include "osd_unix_sdl_machine.h"
10 #elif defined(WIN32)
11 #include "osd_win_sdl_machine.h"
12 #else
13 #warning no machine defined for SDL audio include
14 #endif
15
16 #endif
17
update_sound_null(void)18 void update_sound_null(void)
19 {
20 }
21
22
update_sound_allegro(void)23 void update_sound_allegro(void)
24 {
25 #ifdef ALLEGRO
26 int dum;
27 char ch;
28
29 static where_to_fill = 0;
30 static remaining_to_fill = 0;
31 static remaining_to_read = 0;
32
33 #ifndef FINAL_RELEASE
34 // Log("Entering %s\n",__FUNCTION__);
35 #endif
36
37 // fill each channel specific buffer
38 for (ch = 0; ch < 6; ch++)
39 write_psg (ch);
40
41 write_adpcm ();
42
43 // Log("%d/%d\n", dwNewPos, SBUF_SIZE_BYTE);
44
45 if (dwNewPos > SBUF_SIZE_BYTE)
46 dwNewPos = SBUF_SIZE_BYTE;
47
48 if (remaining_to_fill)
49 {
50 memcpy (big_buf, main_buf + remaining_to_read, remaining_to_fill);
51 where_to_fill = remaining_to_fill;
52 remaining_to_fill = 0;
53 remaining_to_read = 0;
54 }
55
56 // do a simplistic mixing (should be hard instead of this one)
57 /* TEST */
58 if (io.adpcm_psize > 1)
59 for (dum = 0; dum < dwNewPos; dum++)
60 main_buf[dum] = (
61 (
62 (sbuf[0][dum]
63 + sbuf[1][dum]
64 + sbuf[2][dum]
65 + sbuf[3][dum]
66 + sbuf[4][dum]
67 + sbuf[5][dum] + adpcmbuf[dum]) >> 2)) ^ 0x80;
68 // main_buf[dum] = (adpcmbuf[dum])^0x80;
69 else
70 for (dum = 0; dum < dwNewPos; dum++)
71 main_buf[dum] =
72 ((sbuf[0][dum] + sbuf[1][dum] + sbuf[2][dum] + sbuf[3][dum] +
73 sbuf[4][dum] + sbuf[5][dum]) >> 2) ^ 0x80;
74
75 {
76
77 int size;
78 unsigned char *p;
79
80 #if defined(LINUX) || defined(MSDOS)
81 if (MP3_playing)
82 run_amp ();
83 #endif
84
85 size = dwNewPos;
86
87 if (where_to_fill + size < sbuf_size)
88 {
89 memcpy (big_buf + where_to_fill, main_buf, size);
90 where_to_fill += size;
91 }
92 else
93 {
94 memcpy (big_buf + where_to_fill, main_buf, sbuf_size - where_to_fill);
95 remaining_to_read = sbuf_size - where_to_fill;
96 remaining_to_fill = size - remaining_to_read;
97 where_to_fill = 0;
98
99 // if dump asked, write in a file
100 if (dump_snd)
101 fwrite (big_buf, 1, sbuf_size, out_snd);
102
103 while (!(p = get_audio_stream_buffer (PCM_stream)));
104
105 memcpy (p, big_buf, sbuf_size);
106
107 free_audio_stream_buffer (PCM_stream);
108
109 }
110
111 }
112 #endif
113 }
114
115
116 #ifndef MSDOS
117
118 void (*update_sound[4])() =
119 {
120 update_sound_null, update_sound_allegro, update_sound_allegro, update_sound_null
121 };
122
123 /* SDL Audio Stuff */
124
125 unsigned char old;
126 Uint32 audio_len=0;
127
128 /* Callback for SDL Audio */
sdl_fill_audio(void * data,Uint8 * stream,int len)129 void sdl_fill_audio(void *data, Uint8 *stream, int len)
130 {
131 UChar lvol, rvol;
132 int i;
133 UChar center;
134 #ifdef SOUND_DEBUG
135 UChar first_chan;
136
137 //IXION
138 if ((first_chan = ((io.psg_lfo_ctrl & 3) == 0) ? 0 : 2) == 2)
139 ;
140 // printf("first_chan = 2\n");
141
142 for (i = first_chan; i < 6; i++)
143 #else
144 for (i = 0; i < 6; i++)
145 #endif
146 WriteBuffer(sbuf[i], i, len);
147
148 write_adpcm();
149
150 /*
151 * Adjust the final post-mixed left/right volumes. 0-15 * 1.22 comes out to
152 * (0..18) which when multiplied by the ((-127..127) * 7) we get in the final
153 * stream mix below we have (-16002..16002) which we then divide by 128 to get
154 * a nice unsigned 8-bit value of 128 + (-125..125).
155 */
156 if (host.sound.stereo)
157 {
158 lvol = (io.psg_volume >> 4) * 1.22;
159 rvol = (io.psg_volume & 0x0F) * 1.22;
160 }
161 else
162 {
163 /*
164 * Use the average of the two channels for mono
165 */
166 lvol = rvol = (((io.psg_volume >> 4) * 1.22) + ((io.psg_volume & 0x0F) * 1.22)) / 2;
167 }
168
169 SDL_LockAudio();
170
171 center = (host.sound.signed_sound?0:128);
172
173 /*
174 * Mix streams and apply master volume.
175 */
176 for (i = 0; i < len ; i++)
177 stream[i] = center + ((UInt32) ((sbuf[0][i] + sbuf[1][i] + sbuf[2][i] + sbuf[3][i] + sbuf[4][i] + sbuf[5][i] +
178 adpcmbuf[i]) * (!(i % 2) ? lvol : rvol)) >> 7);
179
180 SDL_UnlockAudio();
181
182 if (dump_snd) // We also have to write data into a file
183 {
184 dump_audio_chunck(stream, len);
185 }
186
187 }
188
189 #else /* MSDOS */
190
update_sound_seal(void)191 void update_sound_seal(void)
192 {
193 int dum;
194 char ch;
195 static int old = 0;
196
197 // fill each channel specific buffer
198 for (ch = 0; ch < 6; ch++)
199 write_psg (ch);
200
201 write_adpcm ();
202
203 // do a simplistic mixing (should be hard instead of this one)
204 /* TEST */
205
206 // Log("new pos = %d\n", dwNewPos);
207
208 /* TEST */
209 if (io.adpcm_psize > 1)
210 for (dum = 0; dum < dwNewPos; dum++)
211 main_buf[dum] = (
212 (
213 (sbuf[0][dum]
214 + sbuf[1][dum]
215 + sbuf[2][dum]
216 + sbuf[3][dum]
217 + sbuf[4][dum]
218 + sbuf[5][dum] + adpcmbuf[dum]) >> 2));
219 main_buf[dum] = (adpcmbuf[dum])^0x80;
220 else
221 for (dum = 0; dum < dwNewPos; dum++)
222 main_buf[dum] =
223 ((sbuf
224 [0][dum] + sbuf[1][dum] + sbuf[2][dum] + sbuf[3][dum] +
225 sbuf[4][dum] + sbuf[5][dum]) >> 2);
226
227 // for (dum=0;dum<dwNewPos;dum++)
228 // main_buf[dum]=((sbuf[0][dum]+sbuf[1][dum]+sbuf[2][dum]+sbuf[3][dum]+sbuf[4][dum]+sbuf[5][dum])>>2 );
229 // main_buf[dum]=adpcmbuf[dum] << 2;
230
231 #if defined(DOUBLE_BUFFER)
232
233 memcpy (lpWave->lpData + old_snd_pos, main_buf,
234 lpWave->dwLength - old_snd_pos);
235
236 if (old_snd_pos)
237 {
238
239 #ifndef FINAL_RELEASE
240 fprintf (stderr, "set loop end to %d\n", old_snd_pos + dwNewPos);
241 #endif
242 lpWave->dwLoopEnd = old_snd_pos + dwNewPos;
243 // set the loop end to the end of the sample
244
245 //ASetVoicePosition(hVoice,0);
246 AWriteAudioData (lpWave, 0L, lpWave->dwLength);
247
248 {
249 long dum;
250 do
251 {
252 AGetVoicePosition (hVoice, &dum);
253
254 #ifndef FINAL_RELEASE
255 fprintf (stderr, "%d / %d\n", dum, old_snd_pos + dwNewPos);
256 #endif
257
258 AUpdateAudio ();
259 }
260 while (dum > old_snd_pos);
261 }
262
263 old_snd_pos = 0;
264 }
265 else
266 {
267
268 #ifndef FINAL_RELEASE
269 fprintf (stderr, "i've not set loop end\n");
270 #endif
271 old_snd_pos = dwNewPos;
272 AWriteAudioData (lpWave, 0L, lpWave->dwLength);
273
274 {
275 long dum;
276 do
277 {
278 AGetVoicePosition (hVoice, &dum);
279
280 #ifndef FINAL_RELEASE
281 fprintf (stderr, "%d / %d\n", dum, old_snd_pos);
282 #endif
283
284 AUpdateAudio ();
285 }
286 while (dum < old_snd_pos);
287 }
288
289
290 }
291
292 //memcpy(lpWave->lpData,main_buf,lpWave->dwLength);
293 //memcpy(lpWave->lpData,sbuf[2],lpWave->dwLength);
294 //lpWave->dwLoopEnd = dwNewPos;
295 //AWriteAudioData(lpWave, 0L, lpWave->dwLength);
296
297 //ASetVoicePosition(hVoice,0);
298 //old=dwNewPos;
299 // }
300
301 AUpdateAudio ();
302
303
304 #else /* not double buffer */
305 {
306 long dum;
307 do
308 {
309 AGetVoicePosition (hVoice, &dum);
310
311 AUpdateAudio ();
312 }
313 while (dum < old - 10);
314 }
315
316 memcpy (lpWave->lpData, main_buf, lpWave->dwLength);
317 //memcpy(lpWave->lpData,sbuf[2],lpWave->dwLength);
318 lpWave->dwLoopEnd = dwNewPos;
319 AWriteAudioData (lpWave, 0L, lpWave->dwLength);
320
321 // if dump asked, write in a file
322 if (dump_snd)
323 fwrite (lpWave->lpData, 1, dwNewPos, out_snd);
324
325 ASetVoicePosition (hVoice, 0);
326 old = dwNewPos;
327 // }
328
329 AUpdateAudio ();
330
331 #endif /* else double buffer */
332
333 }
334
335 void (*update_sound[4])() =
336 {
337 update_sound_null, update_sound_allegro, update_sound_seal, update_sound_null
338 };
339
340 #endif
341
342
mseq(UInt32 * rand_val)343 int mseq(UInt32 *rand_val)
344 {
345 if (*rand_val & 0x00080000)
346 {
347 *rand_val = ((*rand_val ^ 0x0004) << 1) + 1;
348 return 1;
349 }
350 else
351 {
352 *rand_val <<= 1;
353 return 0;
354 }
355 }
356
357
358 /*
359 *
360 * Lookup tables for IMA ADPCM format
361 *
362 */
363 int AdpcmIndexAdjustTable[16] =
364 {
365 -1, -1, -1, -1, /* +0 - +3, decrease the step size */
366 2, 4, 6, 8, /* +4 - +7, increase the step size */
367 -1, -1, -1, -1, /* -0 - -3, decrease the step size */
368 2, 4, 6, 8, /* -4 - -7, increase the step size */
369 };
370
371 #define ADPCM_MAX_INDEX 48
372
373 int AdpcmStepSizeTable[ADPCM_MAX_INDEX + 1] =
374 {
375 16, 17, 19, 21, 23, 25, 28,
376 31, 34, 37, 41, 45, 50, 55,
377 60, 66, 73, 80, 88, 97, 107,
378 118, 130, 143, 157, 173, 190,
379 209, 230, 253, 279, 307, 337,
380 371, 408, 449, 494, 544, 598,
381 658, 724, 796, 876, 963, 1060,
382 1166, 1282, 1411, 1552
383 };
384
385 /* TODO : improve pointer in adpcm buffer maybe using fixed type */
WriteBufferAdpcm8(UChar * buf,UInt32 begin,UInt32 size,SChar * Index,SInt32 * PreviousValue)386 UInt32 WriteBufferAdpcm8 (UChar *buf, UInt32 begin, UInt32 size, SChar *Index, SInt32 *PreviousValue)
387 {
388 UInt32 ret_val = 0;
389
390 /* TODO: use something else than ALLEGRO's fixed to make this portable */
391 #ifdef ALLEGRO
392 SInt32 step, difference, deltaCode;
393 SChar index = *Index;
394 SInt32 previousValue = *PreviousValue;
395 fixed FixedIndex = 0, FixedInc;
396
397
398 if (io.adpcm_rate)
399 FixedInc = ftofix ((float) io.adpcm_rate * 1000 / (float) host.sound.freq);
400 else
401 return 0;
402
403 while (size)
404 {
405
406 FixedIndex += FixedInc;
407
408 while (FixedIndex > itofix (1))
409 {
410
411 FixedIndex -= itofix (1);
412
413 ret_val++;
414
415 deltaCode = PCM[begin >> 1];
416
417 if (begin & 1)
418 deltaCode >>= 4;
419 else
420 deltaCode &= 0xF;
421
422 step = AdpcmStepSizeTable[index];
423
424 begin++;
425
426 begin &= 0x1FFFF;
427 // Make the adpcm repeat from beginning once finished
428
429 /* Construct the difference by scaling the current step size */
430 /* This is approximately: difference = (deltaCode+.5)*step/4 */
431 difference = step >> 3;
432 if (deltaCode & 1)
433 difference += step >> 2;
434 if (deltaCode & 2)
435 difference += step >> 1;
436 if (deltaCode & 4)
437 difference += step;
438
439 if (deltaCode & 8)
440 difference = -difference;
441
442 /* Build the new sample */
443 previousValue += difference;
444
445 if (previousValue > 32767)
446 previousValue = 32767;
447 else if (previousValue < -32768)
448 previousValue = -32768;
449
450 index += AdpcmIndexAdjustTable[deltaCode];
451 if (index < 0)
452 index = 0;
453 else if (index > ADPCM_MAX_INDEX)
454 index = ADPCM_MAX_INDEX;
455
456 }
457 /* TEST, was 5 */
458 *(buf++) = (previousValue << 6) >> 8;
459
460 size--;
461
462 }
463
464 *Index = index;
465 *PreviousValue = previousValue;
466
467 #else
468 memset(buf, 0, host.sound.sample_size);
469 #endif
470
471 return ret_val;
472 }
473
474
WriteBuffer(char * buf,int ch,unsigned dwSize)475 void WriteBuffer(char *buf, int ch, unsigned dwSize)
476 {
477 static UInt32 fixed_n[6] = { 0, 0, 0, 0, 0, 0 };
478 UInt32 fixed_inc;
479 static UInt32 k[6] = { 0, 0, 0, 0, 0, 0 };
480 static UInt32 t; // used to know how much we got to advance in the ring buffer
481 static UInt32 r[6];
482 static UInt32 rand_val[6] = { 0, 0, 0, 0, 0x51F631E4, 0x51F631E4 }; // random seed for 'noise' generation
483 UInt16 dwPos = 0;
484 SInt32 vol;
485 UInt32 Tp;
486 static char vol_tbl[32] =
487 {
488 /*
489 * Funky stuff everywhere! I'm quite sure there was a reason to use an array
490 * of constant values divided by constant values and having the host machine figure
491 * it all out . . . that's why I'm leaving the original formula here within the
492 * comment.
493 * 100 / 256, 451 / 256, 508 / 256, 573 / 256, 646 / 256, 728 / 256,
494 * 821 / 256, 925 / 256,
495 * 1043 / 256, 1175 / 256, 1325 / 256, 1493 / 256, 1683 / 256, 1898 / 256,
496 * 2139 / 256, 2411 / 256,
497 * 2718 / 256, 3064 / 256, 3454 / 256, 3893 / 256, 4388 / 256, 4947 / 256,
498 * 5576 / 256, 6285 / 256,
499 * 7085 / 256, 7986 / 256, 9002 / 256, 10148 / 256, 11439 / 256, 12894 / 256,
500 * 14535 / 256, 16384 / 256
501 */
502 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 21, 24, 27, 31, 35, 39, 44, 50, 56, 64
503 };
504 UInt16 lbal, rbal;
505 SChar sample;
506
507 if (!(io.PSG[ch][PSG_DDA_REG] & PSG_DDA_ENABLE) || io.psg_channel_disabled[ch])
508 {
509 /*
510 * There is no audio to be played on this channel.
511 */
512 fixed_n[ch] = 0;
513 memset(buf, 0, dwSize);
514 return;
515 }
516
517 if ((io.PSG[ch][PSG_DDA_REG] & PSG_DDA_DIRECT_ACCESS) || io.psg_da_count[ch])
518 {
519 /*
520 * There is 'direct access' audio to be played.
521 */
522 static UInt32 da_index[6] = { 0, 0, 0, 0, 0, 0 };
523 UInt16 index = da_index[ch] >> 16;
524
525 /*
526 * For this direct audio stuff there is no frequency provided via PSG registers 3
527 * and 4. I'm not sure if this is normal behaviour or if it's something wrong in
528 * the emulation but I'm leaning toward the former.
529 *
530 * The 0x1FF divisor is completely arbitrary. I adjusted it by listening to the voices
531 * in Street Fighter 2 CE. If anyone has information to improve my "seat of the pants"
532 * calculations then by all means *does finger quotes* "throw me a frikkin` bone here".
533 *
534 * See the big comment in the final else clause for an explanation of this value
535 * to the best of my knowledge.
536 */
537 fixed_inc = ((UInt32) (3580000 / host.sound.freq) << 16) / 0x1FF;
538
539 /*
540 * Volume handling changed 2-24-03.
541 * I believe io.psg_volume should only be used to compute the final sample
542 * volume after all the buffers have been mixed together. Alright, it's what
543 * other people have already stated, and I believe them :)
544 */
545
546 if (host.sound.stereo)
547 {
548 /*
549 * We multiply the 4-bit balance values by 1.1 to get a result from (0..16.5).
550 * This multiplied by the 5-bit channel volume (0..31) gives us a result of
551 * (0..511).
552 */
553 lbal = ((io.PSG[ch][5] >> 4) * 1.1) * (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME);
554 rbal = ((io.PSG[ch][5] & 0x0F) * 1.1) * (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME);
555 }
556 else
557 {
558 /*
559 * Use an average of the two channels for mono.
560 */
561 lbal = ((((io.PSG[ch][5] >> 4) * 1.1) * (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME)) +
562 (((io.PSG[ch][5] & 0x0F) * 1.1) * (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME))) / 2;
563 }
564
565 while ((dwPos < dwSize) && io.psg_da_count[ch])
566 {
567 /*
568 * Make our sample data signed (-16..15) and then increment a non-negative
569 * result otherwise a sample with a value of 10000b will not be reproduced,
570 * which I do not believe is the correct behaviour. Plus the increment
571 * insures matching values on both sides of the wave.
572 */
573 if ((sample = io.psg_da_data[ch][index] - 16) >= 0)
574 sample++;
575
576 /*
577 * Left channel, or main channel in mono mode. Multiply our sample value
578 * (-16..16) by our balance (0..511) and then divide by 64 to get a final
579 * 8-bit output sample of (-127..127)
580 */
581 *buf++ = (char) ((SInt32) (sample * lbal) >> 6);
582
583 if (host.sound.stereo)
584 {
585 /*
586 * Same as above but for right channel.
587 */
588 *buf++ = (char) ((SInt32) (sample * rbal) >> 6);
589 dwPos += 2;
590 }
591 else
592 {
593 dwPos++;
594 }
595
596 da_index[ch] += fixed_inc;
597 da_index[ch] &= 0x3FFFFFF; /* (1023 << 16) + 0xFFFF */
598 if ((da_index[ch] >> 16) != index)
599 {
600 index = da_index[ch] >> 16;
601 io.psg_da_count[ch]--;
602 }
603 }
604
605 if ((dwPos != dwSize) && (io.PSG[ch][PSG_DDA_REG] & PSG_DDA_DIRECT_ACCESS))
606 {
607 memset(buf, 0, dwSize - dwPos);
608 return;
609 }
610 }
611
612 if ((ch > 3) && (io.PSG[ch][7] & 0x80))
613 {
614 UInt32 Np = (io.PSG[ch][7] & 0x1F);
615
616 /*
617 * PSG Noise generation, for nifty little effects like space ships taking off or blowing up.
618 * Only available to PSG channels 5 and 6.
619 */
620 // if (ds_nChannels == 2) // STEREO DISABLED
621 // {
622 // lvol = ((io.psg_volume>>3)&0x1E) + (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME) + ((io.PSG[ch][5]>>3)&0x1E);
623 // lvol = lvol-60;
624 // if (lvol < 0) lvol = 0;
625 // lvol = vol_tbl[lvol];
626 // rvol = ((io.psg_volume<<1)&0x1E) + (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME) + ((io.PSG[ch][5]<<1)&0x1E);
627 // rvol = rvol-60;
628 // if (rvol < 0) rvol = 0;
629 // rvol = vol_tbl[rvol];
630 // for (dwPos = 0; dwPos < dwSize; dwPos += 2)
631 // {
632 // k[ch] += 3000+Np*512;
633 // t = k[ch] / (DWORD) host.sound.freq;
634 // if (t >= 1)
635 // {
636 // r[ch] = mseq(&rand_val[ch]);
637 // k[ch] -= host.sound.freq * t;
638 // }
639 // *buf++ = (WORD)((r[ch] ? 10*702 : -10*702)*lvol/64);
640 // *buf++ = (WORD)((r[ch] ? 10*702 : -10*702)*rvol/64);
641 // }
642 // }
643 // else // MONO
644
645 vol = max((io.psg_volume >> 3) & 0x1E, (io.psg_volume << 1) & 0x1E) +
646 (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME) +
647 max((io.PSG[ch][5] >> 3) & 0x1E, (io.PSG[ch][5] << 1) & 0x1E);
648 //average sound level
649
650 if ((vol -= 60) < 0)
651 vol = 0;
652
653 vol = vol_tbl[vol];
654 // get cooked volume
655
656 while (dwPos < dwSize)
657 {
658 k[ch] += 3000 + Np * 512;
659
660 if ((t = (k[ch] / (UInt32) host.sound.freq)) >= 1)
661 {
662 r[ch] = mseq(&rand_val[ch]);
663 k[ch] -= host.sound.freq * t;
664 }
665
666 *buf++ = (signed char) ((r[ch] ? 10 * 702 : -10 * 702) * vol / 256 / 16); // Level 0
667 //sbuf[ch][dum++] = (WORD)((r[ch] ? 10*702 : -10*702)*lvol/64/256);
668 //*buf++ = (r[ch] ? 32 : -32) * lvol / 24;
669 dwPos++;
670 }
671 }
672 else if ((Tp = (io.PSG[ch][PSG_FREQ_LSB_REG] + (io.PSG[ch][PSG_FREQ_MSB_REG] << 8))) == 0)
673 {
674 /*
675 * 12-bit pseudo frequency value stored in PSG registers 2 (all 8 bits) and 3
676 * (lower nibble). If we get to this point and the value is 0 then there's no
677 * sound to be played.
678 *
679 * dwPos will either be 0 as initialized at the beginning of the function or a value
680 * left over from the direct audio stuff. If left over then buf will already be at
681 * (buf + dwPos) from the beginning of the function.
682 */
683 memset(buf, 0, dwSize);
684 }
685 else
686 {
687 /*
688 * Thank god for well commented code! The original line of code read:
689 * fixed_inc = ((UInt32) (3.2 * 1118608 / host.sound.freq) << 16) / Tp;
690 * and had nary a comment to be found. It took a little head scratching to get
691 * it figured out. The 3.2 * 1118608 comes out to 3574595.6 which is obviously
692 * meant to represent the 3.58mhz cpu clock speed used in the pc engine to
693 * decrement the sound 'frequency'. I haven't figured out why the original
694 * author had the two numbers multiplied together to get the odd value instead of
695 * just using 3580000. I did some checking and the value will compute the same
696 * using either value divided by any standard soundcard samplerate. The
697 * host.sound.freq is our soundcard's samplerate which is quite a bit slower than
698 * the pce's cpu (3580000 vs. 22050/44100 typically).
699 *
700 * Taken from the PSG doc written by Paul Clifford (paul@plasma.demon.co.uk)
701 * <in reference to the 12 bit frequency value in PSG registers 2 and 3>
702 * "For waveform output, a copy of this value is, in effect, decremented 3,580,000
703 * times a second until zero is reached. When this happens the PSG advances an
704 * internal pointer into the channel's waveform buffer by one."
705 *
706 * So all we need to do to emulate original pc engine behaviour is take our soundcard's
707 * sampling rate into consideration with regard to the 3580000 effective pc engine
708 * samplerate. We use 16.16 fixed arithmetic for speed.
709 */
710 fixed_inc = ((UInt32) (3580000 / host.sound.freq) << 16) / Tp;
711
712 if (host.sound.stereo)
713 {
714 /*
715 * See the direct audio code above if you're curious why we're multiplying by 1.1
716 */
717 lbal = ((io.PSG[ch][5] >> 4) * 1.1) * (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME);
718 rbal = ((io.PSG[ch][5] & 0x0F) * 1.1) * (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME);
719 }
720 else
721 {
722 lbal = ((((io.PSG[ch][5] >> 4) * 1.1) * (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME)) +
723 (((io.PSG[ch][5] & 0x0F) * 1.1) * (io.PSG[ch][4] & PSG_DDA_VOICE_VOLUME))) / 2;
724 }
725
726 while (dwPos < dwSize)
727 {
728 /*
729 * See the direct audio stuff a little above for an explanation of everything
730 * within this loop.
731 */
732 if ((sample = (io.wave[ch][io.PSG[ch][PSG_DATA_INDEX_REG]] - 16)) >= 0)
733 sample++;
734
735 *buf++ = (char) ((SInt16) (sample * lbal) >> 6);
736
737 if (host.sound.stereo)
738 {
739 *buf++ = (char) ((SInt32) (sample * rbal) >> 6);
740 dwPos += 2;
741 }
742 else
743 {
744 dwPos++;
745 }
746
747 fixed_n[ch] += fixed_inc;
748 fixed_n[ch] &= 0x1FFFFF; /* (31 << 16) + 0xFFFF */
749 io.PSG[ch][PSG_DATA_INDEX_REG] = fixed_n[ch] >> 16;
750 }
751 }
752 }
753