* [2SF] Used more up-to-date asmjit, despite the ugly looking code.
| ... | ... |
@@ -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 |
{
|
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -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 |
-} |
| ... | ... |
@@ -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 |
{
|
| ... | ... |
@@ -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 |
{
|
| ... | ... |
@@ -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 |
{
|
| 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 |
+} |