diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2013-05-21 04:09:44 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2013-05-21 04:29:04 -0400 |
commit | 71b9685dcd7868f233ce762a07731f6f1fd62adb (patch) | |
tree | 9153ff0200f22a816e6fcc61ba9f53a9a860a69c /lib | |
parent | 00e55d0451930b6c271786d476c4d8b167e80477 (diff) | |
download | rockbox-71b9685dcd7868f233ce762a07731f6f1fd62adb.tar.gz rockbox-71b9685dcd7868f233ce762a07731f6f1fd62adb.zip |
Fix FS#9577 - SNES player missing tracks on certain SPCs
Affected BRR cached waveforms but not realtime BRR decode as far as
I could ascertain. BRR cached waves required loop points to be inside
the initial waveform but this change removes that restriction.
Change-Id: I0ef4db720e5c28bd7b2fb9ae255d27c0a7213f79
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rbcodec/codecs/libspc/spc_codec.h | 1 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libspc/spc_dsp.c | 128 |
2 files changed, 85 insertions, 44 deletions
diff --git a/lib/rbcodec/codecs/libspc/spc_codec.h b/lib/rbcodec/codecs/libspc/spc_codec.h index a8eee6bfef..9686694134 100644 --- a/lib/rbcodec/codecs/libspc/spc_codec.h +++ b/lib/rbcodec/codecs/libspc/spc_codec.h | |||
@@ -292,6 +292,7 @@ struct voice_wave_t | |||
292 | int loop; /* length of looping area */ | 292 | int loop; /* length of looping area */ |
293 | unsigned block_header; /* header byte from current BRR block */ | 293 | unsigned block_header; /* header byte from current BRR block */ |
294 | uint8_t const* addr; /* BRR waveform address in RAM */ | 294 | uint8_t const* addr; /* BRR waveform address in RAM */ |
295 | unsigned loop_addr; /* Loop address in RAM */ | ||
295 | }; | 296 | }; |
296 | #else /* !SPC_BRRCACHE */ | 297 | #else /* !SPC_BRRCACHE */ |
297 | struct voice_wave_t | 298 | struct voice_wave_t |
diff --git a/lib/rbcodec/codecs/libspc/spc_dsp.c b/lib/rbcodec/codecs/libspc/spc_dsp.c index 58bf681d2e..0df0ab04f7 100644 --- a/lib/rbcodec/codecs/libspc/spc_dsp.c +++ b/lib/rbcodec/codecs/libspc/spc_dsp.c | |||
@@ -313,21 +313,21 @@ decode_brr_block( struct voice_t* voice, uint8_t const* addr, int16_t* out ) | |||
313 | static void NO_INLINE ICODE_ATTR_SPC | 313 | static void NO_INLINE ICODE_ATTR_SPC |
314 | brr_decode_cache( struct Spc_Dsp* this, struct src_dir const* sd, | 314 | brr_decode_cache( struct Spc_Dsp* this, struct src_dir const* sd, |
315 | unsigned start_addr, struct voice_t* voice, | 315 | unsigned start_addr, struct voice_t* voice, |
316 | struct raw_voice_t const* raw_voice ) | 316 | unsigned waveform, bool initial_point ) |
317 | { | 317 | { |
318 | /* a little extra for samples that go past end */ | 318 | /* a little extra for samples that go past end */ |
319 | static int16_t BRRcache [BRR_CACHE_SIZE] CACHEALIGN_ATTR; | 319 | static int16_t BRRcache [BRR_CACHE_SIZE] CACHEALIGN_ATTR; |
320 | 320 | ||
321 | DEBUGF( "decode at %08x (wave #%d)\n", | 321 | DEBUGF( "decode at %08x (wave #%d)\n", start_addr, waveform ); |
322 | start_addr, raw_voice->waveform ); | ||
323 | 322 | ||
324 | struct cache_entry_t* const wave_entry = | 323 | struct cache_entry_t* const wave_entry = &this->wave_entry [waveform]; |
325 | &this->wave_entry [raw_voice->waveform]; | ||
326 | 324 | ||
327 | wave_entry->start_addr = start_addr; | 325 | wave_entry->start_addr = start_addr; |
328 | 326 | ||
329 | uint8_t const* const loop_ptr = | 327 | unsigned loop_addr = letoh16( sd [waveform].loop ); |
330 | ram.ram + letoh16( sd [raw_voice->waveform].loop ); | 328 | uint8_t const* const loop_ptr = ram.ram + loop_addr; |
329 | |||
330 | DEBUGF( "loop addr at %08x\n", (unsigned)loop_addr ); | ||
331 | 331 | ||
332 | int16_t* loop_start = NULL; | 332 | int16_t* loop_start = NULL; |
333 | 333 | ||
@@ -337,8 +337,13 @@ brr_decode_cache( struct Spc_Dsp* this, struct src_dir const* sd, | |||
337 | wave_entry->samples = out; | 337 | wave_entry->samples = out; |
338 | 338 | ||
339 | /* BRR filter uses previous samples */ | 339 | /* BRR filter uses previous samples */ |
340 | out [BRR_BLOCK_SIZE + 1] = 0; | 340 | if ( initial_point ) |
341 | out [BRR_BLOCK_SIZE + 2] = 0; | 341 | { |
342 | /* initialize filters */ | ||
343 | out [BRR_BLOCK_SIZE + 1] = 0; | ||
344 | out [BRR_BLOCK_SIZE + 2] = 0; | ||
345 | } | ||
346 | |||
342 | *out++ = 0; | 347 | *out++ = 0; |
343 | 348 | ||
344 | unsigned block_header; | 349 | unsigned block_header; |
@@ -348,8 +353,8 @@ brr_decode_cache( struct Spc_Dsp* this, struct src_dir const* sd, | |||
348 | if ( addr == loop_ptr ) | 353 | if ( addr == loop_ptr ) |
349 | { | 354 | { |
350 | loop_start = out; | 355 | loop_start = out; |
351 | DEBUGF( "loop at %08lx (wave #%d)\n", | 356 | DEBUGF( "loop found at %08lx (wave #%d)\n", |
352 | (unsigned long)(addr - RAM), raw_voice->waveform ); | 357 | (unsigned long)(addr - RAM), waveform ); |
353 | } | 358 | } |
354 | 359 | ||
355 | /* output position - preincrement */ | 360 | /* output position - preincrement */ |
@@ -389,53 +394,79 @@ brr_decode_cache( struct Spc_Dsp* this, struct src_dir const* sd, | |||
389 | else | 394 | else |
390 | { | 395 | { |
391 | DEBUGF( "loop point outside initial wave\n" ); | 396 | DEBUGF( "loop point outside initial wave\n" ); |
397 | /* Plan filter init for later decoding at loop point */ | ||
398 | int16_t* next = BRRcache + loop_addr * 2; | ||
399 | next [BRR_BLOCK_SIZE + 1] = out [0]; | ||
400 | next [BRR_BLOCK_SIZE + 2] = out [1]; | ||
392 | } | 401 | } |
393 | } | 402 | } |
394 | 403 | ||
395 | DEBUGF( "end at %08lx (wave #%d)\n", | 404 | DEBUGF( "end at %08lx (wave #%d)\n", |
396 | (unsigned long)(addr - RAM), raw_voice->waveform ); | 405 | (unsigned long)(addr - RAM), waveform ); |
397 | 406 | ||
398 | /* add to cache */ | 407 | /* add to cache */ |
399 | this->wave_entry_old [this->oldsize++] = *wave_entry; | 408 | this->wave_entry_old [this->oldsize++] = *wave_entry; |
400 | } | 409 | } |
401 | 410 | ||
402 | static inline void | 411 | /* see if in cache */ |
403 | brr_key_on( struct Spc_Dsp* this, struct src_dir const* sd, | 412 | static inline bool |
404 | struct voice_t* voice, struct raw_voice_t const* raw_voice ) | 413 | brr_probe_cache( struct Spc_Dsp* this, unsigned start_addr, |
414 | struct cache_entry_t* wave_entry ) | ||
405 | { | 415 | { |
406 | unsigned start_addr = letoh16( sd [raw_voice->waveform].start ); | 416 | if ( wave_entry->start_addr == start_addr ) |
407 | struct cache_entry_t* const wave_entry = | 417 | return true; |
408 | &this->wave_entry [raw_voice->waveform]; | ||
409 | 418 | ||
410 | /* predecode BRR if not already */ | 419 | for ( int i = 0; i < this->oldsize; i++ ) |
411 | if ( wave_entry->start_addr != start_addr ) | ||
412 | { | 420 | { |
413 | /* see if in cache */ | 421 | struct cache_entry_t* e = &this->wave_entry_old [i]; |
414 | for ( int i = 0; i < this->oldsize; i++ ) | ||
415 | { | ||
416 | struct cache_entry_t* e = &this->wave_entry_old [i]; | ||
417 | 422 | ||
418 | if ( e->start_addr == start_addr ) | 423 | if ( e->start_addr == start_addr ) |
419 | { | 424 | { |
420 | DEBUGF( "found in wave_entry_old (oldsize=%d)\n", | 425 | #if 0 /* do NOT want to see all the key down stuff for cached waves */ |
421 | this->oldsize ); | 426 | DEBUGF( "found in wave_entry_old (oldsize=%d)\n", |
422 | *wave_entry = *e; | 427 | this->oldsize ); |
423 | goto wave_in_cache; /* Wave in cache */ | 428 | #endif |
424 | } | 429 | *wave_entry = *e; |
430 | return true; /* Wave in cache */ | ||
425 | } | 431 | } |
432 | } | ||
433 | |||
434 | return false; | ||
435 | } | ||
426 | 436 | ||
437 | static NO_INLINE ICODE_ATTR_SPC void | ||
438 | brr_key_on( struct Spc_Dsp* this, struct src_dir const* sd, | ||
439 | struct voice_t* voice, struct raw_voice_t const* raw_voice, | ||
440 | unsigned start_addr ) | ||
441 | { | ||
442 | bool initial_point = false; | ||
443 | unsigned waveform = raw_voice->waveform; | ||
444 | |||
445 | if (start_addr == (unsigned)-1) | ||
446 | { | ||
447 | initial_point = true; | ||
448 | start_addr = letoh16( sd [waveform].start ); | ||
449 | } | ||
450 | |||
451 | struct cache_entry_t* const wave_entry = &this->wave_entry [waveform]; | ||
452 | |||
453 | /* predecode BRR if not already */ | ||
454 | if ( !brr_probe_cache( this, start_addr, wave_entry ) ) | ||
455 | { | ||
427 | /* actually decode it */ | 456 | /* actually decode it */ |
428 | brr_decode_cache( this, sd, start_addr, voice, raw_voice ); | 457 | brr_decode_cache( this, sd, start_addr, voice, waveform, |
458 | initial_point ); | ||
429 | } | 459 | } |
430 | 460 | ||
431 | wave_in_cache: | 461 | voice->wave.position = 3 * 0x1000 - 1; /* 0x2fff */ |
432 | voice->wave.position = 3 * 0x1000 - 1; /* 0x2fff */ | 462 | voice->wave.samples = wave_entry->samples; |
433 | voice->wave.samples = wave_entry->samples; | 463 | voice->wave.end = wave_entry->end; |
434 | voice->wave.end = wave_entry->end; | 464 | voice->wave.loop = wave_entry->loop; |
435 | voice->wave.loop = wave_entry->loop; | 465 | voice->wave.loop_addr = letoh16( sd [waveform].loop ); |
436 | } | 466 | } |
437 | 467 | ||
438 | static inline int brr_decode( struct src_dir const* sd, struct voice_t* voice, | 468 | static inline int brr_decode( struct Spc_Dsp* this, struct src_dir const* sd, |
469 | struct voice_t* voice, | ||
439 | struct raw_voice_t const* raw_voice ) | 470 | struct raw_voice_t const* raw_voice ) |
440 | { | 471 | { |
441 | if ( voice->wave.position < voice->wave.end ) | 472 | if ( voice->wave.position < voice->wave.end ) |
@@ -444,7 +475,13 @@ static inline int brr_decode( struct src_dir const* sd, struct voice_t* voice, | |||
444 | long loop_len = voice->wave.loop << 12; | 475 | long loop_len = voice->wave.loop << 12; |
445 | 476 | ||
446 | if ( !loop_len ) | 477 | if ( !loop_len ) |
447 | return 2; | 478 | { |
479 | if ( !(voice->wave.block_header & 2 ) ) | ||
480 | return 2; | ||
481 | |||
482 | /* "Loop" is outside initial waveform */ | ||
483 | brr_key_on( this, sd, voice, raw_voice, voice->wave.loop_addr ); | ||
484 | } | ||
448 | 485 | ||
449 | voice->wave.position -= loop_len; | 486 | voice->wave.position -= loop_len; |
450 | return 1; | 487 | return 1; |
@@ -456,7 +493,8 @@ static inline int brr_decode( struct src_dir const* sd, struct voice_t* voice, | |||
456 | 493 | ||
457 | static inline void | 494 | static inline void |
458 | brr_key_on( struct Spc_Dsp* this, struct src_dir const* sd, | 495 | brr_key_on( struct Spc_Dsp* this, struct src_dir const* sd, |
459 | struct voice_t* voice, struct raw_voice_t const* raw_voice ) | 496 | struct voice_t* voice, struct raw_voice_t const* raw_voice, |
497 | unsigned start_addr ) | ||
460 | { | 498 | { |
461 | voice->wave.addr = ram.ram + letoh16( sd [raw_voice->waveform].start ); | 499 | voice->wave.addr = ram.ram + letoh16( sd [raw_voice->waveform].start ); |
462 | /* BRR filter uses previous samples */ | 500 | /* BRR filter uses previous samples */ |
@@ -465,10 +503,11 @@ brr_key_on( struct Spc_Dsp* this, struct src_dir const* sd, | |||
465 | /* force decode on next brr_decode call */ | 503 | /* force decode on next brr_decode call */ |
466 | voice->wave.position = (BRR_BLOCK_SIZE + 3) * 0x1000 - 1; /* 0x12fff */ | 504 | voice->wave.position = (BRR_BLOCK_SIZE + 3) * 0x1000 - 1; /* 0x12fff */ |
467 | voice->wave.block_header = 0; /* "previous" BRR header */ | 505 | voice->wave.block_header = 0; /* "previous" BRR header */ |
468 | (void)this; | 506 | (void)this; (void)start_addr; |
469 | } | 507 | } |
470 | 508 | ||
471 | static inline int brr_decode( struct src_dir const* sd, struct voice_t* voice, | 509 | static inline int brr_decode( struct Spc_Dsp* this, struct src_dir const* sd, |
510 | struct voice_t* voice, | ||
472 | struct raw_voice_t const* raw_voice ) | 511 | struct raw_voice_t const* raw_voice ) |
473 | { | 512 | { |
474 | #undef RAM | 513 | #undef RAM |
@@ -510,6 +549,7 @@ static inline int brr_decode( struct src_dir const* sd, struct voice_t* voice, | |||
510 | decode_brr_block( voice, addr, &voice->wave.samples [1 + BRR_BLOCK_SIZE] ); | 549 | decode_brr_block( voice, addr, &voice->wave.samples [1 + BRR_BLOCK_SIZE] ); |
511 | 550 | ||
512 | return dec; | 551 | return dec; |
552 | (void)this; | ||
513 | } | 553 | } |
514 | #endif /* SPC_BRRCACHE */ | 554 | #endif /* SPC_BRRCACHE */ |
515 | 555 | ||
@@ -527,7 +567,7 @@ key_on( struct Spc_Dsp* const this, struct voice_t* const voice, | |||
527 | voice->envx = 0; | 567 | voice->envx = 0; |
528 | voice->env_mode = state_attack; | 568 | voice->env_mode = state_attack; |
529 | voice->env_timer = ENV_RATE_INIT; /* TODO: inaccurate? */ | 569 | voice->env_timer = ENV_RATE_INIT; /* TODO: inaccurate? */ |
530 | brr_key_on( this, sd, voice, raw_voice ); | 570 | brr_key_on( this, sd, voice, raw_voice, -1 ); |
531 | } | 571 | } |
532 | } | 572 | } |
533 | 573 | ||
@@ -784,7 +824,7 @@ void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) | |||
784 | 824 | ||
785 | ENTER_TIMER(dsp_gen); | 825 | ENTER_TIMER(dsp_gen); |
786 | 826 | ||
787 | switch ( brr_decode( sd, voice, raw_voice ) ) | 827 | switch ( brr_decode( this, sd, voice, raw_voice ) ) |
788 | { | 828 | { |
789 | case 2: | 829 | case 2: |
790 | /* bit was set, so this clears it */ | 830 | /* bit was set, so this clears it */ |