Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
RishiRecon
GitHub Repository: RishiRecon/exploits
Path: blob/main/misc/emulator/xnes/snes9x/apu/apu.cpp
28798 views
1
/***********************************************************************************
2
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4
(c) Copyright 1996 - 2002 Gary Henderson ([email protected]),
5
Jerremy Koot ([email protected])
6
7
(c) Copyright 2002 - 2004 Matthew Kendora
8
9
(c) Copyright 2002 - 2005 Peter Bortas ([email protected])
10
11
(c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13
(c) Copyright 2001 - 2006 John Weidman ([email protected])
14
15
(c) Copyright 2002 - 2006 funkyass ([email protected]),
16
Kris Bleakley ([email protected])
17
18
(c) Copyright 2002 - 2010 Brad Jorsch ([email protected]),
19
Nach ([email protected]),
20
21
(c) Copyright 2002 - 2011 zones ([email protected])
22
23
(c) Copyright 2006 - 2007 nitsuja
24
25
(c) Copyright 2009 - 2011 BearOso,
26
OV2
27
28
29
BS-X C emulator code
30
(c) Copyright 2005 - 2006 Dreamer Nom,
31
zones
32
33
C4 x86 assembler and some C emulation code
34
(c) Copyright 2000 - 2003 _Demo_ ([email protected]),
35
Nach,
36
zsKnight ([email protected])
37
38
C4 C++ code
39
(c) Copyright 2003 - 2006 Brad Jorsch,
40
Nach
41
42
DSP-1 emulator code
43
(c) Copyright 1998 - 2006 _Demo_,
44
Andreas Naive ([email protected]),
45
Gary Henderson,
46
Ivar ([email protected]),
47
John Weidman,
48
Kris Bleakley,
49
Matthew Kendora,
50
Nach,
51
neviksti ([email protected])
52
53
DSP-2 emulator code
54
(c) Copyright 2003 John Weidman,
55
Kris Bleakley,
56
Lord Nightmare ([email protected]),
57
Matthew Kendora,
58
neviksti
59
60
DSP-3 emulator code
61
(c) Copyright 2003 - 2006 John Weidman,
62
Kris Bleakley,
63
Lancer,
64
z80 gaiden
65
66
DSP-4 emulator code
67
(c) Copyright 2004 - 2006 Dreamer Nom,
68
John Weidman,
69
Kris Bleakley,
70
Nach,
71
z80 gaiden
72
73
OBC1 emulator code
74
(c) Copyright 2001 - 2004 zsKnight,
75
pagefault ([email protected]),
76
Kris Bleakley
77
Ported from x86 assembler to C by sanmaiwashi
78
79
SPC7110 and RTC C++ emulator code used in 1.39-1.51
80
(c) Copyright 2002 Matthew Kendora with research by
81
zsKnight,
82
John Weidman,
83
Dark Force
84
85
SPC7110 and RTC C++ emulator code used in 1.52+
86
(c) Copyright 2009 byuu,
87
neviksti
88
89
S-DD1 C emulator code
90
(c) Copyright 2003 Brad Jorsch with research by
91
Andreas Naive,
92
John Weidman
93
94
S-RTC C emulator code
95
(c) Copyright 2001 - 2006 byuu,
96
John Weidman
97
98
ST010 C++ emulator code
99
(c) Copyright 2003 Feather,
100
John Weidman,
101
Kris Bleakley,
102
Matthew Kendora
103
104
Super FX x86 assembler emulator code
105
(c) Copyright 1998 - 2003 _Demo_,
106
pagefault,
107
zsKnight
108
109
Super FX C emulator code
110
(c) Copyright 1997 - 1999 Ivar,
111
Gary Henderson,
112
John Weidman
113
114
Sound emulator code used in 1.5-1.51
115
(c) Copyright 1998 - 2003 Brad Martin
116
(c) Copyright 1998 - 2006 Charles Bilyue'
117
118
Sound emulator code used in 1.52+
119
(c) Copyright 2004 - 2007 Shay Green ([email protected])
120
121
SH assembler code partly based on x86 assembler code
122
(c) Copyright 2002 - 2004 Marcus Comstedt ([email protected])
123
124
2xSaI filter
125
(c) Copyright 1999 - 2001 Derek Liauw Kie Fa
126
127
HQ2x, HQ3x, HQ4x filters
128
(c) Copyright 2003 Maxim Stepin ([email protected])
129
130
NTSC filter
131
(c) Copyright 2006 - 2007 Shay Green
132
133
GTK+ GUI code
134
(c) Copyright 2004 - 2011 BearOso
135
136
Win32 GUI code
137
(c) Copyright 2003 - 2006 blip,
138
funkyass,
139
Matthew Kendora,
140
Nach,
141
nitsuja
142
(c) Copyright 2009 - 2011 OV2
143
144
Mac OS GUI code
145
(c) Copyright 1998 - 2001 John Stiles
146
(c) Copyright 2001 - 2011 zones
147
148
149
Specific ports contains the works of other authors. See headers in
150
individual files.
151
152
153
Snes9x homepage: http://www.snes9x.com/
154
155
Permission to use, copy, modify and/or distribute Snes9x in both binary
156
and source form, for non-commercial purposes, is hereby granted without
157
fee, providing that this license information and copyright notice appear
158
with all copies and any derived work.
159
160
This software is provided 'as-is', without any express or implied
161
warranty. In no event shall the authors be held liable for any damages
162
arising from the use of this software or it's derivatives.
163
164
Snes9x is freeware for PERSONAL USE only. Commercial users should
165
seek permission of the copyright holders first. Commercial use includes,
166
but is not limited to, charging money for Snes9x or software derived from
167
Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
168
using Snes9x as a promotion for your commercial product.
169
170
The copyright holders request that bug fixes and improvements to the code
171
should be forwarded to them so everyone can benefit from the modifications
172
in future versions.
173
174
Super NES and Super Nintendo Entertainment System are trademarks of
175
Nintendo Co., Limited and its subsidiary companies.
176
***********************************************************************************/
177
178
179
#include <math.h>
180
#include "snes9x.h"
181
#include "apu.h"
182
#ifdef FANCY
183
#include "snapshot.h"
184
#endif
185
#include "display.h"
186
#include "linear_resampler.h"
187
#include "hermite_resampler.h"
188
189
#define APU_DEFAULT_INPUT_RATE 32000
190
#define APU_MINIMUM_SAMPLE_COUNT 512
191
#define APU_MINIMUM_SAMPLE_BLOCK 128
192
#define APU_NUMERATOR_NTSC 15664
193
#define APU_DENOMINATOR_NTSC 328125
194
#define APU_NUMERATOR_PAL 34176
195
#define APU_DENOMINATOR_PAL 709379
196
#define APU_DEFAULT_RESAMPLER HermiteResampler
197
198
SNES_SPC *spc_core = NULL;
199
200
static uint8 APUROM[64] =
201
{
202
0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0,
203
0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78,
204
0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4,
205
0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5,
206
0xCB, 0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB,
207
0x01, 0x10, 0xEF, 0x7E, 0xF4, 0x10, 0xEB, 0xBA,
208
0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4, 0xDD,
209
0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF
210
};
211
212
namespace spc
213
{
214
static apu_callback sa_callback = NULL;
215
static void *extra_data = NULL;
216
217
static bool8 sound_in_sync = TRUE;
218
static bool8 sound_enabled = FALSE;
219
220
static int buffer_size;
221
static int lag_master = 0;
222
static int lag = 0;
223
224
static uint8 *landing_buffer = NULL;
225
static uint8 *shrink_buffer = NULL;
226
227
static Resampler *resampler = NULL;
228
229
static int32 reference_time;
230
static uint32 remainder;
231
232
static const int timing_hack_numerator = SNES_SPC::tempo_unit;
233
static int timing_hack_denominator = SNES_SPC::tempo_unit;
234
/* Set these to NTSC for now. Will change to PAL in S9xAPUTimingSetSpeedup
235
if necessary on game load. */
236
static uint32 ratio_numerator = APU_NUMERATOR_NTSC;
237
static uint32 ratio_denominator = APU_DENOMINATOR_NTSC;
238
}
239
240
static void EightBitize (uint8 *, int);
241
static void DeStereo (uint8 *, int);
242
static void ReverseStereo (uint8 *, int);
243
static void UpdatePlaybackRate (void);
244
static void from_apu_to_state (uint8 **, void *, size_t);
245
static void to_apu_from_state (uint8 **, void *, size_t);
246
#ifdef FANCY
247
static void SPCSnapshotCallback (void);
248
#endif
249
static inline int S9xAPUGetClock (int32);
250
static inline int S9xAPUGetClockRemainder (int32);
251
252
253
static void EightBitize (uint8 *buffer, int sample_count)
254
{
255
uint8 *buf8 = (uint8 *) buffer;
256
int16 *buf16 = (int16 *) buffer;
257
258
for (int i = 0; i < sample_count; i++)
259
buf8[i] = (uint8) ((buf16[i] / 256) + 128);
260
}
261
262
static void DeStereo (uint8 *buffer, int sample_count)
263
{
264
int16 *buf = (int16 *) buffer;
265
int32 s1, s2;
266
267
for (int i = 0; i < sample_count >> 1; i++)
268
{
269
s1 = (int32) buf[2 * i];
270
s2 = (int32) buf[2 * i + 1];
271
buf[i] = (int16) ((s1 + s2) >> 1);
272
}
273
}
274
275
static void ReverseStereo (uint8 *src_buffer, int sample_count)
276
{
277
int16 *buffer = (int16 *) src_buffer;
278
279
for (int i = 0; i < sample_count; i += 2)
280
{
281
buffer[i + 1] ^= buffer[i];
282
buffer[i] ^= buffer[i + 1];
283
buffer[i + 1] ^= buffer[i];
284
}
285
}
286
287
bool8 S9xMixSamples (uint8 *buffer, int sample_count)
288
{
289
static int shrink_buffer_size = -1;
290
uint8 *dest;
291
292
if (!Settings.SixteenBitSound || !Settings.Stereo)
293
{
294
/* We still need both stereo samples for generating the mono sample */
295
if (!Settings.Stereo)
296
sample_count <<= 1;
297
298
/* We still have to generate 16-bit samples for bit-dropping, too */
299
if (shrink_buffer_size < (sample_count << 1))
300
{
301
delete[] spc::shrink_buffer;
302
spc::shrink_buffer = new uint8[sample_count << 1];
303
shrink_buffer_size = sample_count << 1;
304
}
305
306
dest = spc::shrink_buffer;
307
}
308
else
309
dest = buffer;
310
311
if (Settings.Mute)
312
{
313
memset(dest, 0, sample_count << 1);
314
spc::resampler->clear();
315
316
return (FALSE);
317
}
318
else
319
{
320
if (spc::resampler->avail() >= (sample_count + spc::lag))
321
{
322
spc::resampler->read((short *) dest, sample_count);
323
if (spc::lag == spc::lag_master)
324
spc::lag = 0;
325
}
326
else
327
{
328
memset(buffer, (Settings.SixteenBitSound ? 0 : 128), (sample_count << (Settings.SixteenBitSound ? 1 : 0)) >> (Settings.Stereo ? 0 : 1));
329
if (spc::lag == 0)
330
spc::lag = spc::lag_master;
331
332
return (FALSE);
333
}
334
}
335
336
if (Settings.ReverseStereo && Settings.Stereo)
337
ReverseStereo(dest, sample_count);
338
339
if (!Settings.Stereo || !Settings.SixteenBitSound)
340
{
341
if (!Settings.Stereo)
342
{
343
DeStereo(dest, sample_count);
344
sample_count >>= 1;
345
}
346
347
if (!Settings.SixteenBitSound)
348
EightBitize(dest, sample_count);
349
350
memcpy(buffer, dest, (sample_count << (Settings.SixteenBitSound ? 1 : 0)));
351
}
352
353
return (TRUE);
354
}
355
356
int S9xGetSampleCount (void)
357
{
358
return (spc::resampler->avail() >> (Settings.Stereo ? 0 : 1));
359
}
360
361
void S9xFinalizeSamples (void)
362
{
363
if (!Settings.Mute)
364
{
365
if (!spc::resampler->push((short *) spc::landing_buffer, spc_core->sample_count()))
366
{
367
/* We weren't able to process the entire buffer. Potential overrun. */
368
spc::sound_in_sync = FALSE;
369
370
if (Settings.SoundSync && !Settings.TurboMode)
371
return;
372
}
373
}
374
375
if (!Settings.SoundSync || Settings.TurboMode || Settings.Mute)
376
spc::sound_in_sync = TRUE;
377
else
378
if (spc::resampler->space_empty() >= spc::resampler->space_filled())
379
spc::sound_in_sync = TRUE;
380
else
381
spc::sound_in_sync = FALSE;
382
383
spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
384
}
385
386
void S9xLandSamples (void)
387
{
388
if (spc::sa_callback != NULL)
389
spc::sa_callback(spc::extra_data);
390
else
391
S9xFinalizeSamples();
392
}
393
394
void S9xClearSamples (void)
395
{
396
spc::resampler->clear();
397
spc::lag = spc::lag_master;
398
}
399
400
bool8 S9xSyncSound (void)
401
{
402
if (!Settings.SoundSync || spc::sound_in_sync)
403
return (TRUE);
404
405
S9xLandSamples();
406
407
return (spc::sound_in_sync);
408
}
409
410
void S9xSetSamplesAvailableCallback (apu_callback callback, void *data)
411
{
412
spc::sa_callback = callback;
413
spc::extra_data = data;
414
}
415
416
static void UpdatePlaybackRate (void)
417
{
418
if (Settings.SoundInputRate == 0)
419
Settings.SoundInputRate = APU_DEFAULT_INPUT_RATE;
420
421
double time_ratio = (double) Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator);
422
spc::resampler->time_ratio(time_ratio);
423
}
424
425
bool8 S9xInitSound (int buffer_ms, int lag_ms)
426
{
427
// buffer_ms : buffer size given in millisecond
428
// lag_ms : allowable time-lag given in millisecond
429
430
int sample_count = buffer_ms * 32000 / 1000;
431
int lag_sample_count = lag_ms * 32000 / 1000;
432
433
spc::lag_master = lag_sample_count;
434
if (Settings.Stereo)
435
spc::lag_master <<= 1;
436
spc::lag = spc::lag_master;
437
438
if (sample_count < APU_MINIMUM_SAMPLE_COUNT)
439
sample_count = APU_MINIMUM_SAMPLE_COUNT;
440
441
spc::buffer_size = sample_count;
442
if (Settings.Stereo)
443
spc::buffer_size <<= 1;
444
if (Settings.SixteenBitSound)
445
spc::buffer_size <<= 1;
446
447
printf("Sound buffer size: %d (%d samples)\n", spc::buffer_size, sample_count);
448
449
if (spc::landing_buffer)
450
delete[] spc::landing_buffer;
451
spc::landing_buffer = new uint8[spc::buffer_size * 2];
452
if (!spc::landing_buffer)
453
return (FALSE);
454
455
/* The resampler and spc unit use samples (16-bit short) as
456
arguments. Use 2x in the resampler for buffer leveling with SoundSync */
457
if (!spc::resampler)
458
{
459
spc::resampler = new APU_DEFAULT_RESAMPLER(spc::buffer_size >> (Settings.SoundSync ? 0 : 1));
460
if (!spc::resampler)
461
{
462
delete[] spc::landing_buffer;
463
return (FALSE);
464
}
465
}
466
else
467
spc::resampler->resize(spc::buffer_size >> (Settings.SoundSync ? 0 : 1));
468
469
spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
470
471
UpdatePlaybackRate();
472
473
spc::sound_enabled = S9xOpenSoundDevice();
474
475
return (spc::sound_enabled);
476
}
477
478
void S9xSetSoundControl (uint8 voice_switch)
479
{
480
spc_core->dsp_set_stereo_switch(voice_switch << 8 | voice_switch);
481
}
482
483
void S9xSetSoundMute (bool8 mute)
484
{
485
Settings.Mute = mute;
486
if (!spc::sound_enabled)
487
Settings.Mute = TRUE;
488
}
489
490
void S9xDumpSPCSnapshot (void)
491
{
492
spc_core->dsp_dump_spc_snapshot();
493
}
494
#ifdef FANCY
495
static void SPCSnapshotCallback (void)
496
{
497
S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR));
498
printf("Dumped key-on triggered spc snapshot.\n");
499
}
500
#endif
501
bool8 S9xInitAPU (void)
502
{
503
spc_core = new SNES_SPC;
504
if (!spc_core)
505
return (FALSE);
506
507
spc_core->init();
508
spc_core->init_rom(APUROM);
509
#ifdef FANCY
510
spc_core->dsp_set_spc_snapshot_callback(SPCSnapshotCallback);
511
#endif
512
spc::landing_buffer = NULL;
513
spc::shrink_buffer = NULL;
514
spc::resampler = NULL;
515
516
return (TRUE);
517
}
518
519
void S9xDeinitAPU (void)
520
{
521
if (spc_core)
522
{
523
delete spc_core;
524
spc_core = NULL;
525
}
526
527
if (spc::resampler)
528
{
529
delete spc::resampler;
530
spc::resampler = NULL;
531
}
532
533
if (spc::landing_buffer)
534
{
535
delete[] spc::landing_buffer;
536
spc::landing_buffer = NULL;
537
}
538
539
if (spc::shrink_buffer)
540
{
541
delete[] spc::shrink_buffer;
542
spc::shrink_buffer = NULL;
543
}
544
}
545
546
static inline int S9xAPUGetClock (int32 cpucycles)
547
{
548
return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) /
549
spc::ratio_denominator;
550
}
551
552
static inline int S9xAPUGetClockRemainder (int32 cpucycles)
553
{
554
return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) %
555
spc::ratio_denominator;
556
}
557
558
uint8 S9xAPUReadPort (int port)
559
{
560
return ((uint8) spc_core->read_port(S9xAPUGetClock(CPU.Cycles), port));
561
}
562
563
void S9xAPUWritePort (int port, uint8 byte)
564
{
565
spc_core->write_port(S9xAPUGetClock(CPU.Cycles), port, byte);
566
}
567
568
void S9xAPUSetReferenceTime (int32 cpucycles)
569
{
570
spc::reference_time = cpucycles;
571
}
572
573
void S9xAPUExecute (void)
574
{
575
/* Accumulate partial APU cycles */
576
spc_core->end_frame(S9xAPUGetClock(CPU.Cycles));
577
578
spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles);
579
580
S9xAPUSetReferenceTime(CPU.Cycles);
581
}
582
583
void S9xAPUEndScanline (void)
584
{
585
S9xAPUExecute();
586
587
if (spc_core->sample_count() >= APU_MINIMUM_SAMPLE_BLOCK || !spc::sound_in_sync)
588
S9xLandSamples();
589
}
590
591
void S9xAPUTimingSetSpeedup (int ticks)
592
{
593
if (ticks != 0)
594
printf("APU speedup hack: %d\n", ticks);
595
596
spc::timing_hack_denominator = SNES_SPC::tempo_unit - ticks;
597
spc_core->set_tempo(spc::timing_hack_denominator);
598
599
spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC;
600
spc::ratio_denominator = Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC;
601
spc::ratio_denominator = spc::ratio_denominator * spc::timing_hack_denominator / spc::timing_hack_numerator;
602
603
UpdatePlaybackRate();
604
}
605
606
void S9xAPUAllowTimeOverflow (bool allow)
607
{
608
if (allow)
609
printf("APU time overflow allowed\n");
610
611
spc_core->spc_allow_time_overflow(allow);
612
}
613
614
void S9xResetAPU (void)
615
{
616
spc::reference_time = 0;
617
spc::remainder = 0;
618
spc_core->reset();
619
spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
620
621
spc::resampler->clear();
622
}
623
624
void S9xSoftResetAPU (void)
625
{
626
spc::reference_time = 0;
627
spc::remainder = 0;
628
spc_core->soft_reset();
629
spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
630
631
spc::resampler->clear();
632
}
633
634
static void from_apu_to_state (uint8 **buf, void *var, size_t size)
635
{
636
memcpy(*buf, var, size);
637
*buf += size;
638
}
639
640
static void to_apu_from_state (uint8 **buf, void *var, size_t size)
641
{
642
memcpy(var, *buf, size);
643
*buf += size;
644
}
645
646
void S9xAPUSaveState (uint8 *block)
647
{
648
uint8 *ptr = block;
649
650
spc_core->copy_state(&ptr, from_apu_to_state);
651
652
SET_LE32(ptr, spc::reference_time);
653
ptr += sizeof(int32);
654
SET_LE32(ptr, spc::remainder);
655
}
656
657
void S9xAPULoadState (uint8 *block)
658
{
659
uint8 *ptr = block;
660
661
S9xResetAPU();
662
663
spc_core->copy_state(&ptr, to_apu_from_state);
664
665
spc::reference_time = GET_LE32(ptr);
666
ptr += sizeof(int32);
667
spc::remainder = GET_LE32(ptr);
668
}
669
670