Browse code

* Fixes for gcc and clang (while they can compile the code, the DLLs made aren't functional, but oh well).

* [2SF] Used more up-to-date asmjit, despite the ugly looking code.

Naram Qashat authored on 2014/09/17 19:51:45
Showing 1 changed files
... ...
@@ -404,7 +404,7 @@ template<class ResamplerClass> bool S9xInitSound(int buffer_ms, int lag_ms)
404 404
 		return false;
405 405
 
406 406
 	/* The resampler and spc unit use samples (16-bit short) as
407
-	/*   arguments. Use 2x in the resampler for buffer leveling with SoundSync */
407
+	 *   arguments. Use 2x in the resampler for buffer leveling with SoundSync */
408 408
 	spc::resampler.reset(new ResamplerClass(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)));
409 409
 	if (!spc::resampler)
410 410
 	{
Browse code

[SNSF] Replaced most uses of fill/copy with fill_n/copy_n, and a few other minor code cleanups.

Naram Qashat authored on 2013/05/27 22:34:22
Showing 1 changed files
... ...
@@ -235,11 +235,10 @@ namespace spc
235 235
 
236 236
 static void EightBitize(uint8_t *buffer, int sample_count)
237 237
 {
238
-	uint8_t *buf8 = buffer;
239 238
 	int16_t *buf16 = reinterpret_cast<int16_t *>(buffer);
240 239
 
241 240
 	for (int i = 0; i < sample_count; ++i)
242
-		buf8[i] = static_cast<uint8_t>((buf16[i] / 256) + 128);
241
+		buffer[i] = static_cast<uint8_t>((buf16[i] / 256) + 128);
243 242
 }
244 243
 
245 244
 static void DeStereo(uint8_t *buffer, int sample_count)
... ...
@@ -287,7 +286,7 @@ bool S9xMixSamples(uint8_t *buffer, int sample_count)
287 286
 
288 287
 	if (Settings.Mute)
289 288
 	{
290
-		std::fill(&dest[0], &dest[sample_count << 1], 0);
289
+		std::fill_n(&dest[0], sample_count << 1, 0);
291 290
 		spc::resampler->clear();
292 291
 
293 292
 		return false;
... ...
@@ -302,7 +301,7 @@ bool S9xMixSamples(uint8_t *buffer, int sample_count)
302 301
 		}
303 302
 		else
304 303
 		{
305
-			std::fill(&buffer[0], &buffer[(sample_count << (Settings.SixteenBitSound ? 1 : 0)) >> (Settings.Stereo ? 0 : 1)], Settings.SixteenBitSound ? 0 : 128);
304
+			std::fill_n(&buffer[0], (sample_count << (Settings.SixteenBitSound ? 1 : 0)) >> (Settings.Stereo ? 0 : 1), Settings.SixteenBitSound ? 0 : 128);
306 305
 			if (!spc::lag)
307 306
 				spc::lag = spc::lag_master;
308 307
 
... ...
@@ -324,7 +323,7 @@ bool S9xMixSamples(uint8_t *buffer, int sample_count)
324 323
 		if (!Settings.SixteenBitSound)
325 324
 			EightBitize(dest, sample_count);
326 325
 
327
-		std::copy(&dest[0], &dest[sample_count << (Settings.SixteenBitSound ? 1 : 0)], &buffer[0]);
326
+		std::copy_n(&dest[0], sample_count << (Settings.SixteenBitSound ? 1 : 0), &buffer[0]);
328 327
 	}
329 328
 
330 329
 	return true;
... ...
@@ -349,12 +348,7 @@ void S9xFinalizeSamples()
349 348
 		}
350 349
 	}
351 350
 
352
-	if (!Settings.SoundSync || Settings.TurboMode || Settings.Mute)
353
-		spc::sound_in_sync = true;
354
-	else if (spc::resampler->space_empty() >= spc::resampler->space_filled())
355
-		spc::sound_in_sync = true;
356
-	else
357
-		spc::sound_in_sync = false;
351
+	spc::sound_in_sync = !Settings.SoundSync || Settings.TurboMode || Settings.Mute || spc::resampler->space_empty() >= spc::resampler->space_filled();
358 352
 
359 353
 	spc_core->set_output(reinterpret_cast<SNES_SPC::sample_t *>(spc::landing_buffer.get()), spc::buffer_size >> 1);
360 354
 }
Browse code

[SNSF] Massive code cleanup, as well as removing as much unused code/variables as possible.

Naram Qashat authored on 2013/05/23 06:02:16
Showing 1 changed files
... ...
@@ -175,11 +175,8 @@
175 175
   Nintendo Co., Limited and its subsidiary companies.
176 176
  ***********************************************************************************/
177 177
 
178
-
179
-#include <math.h>
178
+#include <memory>
180 179
 #include "apu.h"
181
-//#include "snapshot.h"
182
-//#include "display.h"
183 180
 #include "linear_resampler.h"
184 181
 #include "hermite_resampler.h"
185 182
 #include "bspline_resampler.h"
... ...
@@ -189,18 +186,17 @@
189 186
 bool SincResampler::initializedLUTs = false;
190 187
 double SincResampler::sinc_lut[SincResampler::SINC_SAMPLES + 1];
191 188
 
192
-#define APU_DEFAULT_INPUT_RATE		32000
193
-#define APU_MINIMUM_SAMPLE_COUNT	512
194
-#define APU_MINIMUM_SAMPLE_BLOCK	128
195
-#define APU_NUMERATOR_NTSC			15664
196
-#define APU_DENOMINATOR_NTSC		328125
197
-#define APU_NUMERATOR_PAL			34176
198
-#define APU_DENOMINATOR_PAL			709379
199
-#define APU_DEFAULT_RESAMPLER		HermiteResampler
189
+static const uint32_t APU_DEFAULT_INPUT_RATE = 32000;
190
+static const int APU_MINIMUM_SAMPLE_COUNT = 512;
191
+static const int APU_MINIMUM_SAMPLE_BLOCK = 128;
192
+static const uint32_t APU_NUMERATOR_NTSC = 15664;
193
+static const uint32_t APU_DENOMINATOR_NTSC = 328125;
194
+static const uint32_t APU_NUMERATOR_PAL = 34176;
195
+static const uint32_t APU_DENOMINATOR_PAL = 709379;
200 196
 
201
-SNES_SPC	*spc_core = NULL;
197
+static std::unique_ptr<SNES_SPC> spc_core;
202 198
 
