1 /*****************************************************************************\
2      Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3                 This file is licensed under the Snes9x License.
4    For further information, consult the LICENSE file in the root directory.
5 \*****************************************************************************/
6 
7 #include <cmath>
8 #include "../snes9x.h"
9 #include "apu.h"
10 #include "../msu1.h"
11 #include "../snapshot.h"
12 #include "../display.h"
13 #include "resampler.h"
14 
15 #include "bapu/snes/snes.hpp"
16 
17 static const int APU_DEFAULT_INPUT_RATE = 31950; // ~59.94Hz
18 static const int APU_SAMPLE_BLOCK       = 48;
19 static const int APU_NUMERATOR_NTSC     = 15664;
20 static const int APU_DENOMINATOR_NTSC   = 328125;
21 static const int APU_NUMERATOR_PAL      = 34176;
22 static const int APU_DENOMINATOR_PAL    = 709379;
23 
24 // Max number of samples we'll ever generate before call to port API and
25 // moving the samples to the resampler.
26 // This is 535 sample frames, which corresponds to 1 video frame + some leeway
27 // for use with SoundSync, multiplied by 2, for left and right samples.
28 static const int MINIMUM_BUFFER_SIZE = 550 * 2;
29 
30 namespace SNES {
31 #include "bapu/dsp/blargg_endian.h"
32 CPU cpu;
33 } // namespace SNES
34 
35 namespace spc {
36 static apu_callback callback = NULL;
37 static void *callback_data = NULL;
38 
39 static bool8 sound_in_sync = TRUE;
40 static bool8 sound_enabled = FALSE;
41 
42 static Resampler *resampler = NULL;
43 
44 static int32 reference_time;
45 static uint32 remainder;
46 
47 static const int timing_hack_numerator = 256;
48 static int timing_hack_denominator = 256;
49 /* Set these to NTSC for now. Will change to PAL in S9xAPUTimingSetSpeedup
50    if necessary on game load. */
51 static uint32 ratio_numerator = APU_NUMERATOR_NTSC;
52 static uint32 ratio_denominator = APU_DENOMINATOR_NTSC;
53 
54 static double dynamic_rate_multiplier = 1.0;
55 } // namespace spc
56 
57 namespace msu {
58 // Always 16-bit, Stereo; 1.5x dsp buffer to never overflow
59 static Resampler *resampler = NULL;
60 static int16 *resample_buffer = NULL;
61 static int resample_buffer_size = 0;
62 } // namespace msu
63 
64 static void UpdatePlaybackRate(void);
65 static void SPCSnapshotCallback(void);
66 static inline int S9xAPUGetClock(int32);
67 static inline int S9xAPUGetClockRemainder(int32);
68 
S9xMixSamples(uint8 * dest,int sample_count)69 bool8 S9xMixSamples(uint8 *dest, int sample_count)
70 {
71     int16 *out = (int16 *)dest;
72 
73     if (Settings.Mute)
74     {
75         memset(out, 0, sample_count << 1);
76         S9xClearSamples();
77     }
78     else
79     {
80         if (spc::resampler->avail() >= sample_count)
81         {
82             spc::resampler->read((short *)out, sample_count);
83 
84             if (Settings.MSU1)
85             {
86                 if (msu::resampler->avail() >= sample_count)
87                 {
88                     if (msu::resample_buffer_size < sample_count)
89                     {
90                         if (msu::resample_buffer)
91                             delete[] msu::resample_buffer;
92                         msu::resample_buffer = new int16[sample_count];
93                         msu::resample_buffer_size = sample_count;
94                     }
95                     msu::resampler->read(msu::resample_buffer,
96                                          sample_count);
97                     for (int i = 0; i < sample_count; ++i)
98                     {
99                         int32 mixed = (int32)out[i] + msu::resample_buffer[i];
100                         out[i] = ((int16)mixed != mixed) ? (mixed >> 31) ^ 0x7fff : mixed;
101                     }
102                 }
103                 else // should never occur
104                     assert(0);
105             }
106         }
107         else
108         {
109             memset(out, 0, sample_count << 1);
110             return false;
111         }
112     }
113 
114     if (spc::resampler->space_empty() >= 535 * 2 || !Settings.SoundSync ||
115         Settings.TurboMode || Settings.Mute)
116         spc::sound_in_sync = true;
117     else
118         spc::sound_in_sync = false;
119 
120     return true;
121 }
122 
S9xGetSampleCount(void)123 int S9xGetSampleCount(void)
124 {
125     return spc::resampler->avail();
126 }
127 
S9xLandSamples(void)128 void S9xLandSamples(void)
129 {
130     if (spc::callback != NULL)
131         spc::callback(spc::callback_data);
132 
133     if (spc::resampler->space_empty() >= 535 * 2 || !Settings.SoundSync ||
134         Settings.TurboMode || Settings.Mute)
135         spc::sound_in_sync = true;
136     else
137         spc::sound_in_sync = false;
138 }
139 
S9xClearSamples(void)140 void S9xClearSamples(void)
141 {
142     spc::resampler->clear();
143     if (Settings.MSU1)
144         msu::resampler->clear();
145 }
146 
S9xSyncSound(void)147 bool8 S9xSyncSound(void)
148 {
149     if (!Settings.SoundSync || spc::sound_in_sync)
150         return (TRUE);
151 
152     S9xLandSamples();
153 
154     return (spc::sound_in_sync);
155 }
156 
S9xSetSamplesAvailableCallback(apu_callback callback,void * data)157 void S9xSetSamplesAvailableCallback(apu_callback callback, void *data)
158 {
159     spc::callback = callback;
160     spc::callback_data = data;
161 }
162 
S9xUpdateDynamicRate(int avail,int buffer_size)163 void S9xUpdateDynamicRate(int avail, int buffer_size)
164 {
165     spc::dynamic_rate_multiplier = 1.0 + (Settings.DynamicRateLimit * (buffer_size - 2 * avail)) /
166                                              (double)(1000 * buffer_size);
167 
168     UpdatePlaybackRate();
169 }
170 
UpdatePlaybackRate(void)171 static void UpdatePlaybackRate(void)
172 {
173     if (Settings.SoundInputRate == 0)
174         Settings.SoundInputRate = APU_DEFAULT_INPUT_RATE;
175 
176     double time_ratio = (double)Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator);
177 
178     if (Settings.DynamicRateControl)
179     {
180         time_ratio *= spc::dynamic_rate_multiplier;
181     }
182 
183     spc::resampler->time_ratio(time_ratio);
184 
185     if (Settings.MSU1)
186     {
187         time_ratio = (44100.0 / Settings.SoundPlaybackRate) * (Settings.SoundInputRate / 32040.0);
188         msu::resampler->time_ratio(time_ratio);
189     }
190 }
191 
S9xInitSound(int buffer_ms)192 bool8 S9xInitSound(int buffer_ms)
193 {
194     // The resampler and spc unit use samples (16-bit short) as arguments.
195     int buffer_size_samples = MINIMUM_BUFFER_SIZE;
196     int requested_buffer_size_samples = Settings.SoundPlaybackRate * buffer_ms * 2 / 1000;
197 
198     if (requested_buffer_size_samples > buffer_size_samples)
199         buffer_size_samples = requested_buffer_size_samples;
200 
201     if (!spc::resampler)
202     {
203         spc::resampler = new Resampler(buffer_size_samples);
204         if (!spc::resampler)
205             return (FALSE);
206     }
207     else
208         spc::resampler->resize(buffer_size_samples);
209 
210 
211     if (!msu::resampler)
212     {
213         msu::resampler = new Resampler(buffer_size_samples * 3 / 2);
214         if (!msu::resampler)
215             return (FALSE);
216     }
217     else
218         msu::resampler->resize(buffer_size_samples * 3 / 2);
219 
220     SNES::dsp.spc_dsp.set_output(spc::resampler);
221     S9xMSU1SetOutput(msu::resampler);
222 
223     UpdatePlaybackRate();
224 
225     spc::sound_enabled = S9xOpenSoundDevice();
226 
227     return (spc::sound_enabled);
228 }
229 
S9xSetSoundControl(uint8 voice_switch)230 void S9xSetSoundControl(uint8 voice_switch)
231 {
232     SNES::dsp.spc_dsp.set_stereo_switch(voice_switch << 8 | voice_switch);
233 }
234 
S9xSetSoundMute(bool8 mute)235 void S9xSetSoundMute(bool8 mute)
236 {
237     Settings.Mute = mute;
238     if (!spc::sound_enabled)
239         Settings.Mute = TRUE;
240 }
241 
S9xDumpSPCSnapshot(void)242 void S9xDumpSPCSnapshot(void)
243 {
244     SNES::dsp.spc_dsp.dump_spc_snapshot();
245 }
246 
SPCSnapshotCallback(void)247 static void SPCSnapshotCallback(void)
248 {
249     S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR));
250     printf("Dumped key-on triggered spc snapshot.\n");
251 }
252 
S9xInitAPU(void)253 bool8 S9xInitAPU(void)
254 {
255     spc::resampler = NULL;
256     msu::resampler = NULL;
257 
258     return (TRUE);
259 }
260 
S9xDeinitAPU(void)261 void S9xDeinitAPU(void)
262 {
263     if (spc::resampler)
264     {
265         delete spc::resampler;
266         spc::resampler = NULL;
267     }
268 
269     if (msu::resampler)
270     {
271         delete msu::resampler;
272         msu::resampler = NULL;
273     }
274 
275     S9xMSU1DeInit();
276 }
277 
S9xAPUGetClock(int32 cpucycles)278 static inline int S9xAPUGetClock(int32 cpucycles)
279 {
280     return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) /
281            spc::ratio_denominator;
282 }
283 
S9xAPUGetClockRemainder(int32 cpucycles)284 static inline int S9xAPUGetClockRemainder(int32 cpucycles)
285 {
286     return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) %
287            spc::ratio_denominator;
288 }
289 
S9xAPUReadPort(int port)290 uint8 S9xAPUReadPort(int port)
291 {
292     S9xAPUExecute();
293     return ((uint8)SNES::smp.port_read(port & 3));
294 }
295 
S9xAPUWritePort(int port,uint8 byte)296 void S9xAPUWritePort(int port, uint8 byte)
297 {
298     S9xAPUExecute();
299     SNES::cpu.port_write(port & 3, byte);
300 }
301 
S9xAPUSetReferenceTime(int32 cpucycles)302 void S9xAPUSetReferenceTime(int32 cpucycles)
303 {
304     spc::reference_time = cpucycles;
305 }
306 
S9xAPUExecute(void)307 void S9xAPUExecute(void)
308 {
309     SNES::smp.clock -= S9xAPUGetClock(CPU.Cycles);
310     SNES::smp.enter();
311 
312     spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles);
313 
314     S9xAPUSetReferenceTime(CPU.Cycles);
315 }
316 
S9xAPUEndScanline(void)317 void S9xAPUEndScanline(void)
318 {
319     S9xAPUExecute();
320     SNES::dsp.synchronize();
321 
322     if (spc::resampler->space_filled() >= APU_SAMPLE_BLOCK || !spc::sound_in_sync)
323         S9xLandSamples();
324 }
325 
S9xAPUTimingSetSpeedup(int ticks)326 void S9xAPUTimingSetSpeedup(int ticks)
327 {
328     if (ticks != 0)
329         printf("APU speedup hack: %d\n", ticks);
330 
331     spc::timing_hack_denominator = 256 - ticks;
332 
333     spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC;
334     spc::ratio_denominator = Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC;
335     spc::ratio_denominator = spc::ratio_denominator * spc::timing_hack_denominator / spc::timing_hack_numerator;
336 
337     UpdatePlaybackRate();
338 }
339 
S9xResetAPU(void)340 void S9xResetAPU(void)
341 {
342     spc::reference_time = 0;
343     spc::remainder = 0;
344 
345     SNES::cpu.reset();
346     SNES::smp.power();
347     SNES::dsp.power();
348     SNES::dsp.spc_dsp.set_spc_snapshot_callback(SPCSnapshotCallback);
349 
350     S9xClearSamples();
351 }
352 
S9xSoftResetAPU(void)353 void S9xSoftResetAPU(void)
354 {
355     spc::reference_time = 0;
356     spc::remainder = 0;
357     SNES::cpu.reset();
358     SNES::smp.reset();
359     SNES::dsp.reset();
360 
361     S9xClearSamples();
362 }
363 
S9xAPUSaveState(uint8 * block)364 void S9xAPUSaveState(uint8 *block)
365 {
366     uint8 *ptr = block;
367 
368     SNES::smp.save_state(&ptr);
369     SNES::dsp.save_state(&ptr);
370 
371     SNES::set_le32(ptr, spc::reference_time);
372     ptr += sizeof(int32);
373     SNES::set_le32(ptr, spc::remainder);
374     ptr += sizeof(int32);
375     SNES::set_le32(ptr, SNES::dsp.clock);
376     ptr += sizeof(int32);
377     memcpy(ptr, SNES::cpu.registers, 4);
378     ptr += sizeof(int32);
379 
380     memset(ptr, 0, SPC_SAVE_STATE_BLOCK_SIZE - (ptr - block));
381 }
382 
S9xAPULoadState(uint8 * block)383 void S9xAPULoadState(uint8 *block)
384 {
385     uint8 *ptr = block;
386 
387     SNES::smp.load_state(&ptr);
388     SNES::dsp.load_state(&ptr);
389 
390     spc::reference_time = SNES::get_le32(ptr);
391     ptr += sizeof(int32);
392     spc::remainder = SNES::get_le32(ptr);
393     ptr += sizeof(int32);
394     SNES::dsp.clock = SNES::get_le32(ptr);
395     ptr += sizeof(int32);
396     memcpy(SNES::cpu.registers, ptr, 4);
397 }
398 
to_var_from_buf(uint8 ** buf,void * var,size_t size)399 static void to_var_from_buf(uint8 **buf, void *var, size_t size)
400 {
401     memcpy(var, *buf, size);
402     *buf += size;
403 }
404 
405 #undef IF_0_THEN_256
406 #define IF_0_THEN_256(n) ((uint8)((n)-1) + 1)
S9xAPULoadBlarggState(uint8 * oldblock)407 void S9xAPULoadBlarggState(uint8 *oldblock)
408 {
409     uint8 *ptr = oldblock;
410 
411     SNES::SPC_State_Copier copier(&ptr, to_var_from_buf);
412 
413     copier.copy(SNES::smp.apuram, 0x10000); // RAM
414 
415     uint8 regs_in[0x10];
416     uint8 regs[0x10];
417     uint16 pc, spc_time, dsp_time;
418     uint8 a, x, y, psw, sp;
419 
420     copier.copy(regs, 0x10);    // REGS
421     copier.copy(regs_in, 0x10); // REGS_IN
422 
423     // CPU Regs
424     pc = copier.copy_int(0, sizeof(uint16));
425     a = copier.copy_int(0, sizeof(uint8));
426     x = copier.copy_int(0, sizeof(uint8));
427     y = copier.copy_int(0, sizeof(uint8));
428     psw = copier.copy_int(0, sizeof(uint8));
429     sp = copier.copy_int(0, sizeof(uint8));
430     copier.extra();
431 
432     // times
433     spc_time = copier.copy_int(0, sizeof(uint16));
434     dsp_time = copier.copy_int(0, sizeof(uint16));
435 
436     int cur_time = S9xAPUGetClock(CPU.Cycles);
437 
438     // spc_time is absolute, dsp_time is relative
439     // smp.clock is relative, dsp.clock relative but counting upwards
440     SNES::smp.clock = spc_time - cur_time;
441     SNES::dsp.clock = -1 * dsp_time;
442 
443     // DSP
444     SNES::dsp.load_state(&ptr);
445 
446     // Timers
447     uint16 next_time[3];
448     uint8 divider[3], counter[3];
449     for (int i = 0; i < 3; i++)
450     {
451         next_time[i] = copier.copy_int(0, sizeof(uint16));
452         divider[i] = copier.copy_int(0, sizeof(uint8));
453         counter[i] = copier.copy_int(0, sizeof(uint8));
454         copier.extra();
455     }
456     // construct timers out of available parts from blargg smp
457     SNES::smp.timer0.enable = regs[1] >> 0 & 1;        // regs[1] = CONTROL
458     SNES::smp.timer0.target = IF_0_THEN_256(regs[10]); // regs[10+i] = TiTARGET
459     // blargg counts time, get ticks through timer frequency
460     // (assume tempo = 256)
461     SNES::smp.timer0.stage1_ticks = 128 - (next_time[0] - cur_time) / 128;
462     SNES::smp.timer0.stage2_ticks = divider[0];
463     SNES::smp.timer0.stage3_ticks = counter[0];
464 
465     SNES::smp.timer1.enable = regs[1] >> 1 & 1;
466     SNES::smp.timer1.target = IF_0_THEN_256(regs[11]);
467     SNES::smp.timer1.stage1_ticks = 128 - (next_time[1] - cur_time) / 128;
468     SNES::smp.timer1.stage2_ticks = divider[0];
469     SNES::smp.timer1.stage3_ticks = counter[0];
470 
471     SNES::smp.timer2.enable = regs[1] >> 2 & 1;
472     SNES::smp.timer2.target = IF_0_THEN_256(regs[12]);
473     SNES::smp.timer2.stage1_ticks = 16 - (next_time[2] - cur_time) / 16;
474     SNES::smp.timer2.stage2_ticks = divider[0];
475     SNES::smp.timer2.stage3_ticks = counter[0];
476 
477     copier.extra();
478 
479     SNES::smp.opcode_number = 0;
480     SNES::smp.opcode_cycle = 0;
481 
482     SNES::smp.regs.pc = pc;
483     SNES::smp.regs.sp = sp;
484     SNES::smp.regs.B.a = a;
485     SNES::smp.regs.x = x;
486     SNES::smp.regs.B.y = y;
487 
488     // blargg's psw has same layout as byuu's flags
489     SNES::smp.regs.p = psw;
490 
491     // blargg doesn't explicitly store iplrom_enable
492     SNES::smp.status.iplrom_enable = regs[1] & 0x80;
493 
494     SNES::smp.status.dsp_addr = regs[2];
495 
496     SNES::smp.status.ram00f8 = regs_in[8];
497     SNES::smp.status.ram00f9 = regs_in[9];
498 
499     // default to 0 - we are on an opcode boundary, shouldn't matter
500     SNES::smp.rd = SNES::smp.wr = SNES::smp.dp = SNES::smp.sp = SNES::smp.ya = SNES::smp.bit = 0;
501 
502     spc::reference_time = SNES::get_le32(ptr);
503     ptr += sizeof(int32);
504     spc::remainder = SNES::get_le32(ptr);
505 
506     // blargg stores CPUIx in regs_in
507     memcpy(SNES::cpu.registers, regs_in + 4, 4);
508 }
509 
S9xSPCDump(const char * filename)510 bool8 S9xSPCDump(const char *filename)
511 {
512     FILE *fs;
513     uint8 buf[SPC_FILE_SIZE];
514     size_t ignore;
515 
516     fs = fopen(filename, "wb");
517     if (!fs)
518         return (FALSE);
519 
520     S9xSetSoundMute(TRUE);
521 
522     SNES::smp.save_spc(buf);
523 
524     ignore = fwrite(buf, SPC_FILE_SIZE, 1, fs);
525 
526     if (ignore == 0)
527     {
528         fprintf(stderr, "Couldn't write file %s.\n", filename);
529     }
530 
531     fclose(fs);
532 
533     S9xSetSoundMute(FALSE);
534 
535     return (TRUE);
536 }
537