1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Michael Sevakis 2013-05-21 04:09:44 -04:00
parent 00e55d0451
commit 71b9685dcd
2 changed files with 87 additions and 46 deletions

View file

@ -292,6 +292,7 @@ struct voice_wave_t
int loop; /* length of looping area */ int loop; /* length of looping area */
unsigned block_header; /* header byte from current BRR block */ unsigned block_header; /* header byte from current BRR block */
uint8_t const* addr; /* BRR waveform address in RAM */ uint8_t const* addr; /* BRR waveform address in RAM */
unsigned loop_addr; /* Loop address in RAM */
}; };
#else /* !SPC_BRRCACHE */ #else /* !SPC_BRRCACHE */
struct voice_wave_t struct voice_wave_t

View file

@ -313,21 +313,21 @@ decode_brr_block( struct voice_t* voice, uint8_t const* addr, int16_t* out )
static void NO_INLINE ICODE_ATTR_SPC static void NO_INLINE ICODE_ATTR_SPC
brr_decode_cache( struct Spc_Dsp* this, struct src_dir const* sd, brr_decode_cache( struct Spc_Dsp* this, struct src_dir const* sd,
unsigned start_addr, struct voice_t* voice, unsigned start_addr, struct voice_t* voice,
struct raw_voice_t const* raw_voice ) unsigned waveform, bool initial_point )
{ {
/* a little extra for samples that go past end */ /* a little extra for samples that go past end */
static int16_t BRRcache [BRR_CACHE_SIZE] CACHEALIGN_ATTR; static int16_t BRRcache [BRR_CACHE_SIZE] CACHEALIGN_ATTR;
DEBUGF( "decode at %08x (wave #%d)\n", DEBUGF( "decode at %08x (wave #%d)\n", start_addr, waveform );
start_addr, raw_voice->waveform );
struct cache_entry_t* const wave_entry = struct cache_entry_t* const wave_entry = &this->wave_entry [waveform];
&this->wave_entry [raw_voice->waveform];
wave_entry->start_addr = start_addr; wave_entry->start_addr = start_addr;
uint8_t const* const loop_ptr = unsigned loop_addr = letoh16( sd [waveform].loop );
ram.ram + letoh16( sd [raw_voice->waveform].loop ); uint8_t const* const loop_ptr = ram.ram + loop_addr;
DEBUGF( "loop addr at %08x\n", (unsigned)loop_addr );
int16_t* loop_start = NULL; int16_t* loop_start = NULL;
@ -337,8 +337,13 @@ brr_decode_cache( struct Spc_Dsp* this, struct src_dir const* sd,
wave_entry->samples = out; wave_entry->samples = out;
/* BRR filter uses previous samples */ /* BRR filter uses previous samples */
out [BRR_BLOCK_SIZE + 1] = 0; if ( initial_point )
out [BRR_BLOCK_SIZE + 2] = 0; {
/* initialize filters */
out [BRR_BLOCK_SIZE + 1] = 0;
out [BRR_BLOCK_SIZE + 2] = 0;
}
*out++ = 0; *out++ = 0;
unsigned block_header; unsigned block_header;
@ -348,8 +353,8 @@ brr_decode_cache( struct Spc_Dsp* this, struct src_dir const* sd,
if ( addr == loop_ptr ) if ( addr == loop_ptr )
{ {
loop_start = out; loop_start = out;
DEBUGF( "loop at %08lx (wave #%d)\n", DEBUGF( "loop found at %08lx (wave #%d)\n",
(unsigned long)(addr - RAM), raw_voice->waveform ); (unsigned long)(addr - RAM), waveform );
} }
/* output position - preincrement */ /* output position - preincrement */
@ -389,53 +394,79 @@ brr_decode_cache( struct Spc_Dsp* this, struct src_dir const* sd,
else else
{ {
DEBUGF( "loop point outside initial wave\n" ); DEBUGF( "loop point outside initial wave\n" );
/* Plan filter init for later decoding at loop point */
int16_t* next = BRRcache + loop_addr * 2;
next [BRR_BLOCK_SIZE + 1] = out [0];
next [BRR_BLOCK_SIZE + 2] = out [1];
} }
} }
DEBUGF( "end at %08lx (wave #%d)\n", DEBUGF( "end at %08lx (wave #%d)\n",
(unsigned long)(addr - RAM), raw_voice->waveform ); (unsigned long)(addr - RAM), waveform );
/* add to cache */ /* add to cache */
this->wave_entry_old [this->oldsize++] = *wave_entry; this->wave_entry_old [this->oldsize++] = *wave_entry;
} }
static inline void /* see if in cache */
brr_key_on( struct Spc_Dsp* this, struct src_dir const* sd, static inline bool
struct voice_t* voice, struct raw_voice_t const* raw_voice ) brr_probe_cache( struct Spc_Dsp* this, unsigned start_addr,
struct cache_entry_t* wave_entry )
{ {
unsigned start_addr = letoh16( sd [raw_voice->waveform].start ); if ( wave_entry->start_addr == start_addr )
struct cache_entry_t* const wave_entry = return true;
&this->wave_entry [raw_voice->waveform];
/* predecode BRR if not already */ for ( int i = 0; i < this->oldsize; i++ )
if ( wave_entry->start_addr != start_addr )
{ {
/* see if in cache */ struct cache_entry_t* e = &this->wave_entry_old [i];
for ( int i = 0; i < this->oldsize; i++ )
if ( e->start_addr == start_addr )
{ {
struct cache_entry_t* e = &this->wave_entry_old [i]; #if 0 /* do NOT want to see all the key down stuff for cached waves */
DEBUGF( "found in wave_entry_old (oldsize=%d)\n",
if ( e->start_addr == start_addr ) this->oldsize );
{ #endif
DEBUGF( "found in wave_entry_old (oldsize=%d)\n", *wave_entry = *e;
this->oldsize ); return true; /* Wave in cache */
*wave_entry = *e;
goto wave_in_cache; /* Wave in cache */
}
} }
/* actually decode it */
brr_decode_cache( this, sd, start_addr, voice, raw_voice );
} }
wave_in_cache: return false;
voice->wave.position = 3 * 0x1000 - 1; /* 0x2fff */
voice->wave.samples = wave_entry->samples;
voice->wave.end = wave_entry->end;
voice->wave.loop = wave_entry->loop;
} }
static inline int brr_decode( struct src_dir const* sd, struct voice_t* voice, static NO_INLINE ICODE_ATTR_SPC void
brr_key_on( struct Spc_Dsp* this, struct src_dir const* sd,
struct voice_t* voice, struct raw_voice_t const* raw_voice,
unsigned start_addr )
{
bool initial_point = false;
unsigned waveform = raw_voice->waveform;
if (start_addr == (unsigned)-1)
{
initial_point = true;
start_addr = letoh16( sd [waveform].start );
}
struct cache_entry_t* const wave_entry = &this->wave_entry [waveform];
/* predecode BRR if not already */
if ( !brr_probe_cache( this, start_addr, wave_entry ) )
{
/* actually decode it */
brr_decode_cache( this, sd, start_addr, voice, waveform,
initial_point );
}
voice->wave.position = 3 * 0x1000 - 1; /* 0x2fff */
voice->wave.samples = wave_entry->samples;
voice->wave.end = wave_entry->end;
voice->wave.loop = wave_entry->loop;
voice->wave.loop_addr = letoh16( sd [waveform].loop );
}
static inline int brr_decode( struct Spc_Dsp* this, struct src_dir const* sd,
struct voice_t* voice,
struct raw_voice_t const* raw_voice ) struct raw_voice_t const* raw_voice )
{ {
if ( voice->wave.position < voice->wave.end ) 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,
long loop_len = voice->wave.loop << 12; long loop_len = voice->wave.loop << 12;
if ( !loop_len ) if ( !loop_len )
return 2; {
if ( !(voice->wave.block_header & 2 ) )
return 2;
/* "Loop" is outside initial waveform */
brr_key_on( this, sd, voice, raw_voice, voice->wave.loop_addr );
}
voice->wave.position -= loop_len; voice->wave.position -= loop_len;
return 1; return 1;
@ -456,7 +493,8 @@ static inline int brr_decode( struct src_dir const* sd, struct voice_t* voice,
static inline void static inline void
brr_key_on( struct Spc_Dsp* this, struct src_dir const* sd, brr_key_on( struct Spc_Dsp* this, struct src_dir const* sd,
struct voice_t* voice, struct raw_voice_t const* raw_voice ) struct voice_t* voice, struct raw_voice_t const* raw_voice,
unsigned start_addr )
{ {
voice->wave.addr = ram.ram + letoh16( sd [raw_voice->waveform].start ); voice->wave.addr = ram.ram + letoh16( sd [raw_voice->waveform].start );
/* BRR filter uses previous samples */ /* BRR filter uses previous samples */
@ -465,10 +503,11 @@ brr_key_on( struct Spc_Dsp* this, struct src_dir const* sd,
/* force decode on next brr_decode call */ /* force decode on next brr_decode call */
voice->wave.position = (BRR_BLOCK_SIZE + 3) * 0x1000 - 1; /* 0x12fff */ voice->wave.position = (BRR_BLOCK_SIZE + 3) * 0x1000 - 1; /* 0x12fff */
voice->wave.block_header = 0; /* "previous" BRR header */ voice->wave.block_header = 0; /* "previous" BRR header */
(void)this; (void)this; (void)start_addr;
} }
static inline int brr_decode( struct src_dir const* sd, struct voice_t* voice, static inline int brr_decode( struct Spc_Dsp* this, struct src_dir const* sd,
struct voice_t* voice,
struct raw_voice_t const* raw_voice ) struct raw_voice_t const* raw_voice )
{ {
#undef RAM #undef RAM
@ -510,6 +549,7 @@ static inline int brr_decode( struct src_dir const* sd, struct voice_t* voice,
decode_brr_block( voice, addr, &voice->wave.samples [1 + BRR_BLOCK_SIZE] ); decode_brr_block( voice, addr, &voice->wave.samples [1 + BRR_BLOCK_SIZE] );
return dec; return dec;
(void)this;
} }
#endif /* SPC_BRRCACHE */ #endif /* SPC_BRRCACHE */
@ -527,7 +567,7 @@ key_on( struct Spc_Dsp* const this, struct voice_t* const voice,
voice->envx = 0; voice->envx = 0;
voice->env_mode = state_attack; voice->env_mode = state_attack;
voice->env_timer = ENV_RATE_INIT; /* TODO: inaccurate? */ voice->env_timer = ENV_RATE_INIT; /* TODO: inaccurate? */
brr_key_on( this, sd, voice, raw_voice ); brr_key_on( this, sd, voice, raw_voice, -1 );
} }
} }
@ -784,7 +824,7 @@ void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf )
ENTER_TIMER(dsp_gen); ENTER_TIMER(dsp_gen);
switch ( brr_decode( sd, voice, raw_voice ) ) switch ( brr_decode( this, sd, voice, raw_voice ) )
{ {
case 2: case 2:
/* bit was set, so this clears it */ /* bit was set, so this clears it */