203
-static uint8_t APUROM[64] =
199
+static const uint8_t APUROM[] =
204 200
 {
205 201
 	0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0,
206 202
 	0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78,
... ...
@@ -214,81 +210,62 @@ static uint8_t APUROM[64] =
214 210
 
215 211
 namespace spc
216 212
 {
217
-	static apu_callback	sa_callback     = NULL;
218
-	static void			*extra_data     = NULL;
219
-
220
-	static bool		sound_in_sync   = true;
221
-	static bool		sound_enabled   = false;
213
+	static bool sound_in_sync = true;
214
+	static bool sound_enabled = false;
222 215
 
223
-	static int			buffer_size;
224
-	static int			lag_master      = 0;
225
-	static int			lag             = 0;
216
+	static int buffer_size;
217
+	static int lag_master = 0;
218
+	static int lag = 0;
226 219
 
227
-	static uint8_t		*landing_buffer = NULL;
228
-	static uint8_t		*shrink_buffer  = NULL;
220
+	static std::unique_ptr<uint8_t[]> landing_buffer;
221
+	static std::unique_ptr<uint8_t[]> shrink_buffer;
229 222
 
230
-	static Resampler	*resampler      = NULL;
223
+	static std::unique_ptr<Resampler> resampler;
231 224
 
232
-	static int32_t		reference_time;
233
-	static uint32_t		remainder;
225
+	static int32_t reference_time;
226
+	static uint32_t remainder;
234 227
 
235
-	static const int	timing_hack_numerator   = SNES_SPC::tempo_unit;
236
-	static int			timing_hack_denominator = SNES_SPC::tempo_unit;
228
+	static const int timing_hack_numerator = SNES_SPC::tempo_unit;
229
+	static int timing_hack_denominator = SNES_SPC::tempo_unit;
237 230
 	/* Set these to NTSC for now. Will change to PAL in S9xAPUTimingSetSpeedup
238 231
 	   if necessary on game load. */
239
-	static uint32_t		ratio_numerator = APU_NUMERATOR_NTSC;
240
-	static uint32_t		ratio_denominator = APU_DENOMINATOR_NTSC;
232
+	static uint32_t ratio_numerator = APU_NUMERATOR_NTSC;
233
+	static uint32_t ratio_denominator = APU_DENOMINATOR_NTSC;
241 234
 }
242 235
 
243
-static void EightBitize (uint8_t *, int);
244
-static void DeStereo (uint8_t *, int);
245
-static void ReverseStereo (uint8_t *, int);
246
-static void UpdatePlaybackRate();
247
-static void from_apu_to_state (uint8_t **, void *, size_t);
248
-static void to_apu_from_state (uint8_t **, void *, size_t);
249
-//static void SPCSnapshotCallback();
250
-static inline int S9xAPUGetClock (int32_t);
251
-static inline int S9xAPUGetClockRemainder (int32_t);
252
-
253
-
254
-static void EightBitize (uint8_t *buffer, int sample_count)
236
+static void EightBitize(uint8_t *buffer, int sample_count)
255 237
 {
256
-	uint8_t	*buf8  = (uint8_t *) buffer;
257
-	int16_t	*buf16 = (int16_t *) buffer;
238
+	uint8_t *buf8 = buffer;
239
+	int16_t *buf16 = reinterpret_cast<int16_t *>(buffer);
258 240
 
259
-	for (int i = 0; i < sample_count; i++)
260
-		buf8[i] = (uint8_t) ((buf16[i] / 256) + 128);
241
+	for (int i = 0; i < sample_count; ++i)
242
+		buf8[i] = static_cast<uint8_t>((buf16[i] / 256) + 128);
261 243
 }
262 244
 
263
-static void DeStereo (uint8_t *buffer, int sample_count)
245
+static void DeStereo(uint8_t *buffer, int sample_count)
264 246
 {
265
-	int16_t	*buf = (int16_t *) buffer;
266
-	int32_t	s1, s2;
247
+	int16_t *buf = reinterpret_cast<int16_t *>(buffer);
267 248
 
268
-	for (int i = 0; i < sample_count >> 1; i++)
249
+	for (int i = 0; i < sample_count >> 1; ++i)
269 250
 	{
270
-		s1 = (int32_t) buf[2 * i];
271
-		s2 = (int32_t) buf[2 * i + 1];
272
-		buf[i] = (int16_t) ((s1 + s2) >> 1);
251
+		int32_t s1 = static_cast<int32_t>(buf[2 * i]);
252
+		int32_t s2 = static_cast<int32_t>(buf[2 * i + 1]);
253
+		buf[i] = static_cast<int16_t>((s1 + s2) >> 1);
273 254
 	}
274 255
 }
275 256
 
276
-static void ReverseStereo (uint8_t *src_buffer, int sample_count)
257
+static void ReverseStereo(uint8_t *src_buffer, int sample_count)
277 258
 {
278
-	int16_t	*buffer = (int16_t *) src_buffer;
259
+	int16_t *buffer = reinterpret_cast<int16_t *>(src_buffer);
279 260
 
280 261
 	for (int i = 0; i < sample_count; i += 2)
281
-	{
282
-		buffer[i + 1] ^= buffer[i];
283
-		buffer[i] ^= buffer[i + 1];
284
-		buffer[i + 1] ^= buffer[i];
285
-	}
262
+		std::swap(buffer[i], buffer[i + 1]);
286 263
 }
287 264
 
288
-bool S9xMixSamples (uint8_t *buffer, int sample_count)
265
+bool S9xMixSamples(uint8_t *buffer, int sample_count)
289 266
 {
290
-	static int	shrink_buffer_size = -1;
291
-	uint8_t		*dest;
267
+	static int shrink_buffer_size = -1;
268
+	uint8_t *dest;
292 269
 
293 270
 	if (!Settings.SixteenBitSound || !Settings.Stereo)
294 271
 	{
... ...
@@ -299,35 +276,34 @@ bool S9xMixSamples (uint8_t *buffer, int sample_count)
299 276
 		/* We still have to generate 16-bit samples for bit-dropping, too */
300 277
 		if (shrink_buffer_size < (sample_count << 1))
301 278
 		{
302
-			delete[] spc::shrink_buffer;
303
-			spc::shrink_buffer = new uint8_t[sample_count << 1];
279
+			spc::shrink_buffer.reset(new uint8_t[sample_count << 1]);
304 280
 			shrink_buffer_size = sample_count << 1;
305 281
 		}
306 282
 
307
-		dest = spc::shrink_buffer;
283
+		dest = spc::shrink_buffer.get();
308 284
 	}
309 285
 	else
310 286
 		dest = buffer;
311 287
 
312 288
 	if (Settings.Mute)
313 289
 	{
314
-		memset(dest, 0, sample_count << 1);
290
+		std::fill(&dest[0], &dest[sample_count << 1], 0);
315 291
 		spc::resampler->clear();
316 292
 
317 293
 		return false;
318 294
 	}
319 295
 	else
320 296
 	{
321
-		if (spc::resampler->avail() >= (sample_count + spc::lag))
297
+		if (spc::resampler->avail() >= sample_count + spc::lag)
322 298
 		{
323
-			spc::resampler->read((short *) dest, sample_count);
299
+			spc::resampler->read(reinterpret_cast<short *>(dest), sample_count);
324 300
 			if (spc::lag == spc::lag_master)
325 301
 				spc::lag = 0;
326 302
 		}
327 303
 		else
328 304
 		{
329
-			memset(buffer, (Settings.SixteenBitSound ? 0 : 128), (sample_count << (Settings.SixteenBitSound ? 1 : 0)) >> (Settings.Stereo ? 0 : 1));
330
-			if (spc::lag == 0)
305
+			std::fill(&buffer[0], &buffer[(sample_count << (Settings.SixteenBitSound ? 1 : 0)) >> (Settings.Stereo ? 0 : 1)], Settings.SixteenBitSound ? 0 : 128);
306
+			if (!spc::lag)
331 307
 				spc::lag = spc::lag_master;
332 308
 
333 309
 			return false;
... ...
@@ -348,7 +324,7 @@ bool S9xMixSamples (uint8_t *buffer, int sample_count)
348 324
 		if (!Settings.SixteenBitSound)
349 325
 			EightBitize(dest, sample_count);
350 326
 
351
-		memcpy(buffer, dest, (sample_count << (Settings.SixteenBitSound ? 1 : 0)));
327
+		std::copy(&dest[0], &dest[sample_count << (Settings.SixteenBitSound ? 1 : 0)], &buffer[0]);
352 328
 	}
353 329
 
354 330
 	return true;
... ...
@@ -363,7 +339,7 @@ void S9xFinalizeSamples()
363 339
 {
364 340
 	if (!Settings.Mute)
365 341
 	{
366
-		if (!spc::resampler->push((short *) spc::landing_buffer, spc_core->sample_count()))
342
+		if (!spc::resampler->push(reinterpret_cast<short *>(spc::landing_buffer.get()), spc_core->sample_count()))
367 343
 		{
368 344
 			/* We weren't able to process the entire buffer. Potential overrun. */
369 345
 			spc::sound_in_sync = false;
... ...
@@ -375,27 +351,17 @@ void S9xFinalizeSamples()
375 351
 
376 352
 	if (!Settings.SoundSync || Settings.TurboMode || Settings.Mute)
377 353
 		spc::sound_in_sync = true;
378
-	else
379
-	if (spc::resampler->space_empty() >= spc::resampler->space_filled())
354
+	else if (spc::resampler->space_empty() >= spc::resampler->space_filled())
380 355
 		spc::sound_in_sync = true;
381 356
 	else
382 357
 		spc::sound_in_sync = false;
383 358
 
384
-	spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
359
+	spc_core->set_output(reinterpret_cast<SNES_SPC::sample_t *>(spc::landing_buffer.get()), spc::buffer_size >> 1);
385 360
 }
386 361
 
387 362
 void S9xLandSamples()
388 363
 {
389
-	if (spc::sa_callback != NULL)
390
-		spc::sa_callback(spc::extra_data);
391
-	else
392
-		S9xFinalizeSamples();
393
-}
394
-
395
-void S9xClearSamples()
396
-{
397
-	spc::resampler->clear();
398
-	spc::lag = spc::lag_master;
364
+	S9xFinalizeSamples();
399 365
 }
400 366
 
401 367
 bool S9xSyncSound()
... ...
@@ -408,28 +374,22 @@ bool S9xSyncSound()
408 374
 	return spc::sound_in_sync;
409 375
 }
410 376
 
411
-void S9xSetSamplesAvailableCallback (apu_callback callback, void *data)
412
-{
413
-	spc::sa_callback = callback;
414
-	spc::extra_data  = data;
415
-}
416
-
417 377
 static void UpdatePlaybackRate()
418 378
 {
419
-	if (Settings.SoundInputRate == 0)
379
+	if (!Settings.SoundInputRate)
420 380
 		Settings.SoundInputRate = APU_DEFAULT_INPUT_RATE;
421 381
 
422
-	double time_ratio = (double) Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator);
382
+	double time_ratio = static_cast<double>(Settings.SoundInputRate) * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator);
423 383
 	spc::resampler->time_ratio(time_ratio);
424 384
 }
425 385
 
426
-template<class ResamplerClass> bool S9xInitSound (int buffer_ms, int lag_ms)
386
+template<class ResamplerClass> bool S9xInitSound(int buffer_ms, int lag_ms)
427 387
 {
428 388
 	// buffer_ms : buffer size given in millisecond
429 389
 	// lag_ms    : allowable time-lag given in millisecond
430 390
 
431
-	int	sample_count     = buffer_ms * 32000 / 1000;
432
-	int	lag_sample_count = lag_ms    * 32000 / 1000;
391
+	int sample_count = buffer_ms * 32000 / 1000;
392
+	int lag_sample_count = lag_ms * 32000 / 1000;
433 393
 
434 394
 	spc::lag_master = lag_sample_count;
435 395
 	if (Settings.Stereo)
... ...
@@ -445,32 +405,20 @@ template<class ResamplerClass> bool S9xInitSound (int buffer_ms, int lag_ms)
445 405
 	if (Settings.SixteenBitSound)
446 406
 		spc::buffer_size <<= 1;
447 407
 
448
-	printf("Sound buffer size: %d (%d samples)\n", spc::buffer_size, sample_count);
449
-
450
-	if (spc::landing_buffer)
451
-		delete[] spc::landing_buffer;
452
-	spc::landing_buffer = new uint8_t[spc::buffer_size * 2];
408
+	spc::landing_buffer.reset(new uint8_t[spc::buffer_size * 2]);
453 409
 	if (!spc::landing_buffer)
454 410
 		return false;
455 411
 
456 412
 	/* The resampler and spc unit use samples (16-bit short) as
457 413
 	/*   arguments. Use 2x in the resampler for buffer leveling with SoundSync */
458
-	/*if (!spc::resampler)
459
-	{*/
460
-	if (spc::resampler)
461
-		delete spc::resampler;
462
-
463
-		spc::resampler = new ResamplerClass(spc::buffer_size >> (Settings.SoundSync ? 0 : 1));
464
-		if (!spc::resampler)
465
-		{
466
-			delete[] spc::landing_buffer;
467
-			return false;
468
-		}
469
-	/*}
470
-	else
471
-		spc::resampler->resize(spc::buffer_size >> (Settings.SoundSync ? 0 : 1));*/
414
+	spc::resampler.reset(new ResamplerClass(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)));
415
+	if (!spc::resampler)
416
+	{
417
+		spc::landing_buffer.reset();
418
+		return false;
419
+	}
472 420
 
473
-	spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
421
+	spc_core->set_output(reinterpret_cast<SNES_SPC::sample_t *>(spc::landing_buffer.get()), spc::buffer_size >> 1);
474 422
 
475 423
 	UpdatePlaybackRate();
476 424
 
... ...
@@ -485,97 +433,63 @@ template bool S9xInitSound<BsplineResampler>(int, int);
485 433
 template bool S9xInitSound<OsculatingResampler>(int, int);
486 434
 template bool S9xInitSound<SincResampler>(int, int);
487 435
 
488
-void S9xSetSoundControl (uint8_t voice_switch)
436
+void S9xSetSoundControl(uint8_t voice_switch)
489 437
 {
490
-	spc_core->dsp_set_stereo_switch(voice_switch << 8 | voice_switch);
438
+	spc_core->dsp_set_stereo_switch((voice_switch << 8) | voice_switch);
491 439
 }
492 440
 
493
-void S9xSetSoundMute (bool mute)
441
+void S9xSetSoundMute(bool mute)
494 442
 {
495 443
 	Settings.Mute = mute;
496 444
 	if (!spc::sound_enabled)
497 445
 		Settings.Mute = true;
498 446
 }
499 447
 
500
-void S9xDumpSPCSnapshot()
501
-{
502
-	spc_core->dsp_dump_spc_snapshot();
503
-}
504
-
505
-/*static void SPCSnapshotCallback()
506
-{
507
-	S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR));
508
-	printf("Dumped key-on triggered spc snapshot.\n");
509
-}*/
510
-
511 448
 bool S9xInitAPU()
512 449
 {
513
-	spc_core = new SNES_SPC;
450
+	spc_core.reset(new SNES_SPC);
514 451
 	if (!spc_core)
515 452
 		return false;
516 453
 
517 454
 	spc_core->init();
518 455
 	spc_core->init_rom(APUROM);
519 456
 
520
-	//spc_core->dsp_set_spc_snapshot_callback(SPCSnapshotCallback);
521
-
522
-	spc::landing_buffer = NULL;
523
-	spc::shrink_buffer  = NULL;
524
-	spc::resampler      = NULL;
457
+	spc::landing_buffer.reset();
458
+	spc::shrink_buffer.reset();
459
+	spc::resampler.reset();
525 460
 
526 461
 	return true;
527 462
 }
528 463
 
529 464
 void S9xDeinitAPU()
530 465
 {
531
-	if (spc_core)
532
-	{
533
-		delete spc_core;
534
-		spc_core = NULL;
535
-	}
536
-
537
-	if (spc::resampler)
538
-	{
539
-		delete spc::resampler;
540
-		spc::resampler = NULL;
541
-	}
542
-
543
-	if (spc::landing_buffer)
544
-	{
545
-		delete[] spc::landing_buffer;
546
-		spc::landing_buffer = NULL;
547
-	}
548
-
549
-	if (spc::shrink_buffer)
550
-	{
551
-		delete[] spc::shrink_buffer;
552
-		spc::shrink_buffer = NULL;
553
-	}
466
+	spc_core.reset();
467
+	spc::resampler.reset();
468
+	spc::landing_buffer.reset();
469
+	spc::shrink_buffer.reset();
554 470
 }
555 471
 
556
-static inline int S9xAPUGetClock (int32_t cpucycles)
472
+static inline int S9xAPUGetClock(int32_t cpucycles)
557 473
 {
558
-	return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) /
559
-			spc::ratio_denominator;
474
+	return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) / spc::ratio_denominator;
560 475
 }
561 476
 
562
-static inline int S9xAPUGetClockRemainder (int32_t cpucycles)
477
+static inline int S9xAPUGetClockRemainder(int32_t cpucycles)
563 478
 {
564
-	return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) %
565
-			spc::ratio_denominator;
479
+	return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) % spc::ratio_denominator;
566 480
 }
567 481
 
568
-uint8_t S9xAPUReadPort (int port)
482
+uint8_t S9xAPUReadPort(int port)
569 483
 {
570
-	return (uint8_t) spc_core->read_port(S9xAPUGetClock(CPU.Cycles), port);
484
+	return static_cast<uint8_t>(spc_core->read_port(S9xAPUGetClock(CPU.Cycles), port));
571 485
 }
572 486
 
573
-void S9xAPUWritePort (int port, uint8_t byte)
487
+void S9xAPUWritePort(int port, uint8_t byte)
574 488
 {
575 489
 	spc_core->write_port(S9xAPUGetClock(CPU.Cycles), port, byte);
576 490
 }
577 491
 
578
-void S9xAPUSetReferenceTime (int32_t cpucycles)
492
+void S9xAPUSetReferenceTime(int32_t cpucycles)
579 493
 {
580 494
 	spc::reference_time = cpucycles;
581 495
 }
... ...
@@ -598,26 +512,19 @@ void S9xAPUEndScanline()
598 512
 		S9xLandSamples();
599 513
 }
600 514
 
601
-void S9xAPUTimingSetSpeedup (int ticks)
515
+void S9xAPUTimingSetSpeedup(int ticks)
602 516
 {
603
-	if (ticks != 0)
604
-		printf("APU speedup hack: %d\n", ticks);
605
-
606 517
 	spc::timing_hack_denominator = SNES_SPC::tempo_unit - ticks;
607 518
 	spc_core->set_tempo(spc::timing_hack_denominator);
608 519
 
609 520
 	spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC;
610
-	spc::ratio_denominator = Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC;
611
-	spc::ratio_denominator = spc::ratio_denominator * spc::timing_hack_denominator / spc::timing_hack_numerator;
521
+	spc::ratio_denominator = (Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC) * spc::timing_hack_denominator / spc::timing_hack_numerator;
612 522
 
613 523
 	UpdatePlaybackRate();
614 524
 }
615 525
 
616
-void S9xAPUAllowTimeOverflow (bool allow)
526
+void S9xAPUAllowTimeOverflow(bool allow)
617 527
 {
618
-	if (allow)
619
-		printf("APU time overflow allowed\n");
620
-
621 528
 	spc_core->spc_allow_time_overflow(allow);
622 529
 }
623 530
 
... ...
@@ -626,53 +533,7 @@ void S9xResetAPU()
626 533
 	spc::reference_time = 0;
627 534
 	spc::remainder = 0;
628 535
 	spc_core->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
-void S9xSoftResetAPU()
635
-{
636
-	spc::reference_time = 0;
637
-	spc::remainder = 0;
638
-	spc_core->soft_reset();
639
-	spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
536
+	spc_core->set_output(reinterpret_cast<SNES_SPC::sample_t *>(spc::landing_buffer.get()), spc::buffer_size >> 1);
640 537
 
641 538
 	spc::resampler->clear();
642 539
 }
643
-
644
-static void from_apu_to_state (uint8_t **buf, void *var, size_t size)
645
-{
646
-	memcpy(*buf, var, size);
647
-	*buf += size;
648
-}
649
-
650
-static void to_apu_from_state (uint8_t **buf, void *var, size_t size)
651
-{
652
-	memcpy(var, *buf, size);
653
-	*buf += size;
654
-}
655
-
656
-void S9xAPUSaveState (uint8_t *block)
657
-{
658
-	uint8_t	*ptr = block;
659
-
660
-	spc_core->copy_state(&ptr, from_apu_to_state);
661
-
662
-	SET_LE32(ptr, spc::reference_time);
663
-	ptr += sizeof(int32_t);
664
-	SET_LE32(ptr, spc::remainder);
665
-}
666
-
667
-void S9xAPULoadState (uint8_t *block)
668
-{
669
-	uint8_t	*ptr = block;
670
-
671
-	S9xResetAPU();
672
-
673
-	spc_core->copy_state(&ptr, to_apu_from_state);
674
-
675
-	spc::reference_time = GET_LE32(ptr);
676
-	ptr += sizeof(int32_t);
677
-	spc::remainder = GET_LE32(ptr);
678
-}
Browse code

Added Sinc resampler to SNSF plugin, as well as fixed issue with there being garbage at the start of an SNSF when played after one has finished.

Naram Qashat authored on 2013/05/08 03:42:24
Showing 1 changed files
... ...
@@ -184,6 +184,10 @@
184 184
 #include "hermite_resampler.h"
185 185
 #include "bspline_resampler.h"
186 186
 #include "osculating_resampler.h"
187
+#include "sinc_resampler.h"
188
+
189
+bool SincResampler::initializedLUTs = false;
190
+double SincResampler::sinc_lut[SincResampler::SINC_SAMPLES + 1];
187 191
 
188 192
 #define APU_DEFAULT_INPUT_RATE		32000
189 193
 #define APU_MINIMUM_SAMPLE_COUNT	512
... ...
@@ -479,6 +483,7 @@ template bool S9xInitSound<LinearResampler>(int, int);
479 483
 template bool S9xInitSound<HermiteResampler>(int, int);
480 484
 template bool S9xInitSound<BsplineResampler>(int, int);
481 485
 template bool S9xInitSound<OsculatingResampler>(int, int);
486
+template bool S9xInitSound<SincResampler>(int, int);
482 487
 
483 488
 void S9xSetSoundControl (uint8_t voice_switch)
484 489
 {
Browse code

For in_snsf, replaced the B-spline interpolation with the 6-point, 5th-order version, and replaced the Optimal interpolation with 6-point, 5th-order 2nd-order Osculating.

Naram Qashat authored on 2013/04/12 13:36:31
Showing 1 changed files
... ...
@@ -183,7 +183,7 @@
183 183
 #include "linear_resampler.h"
184 184
 #include "hermite_resampler.h"
185 185
 #include "bspline_resampler.h"
186
-#include "optimal_resampler.h"
186
+#include "osculating_resampler.h"
187 187
 
188 188
 #define APU_DEFAULT_INPUT_RATE		32000
189 189
 #define APU_MINIMUM_SAMPLE_COUNT	512
... ...
@@ -478,7 +478,7 @@ template<class ResamplerClass> bool S9xInitSound (int buffer_ms, int lag_ms)
478 478
 template bool S9xInitSound<LinearResampler>(int, int);
479 479
 template bool S9xInitSound<HermiteResampler>(int, int);
480 480
 template bool S9xInitSound<BsplineResampler>(int, int);
481
-template bool S9xInitSound<OptimalResampler>(int, int);
481
+template bool S9xInitSound<OsculatingResampler>(int, int);
482 482
 
483 483
 void S9xSetSoundControl (uint8_t voice_switch)
484 484
 {
Browse code

Added B-spline and Optimal interpolations to in_snsf, but I'll probably be changing this later.

Naram Qashat authored on 2013/04/12 10:24:45
Showing 1 changed files
... ...
@@ -182,6 +182,8 @@
182 182
 //#include "display.h"
183 183
 #include "linear_resampler.h"
184 184
 #include "hermite_resampler.h"
185
+#include "bspline_resampler.h"
186
+#include "optimal_resampler.h"
185 187
 
186 188
 #define APU_DEFAULT_INPUT_RATE		32000
187 189
 #define APU_MINIMUM_SAMPLE_COUNT	512
... ...
@@ -475,6 +477,8 @@ template<class ResamplerClass> bool S9xInitSound (int buffer_ms, int lag_ms)
475 477
 
476 478
 template bool S9xInitSound<LinearResampler>(int, int);
477 479
 template bool S9xInitSound<HermiteResampler>(int, int);
480
+template bool S9xInitSound<BsplineResampler>(int, int);
481
+template bool S9xInitSound<OptimalResampler>(int, int);
478 482
 
479 483
 void S9xSetSoundControl (uint8_t voice_switch)
480 484
 {
Browse code

Cleanup of some warnings, updating modification dates, using nullptr instead of NULL in some cases.

Naram Qashat authored on 2013/03/30 16:17:42
Showing 1 changed files
... ...
@@ -177,7 +177,6 @@
177 177
 
178 178
 
179 179
 #include <math.h>
180
-#include "snes9x.h"
181 180
 #include "apu.h"
182 181
 //#include "snapshot.h"
183 182
 //#include "display.h"
Browse code

Import actual code.

Naram Qashat authored on 2013/03/26 02:41:19
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,670 @@
1
+/***********************************************************************************
2
+  Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
+
4
+  (c) Copyright 1996 - 2002  Gary Henderson (gary.henderson@ntlworld.com),
5
+                             Jerremy Koot (jkoot@snes9x.com)
6
+
7
+  (c) Copyright 2002 - 2004  Matthew Kendora
8
+
9
+  (c) Copyright 2002 - 2005  Peter Bortas (peter@bortas.org)
10
+
11
+  (c) Copyright 2004 - 2005  Joel Yliluoma (http://iki.fi/bisqwit/)
12
+
13
+  (c) Copyright 2001 - 2006  John Weidman (jweidman@slip.net)
14
+
15
+  (c) Copyright 2002 - 2006  funkyass (funkyass@spam.shaw.ca),
16
+                             Kris Bleakley (codeviolation@hotmail.com)
17
+
18
+  (c) Copyright 2002 - 2010  Brad Jorsch (anomie@users.sourceforge.net),
19
+                             Nach (n-a-c-h@users.sourceforge.net),
20
+
21
+  (c) Copyright 2002 - 2011  zones (kasumitokoduck@yahoo.com)
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_ (_demo_@zsnes.com),
35
+                             Nach,
36
+                             zsKnight (zsknight@zsnes.com)
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 (andreasnaive@gmail.com),
45
+                             Gary Henderson,
46
+                             Ivar (ivar@snes9x.com),
47
+                             John Weidman,
48
+                             Kris Bleakley,
49
+                             Matthew Kendora,
50
+                             Nach,
51
+                             neviksti (neviksti@hotmail.com)
52
+
53
+  DSP-2 emulator code
54
+  (c) Copyright 2003         John Weidman,
55
+                             Kris Bleakley,
56
+                             Lord Nightmare (lord_nightmare@users.sourceforge.net),
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 (pagefault@zsnes.com),
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 (gblargg@gmail.com)
120
+
121
+  SH assembler code partly based on x86 assembler code
122
+  (c) Copyright 2002 - 2004  Marcus Comstedt (marcus@mc.pp.se)
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 (maxim@hiend3d.com)
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
+//#include "snapshot.h"
183
+//#include "display.h"
184
+#include "linear_resampler.h"
185
+#include "hermite_resampler.h"
186
+
187
+#define APU_DEFAULT_INPUT_RATE		32000
188
+#define APU_MINIMUM_SAMPLE_COUNT	512
189
+#define APU_MINIMUM_SAMPLE_BLOCK	128
190
+#define APU_NUMERATOR_NTSC			15664
191
+#define APU_DENOMINATOR_NTSC		328125
192
+#define APU_NUMERATOR_PAL			34176
193
+#define APU_DENOMINATOR_PAL			709379
194
+#define APU_DEFAULT_RESAMPLER		HermiteResampler
195
+
196
+SNES_SPC	*spc_core = NULL;
197
+
198
+static uint8_t APUROM[64] =
199
+{
200
+	0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0,
201
+	0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78,
202
+	0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4,
203
+	0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5,
204
+	0xCB, 0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB,
205
+	0x01, 0x10, 0xEF, 0x7E, 0xF4, 0x10, 0xEB, 0xBA,
206
+	0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4, 0xDD,
207
+	0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF
208
+};
209
+
210
+namespace spc
211
+{
212
+	static apu_callback	sa_callback     = NULL;
213
+	static void			*extra_data     = NULL;
214
+
215
+	static bool		sound_in_sync   = true;
216
+	static bool		sound_enabled   = false;
217
+
218
+	static int			buffer_size;
219
+	static int			lag_master      = 0;
220
+	static int			lag             = 0;
221
+
222
+	static uint8_t		*landing_buffer = NULL;
223
+	static uint8_t		*shrink_buffer  = NULL;
224
+
225
+	static Resampler	*resampler      = NULL;
226
+
227
+	static int32_t		reference_time;
228
+	static uint32_t		remainder;
229
+
230
+	static const int	timing_hack_numerator   = SNES_SPC::tempo_unit;
231
+	static int			timing_hack_denominator = SNES_SPC::tempo_unit;
232
+	/* Set these to NTSC for now. Will change to PAL in S9xAPUTimingSetSpeedup
233
+	   if necessary on game load. */
234
+	static uint32_t		ratio_numerator = APU_NUMERATOR_NTSC;
235
+	static uint32_t		ratio_denominator = APU_DENOMINATOR_NTSC;
236
+}
237
+
238
+static void EightBitize (uint8_t *, int);
239
+static void DeStereo (uint8_t *, int);
240
+static void ReverseStereo (uint8_t *, int);
241
+static void UpdatePlaybackRate();
242
+static void from_apu_to_state (uint8_t **, void *, size_t);
243
+static void to_apu_from_state (uint8_t **, void *, size_t);
244
+//static void SPCSnapshotCallback();
245
+static inline int S9xAPUGetClock (int32_t);
246
+static inline int S9xAPUGetClockRemainder (int32_t);
247
+
248
+
249
+static void EightBitize (uint8_t *buffer, int sample_count)
250
+{
251
+	uint8_t	*buf8  = (uint8_t *) buffer;
252
+	int16_t	*buf16 = (int16_t *) buffer;
253
+
254
+	for (int i = 0; i < sample_count; i++)
255
+		buf8[i] = (uint8_t) ((buf16[i] / 256) + 128);
256
+}
257
+
258
+static void DeStereo (uint8_t *buffer, int sample_count)
259
+{
260
+	int16_t	*buf = (int16_t *) buffer;
261
+	int32_t	s1, s2;
262
+
263
+	for (int i = 0; i < sample_count >> 1; i++)
264
+	{
265
+		s1 = (int32_t) buf[2 * i];
266
+		s2 = (int32_t) buf[2 * i + 1];
267
+		buf[i] = (int16_t) ((s1 + s2) >> 1);
268
+	}
269
+}
270
+
271
+static void ReverseStereo (uint8_t *src_buffer, int sample_count)
272
+{
273
+	int16_t	*buffer = (int16_t *) src_buffer;
274
+
275
+	for (int i = 0; i < sample_count; i += 2)
276
+	{
277
+		buffer[i + 1] ^= buffer[i];
278
+		buffer[i] ^= buffer[i + 1];
279
+		buffer[i + 1] ^= buffer[i];
280
+	}
281
+}
282
+
283
+bool S9xMixSamples (uint8_t *buffer, int sample_count)
284
+{
285
+	static int	shrink_buffer_size = -1;
286
+	uint8_t		*dest;
287
+
288
+	if (!Settings.SixteenBitSound || !Settings.Stereo)
289
+	{
290
+		/* We still need both stereo samples for generating the mono sample */
291
+		if (!Settings.Stereo)
292
+			sample_count <<= 1;
293
+
294
+		/* We still have to generate 16-bit samples for bit-dropping, too */
295
+		if (shrink_buffer_size < (sample_count << 1))
296
+		{
297
+			delete[] spc::shrink_buffer;
298
+			spc::shrink_buffer = new uint8_t[sample_count << 1];
299
+			shrink_buffer_size = sample_count << 1;
300
+		}
301
+
302
+		dest = spc::shrink_buffer;
303
+	}
304
+	else
305
+		dest = buffer;
306
+
307
+	if (Settings.Mute)
308
+	{
309
+		memset(dest, 0, sample_count << 1);
310
+		spc::resampler->clear();
311
+
312
+		return false;
313
+	}
314
+	else
315
+	{
316
+		if (spc::resampler->avail() >= (sample_count + spc::lag))
317
+		{
318
+			spc::resampler->read((short *) dest, sample_count);
319
+			if (spc::lag == spc::lag_master)
320
+				spc::lag = 0;
321
+		}
322
+		else
323
+		{
324
+			memset(buffer, (Settings.SixteenBitSound ? 0 : 128), (sample_count << (Settings.SixteenBitSound ? 1 : 0)) >> (Settings.Stereo ? 0 : 1));
325
+			if (spc::lag == 0)
326
+				spc::lag = spc::lag_master;
327
+
328
+			return false;
329
+		}
330
+	}
331
+
332
+	if (Settings.ReverseStereo && Settings.Stereo)
333
+		ReverseStereo(dest, sample_count);
334
+
335
+	if (!Settings.Stereo || !Settings.SixteenBitSound)
336
+	{
337
+		if (!Settings.Stereo)
338
+		{
339
+			DeStereo(dest, sample_count);
340
+			sample_count >>= 1;
341
+		}
342
+
343
+		if (!Settings.SixteenBitSound)
344
+			EightBitize(dest, sample_count);
345
+
346
+		memcpy(buffer, dest, (sample_count << (Settings.SixteenBitSound ? 1 : 0)));
347
+	}
348
+
349
+	return true;
350
+}
351
+
352
+int S9xGetSampleCount()
353
+{
354
+	return spc::resampler->avail() >> (Settings.Stereo ? 0 : 1);
355
+}
356
+
357
+void S9xFinalizeSamples()
358
+{
359
+	if (!Settings.Mute)
360
+	{
361
+		if (!spc::resampler->push((short *) spc::landing_buffer, spc_core->sample_count()))
362
+		{
363
+			/* We weren't able to process the entire buffer. Potential overrun. */
364
+			spc::sound_in_sync = false;
365
+
366
+			if (Settings.SoundSync && !Settings.TurboMode)
367
+				return;
368
+		}
369
+	}
370
+
371
+	if (!Settings.SoundSync || Settings.TurboMode || Settings.Mute)
372
+		spc::sound_in_sync = true;
373
+	else
374
+	if (spc::resampler->space_empty() >= spc::resampler->space_filled())
375
+		spc::sound_in_sync = true;
376
+	else
377
+		spc::sound_in_sync = false;
378
+
379
+	spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
380
+}
381
+
382
+void S9xLandSamples()
383
+{
384
+	if (spc::sa_callback != NULL)
385
+		spc::sa_callback(spc::extra_data);
386
+	else
387
+		S9xFinalizeSamples();
388
+}
389
+
390
+void S9xClearSamples()
391
+{
392
+	spc::resampler->clear();
393
+	spc::lag = spc::lag_master;
394
+}
395
+
396
+bool S9xSyncSound()
397
+{
398
+	if (!Settings.SoundSync || spc::sound_in_sync)
399
+		return true;
400
+
401
+	S9xLandSamples();
402
+
403
+	return spc::sound_in_sync;
404
+}
405
+
406
+void S9xSetSamplesAvailableCallback (apu_callback callback, void *data)
407
+{
408
+	spc::sa_callback = callback;
409
+	spc::extra_data  = data;
410
+}
411
+
412
+static void UpdatePlaybackRate()
413
+{
414
+	if (Settings.SoundInputRate == 0)
415
+		Settings.SoundInputRate = APU_DEFAULT_INPUT_RATE;
416
+
417
+	double time_ratio = (double) Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator);
418
+	spc::resampler->time_ratio(time_ratio);
419
+}
420
+
421
+template<class ResamplerClass> bool S9xInitSound (int buffer_ms, int lag_ms)
422
+{
423
+	// buffer_ms : buffer size given in millisecond
424
+	// lag_ms    : allowable time-lag given in millisecond
425
+
426
+	int	sample_count     = buffer_ms * 32000 / 1000;
427
+	int	lag_sample_count = lag_ms    * 32000 / 1000;
428
+
429
+	spc::lag_master = lag_sample_count;
430
+	if (Settings.Stereo)
431
+		spc::lag_master <<= 1;
432
+	spc::lag = spc::lag_master;
433
+
434
+	if (sample_count < APU_MINIMUM_SAMPLE_COUNT)
435
+		sample_count = APU_MINIMUM_SAMPLE_COUNT;
436
+
437
+	spc::buffer_size = sample_count;
438
+	if (Settings.Stereo)
439
+		spc::buffer_size <<= 1;
440
+	if (Settings.SixteenBitSound)
441
+		spc::buffer_size <<= 1;
442
+
443
+	printf("Sound buffer size: %d (%d samples)\n", spc::buffer_size, sample_count);
444
+
445
+	if (spc::landing_buffer)
446
+		delete[] spc::landing_buffer;
447
+	spc::landing_buffer = new uint8_t[spc::buffer_size * 2];
448
+	if (!spc::landing_buffer)
449
+		return false;
450
+
451
+	/* The resampler and spc unit use samples (16-bit short) as
452
+	/*   arguments. Use 2x in the resampler for buffer leveling with SoundSync */
453
+	/*if (!spc::resampler)
454
+	{*/
455
+	if (spc::resampler)
456
+		delete spc::resampler;
457
+
458
+		spc::resampler = new ResamplerClass(spc::buffer_size >> (Settings.SoundSync ? 0 : 1));
459
+		if (!spc::resampler)
460
+		{
461
+			delete[] spc::landing_buffer;
462
+			return false;
463
+		}
464
+	/*}
465
+	else
466
+		spc::resampler->resize(spc::buffer_size >> (Settings.SoundSync ? 0 : 1));*/
467
+
468
+	spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
469
+
470
+	UpdatePlaybackRate();
471
+
472
+	spc::sound_enabled = S9xOpenSoundDevice();
473
+
474
+	return spc::sound_enabled;
475
+}
476
+
477
+template bool S9xInitSound<LinearResampler>(int, int);
478
+template bool S9xInitSound<HermiteResampler>(int, int);
479
+
480
+void S9xSetSoundControl (uint8_t voice_switch)
481
+{
482
+	spc_core->dsp_set_stereo_switch(voice_switch << 8 | voice_switch);
483
+}
484
+
485
+void S9xSetSoundMute (bool mute)
486
+{
487
+	Settings.Mute = mute;
488
+	if (!spc::sound_enabled)
489
+		Settings.Mute = true;
490
+}
491
+
492
+void S9xDumpSPCSnapshot()
493
+{
494
+	spc_core->dsp_dump_spc_snapshot();
495
+}
496
+
497
+/*static void SPCSnapshotCallback()
498
+{
499
+	S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR));
500
+	printf("Dumped key-on triggered spc snapshot.\n");
501
+}*/
502
+
503
+bool S9xInitAPU()
504
+{
505
+	spc_core = new SNES_SPC;
506
+	if (!spc_core)
507
+		return false;
508
+
509
+	spc_core->init();
510
+	spc_core->init_rom(APUROM);
511
+
512
+	//spc_core->dsp_set_spc_snapshot_callback(SPCSnapshotCallback);
513
+
514
+	spc::landing_buffer = NULL;
515
+	spc::shrink_buffer  = NULL;
516
+	spc::resampler      = NULL;
517
+
518
+	return true;
519
+}
520
+
521
+void S9xDeinitAPU()
522
+{
523
+	if (spc_core)
524
+	{
525
+		delete spc_core;
526
+		spc_core = NULL;
527
+	}
528
+
529
+	if (spc::resampler)
530
+	{
531
+		delete spc::resampler;
532
+		spc::resampler = NULL;
533
+	}
534
+
535
+	if (spc::landing_buffer)
536
+	{
537
+		delete[] spc::landing_buffer;
538
+		spc::landing_buffer = NULL;
539
+	}
540
+
541
+	if (spc::shrink_buffer)
542
+	{
543
+		delete[] spc::shrink_buffer;
544
+		spc::shrink_buffer = NULL;
545
+	}
546
+}
547
+
548
+static inline int S9xAPUGetClock (int32_t cpucycles)
549
+{
550
+	return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) /
551
+			spc::ratio_denominator;
552
+}
553
+
554
+static inline int S9xAPUGetClockRemainder (int32_t cpucycles)
555
+{
556
+	return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) %
557
+			spc::ratio_denominator;
558
+}
559
+
560
+uint8_t S9xAPUReadPort (int port)
561
+{
562
+	return (uint8_t) spc_core->read_port(S9xAPUGetClock(CPU.Cycles), port);
563
+}
564
+
565
+void S9xAPUWritePort (int port, uint8_t byte)
566
+{
567
+	spc_core->write_port(S9xAPUGetClock(CPU.Cycles), port, byte);
568
+}
569
+
570
+void S9xAPUSetReferenceTime (int32_t cpucycles)
571
+{
572
+	spc::reference_time = cpucycles;
573
+}
574
+
575
+void S9xAPUExecute()
576
+{
577
+	/* Accumulate partial APU cycles */
578
+	spc_core->end_frame(S9xAPUGetClock(CPU.Cycles));
579
+
580
+	spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles);
581
+
582
+	S9xAPUSetReferenceTime(CPU.Cycles);
583
+}
584
+
585
+void S9xAPUEndScanline()
586
+{
587
+	S9xAPUExecute();
588
+
589
+	if (spc_core->sample_count() >= APU_MINIMUM_SAMPLE_BLOCK || !spc::sound_in_sync)
590
+		S9xLandSamples();
591
+}
592
+
593
+void S9xAPUTimingSetSpeedup (int ticks)
594
+{
595
+	if (ticks != 0)
596
+		printf("APU speedup hack: %d\n", ticks);
597
+
598
+	spc::timing_hack_denominator = SNES_SPC::tempo_unit - ticks;
599
+	spc_core->set_tempo(spc::timing_hack_denominator);
600
+
601
+	spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC;
602
+	spc::ratio_denominator = Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC;
603
+	spc::ratio_denominator = spc::ratio_denominator * spc::timing_hack_denominator / spc::timing_hack_numerator;
604
+
605
+	UpdatePlaybackRate();
606
+}
607
+
608
+void S9xAPUAllowTimeOverflow (bool allow)
609
+{
610
+	if (allow)
611
+		printf("APU time overflow allowed\n");
612
+
613
+	spc_core->spc_allow_time_overflow(allow);
614
+}
615
+
616
+void S9xResetAPU()
617
+{
618
+	spc::reference_time = 0;
619
+	spc::remainder = 0;
620
+	spc_core->reset();
621
+	spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
622
+
623
+	spc::resampler->clear();
624
+}
625
+
626
+void S9xSoftResetAPU()
627
+{
628
+	spc::reference_time = 0;
629
+	spc::remainder = 0;
630
+	spc_core->soft_reset();
631
+	spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
632
+
633
+	spc::resampler->clear();
634
+}
635
+
636
+static void from_apu_to_state (uint8_t **buf, void *var, size_t size)
637
+{
638
+	memcpy(*buf, var, size);
639
+	*buf += size;
640
+}
641
+
642
+static void to_apu_from_state (uint8_t **buf, void *var, size_t size)
643
+{
644
+	memcpy(var, *buf, size);
645
+	*buf += size;
646
+}
647
+
648
+void S9xAPUSaveState (uint8_t *block)
649
+{
650
+	uint8_t	*ptr = block;
651
+
652
+	spc_core->copy_state(&ptr, from_apu_to_state);
653
+
654
+	SET_LE32(ptr, spc::reference_time);
655
+	ptr += sizeof(int32_t);
656
+	SET_LE32(ptr, spc::remainder);
657
+}
658
+
659
+void S9xAPULoadState (uint8_t *block)
660
+{
661
+	uint8_t	*ptr = block;
662
+
663
+	S9xResetAPU();
664
+
665
+	spc_core->copy_state(&ptr, to_apu_from_state);
666
+
667
+	spc::reference_time = GET_LE32(ptr);
668
+	ptr += sizeof(int32_t);
669
+	spc::remainder = GET_LE32(ptr);
670
+}