diff options
| author | Andree Buschmann <AndreeBuschmann@t-online.de> | 2011-08-31 19:19:49 +0000 |
|---|---|---|
| committer | Andree Buschmann <AndreeBuschmann@t-online.de> | 2011-08-31 19:19:49 +0000 |
| commit | 13cbade08a07296d92e7a7d3e20475de0032cba1 (patch) | |
| tree | 731a1a4a99d86632a719ae49e3b3d2a12e764a3a /apps/codecs/libgme/multi_buffer.c | |
| parent | d089e104034fdf5562bea125d2cacf4ee486782a (diff) | |
| download | rockbox-13cbade08a07296d92e7a7d3e20475de0032cba1.zip rockbox-13cbade08a07296d92e7a7d3e20475de0032cba1.tar.gz rockbox-13cbade08a07296d92e7a7d3e20475de0032cba1.tar.bz2 rockbox-13cbade08a07296d92e7a7d3e20475de0032cba1.tar.xz | |
Update libgme to Blargg's Game_Music_Emu 0.6-pre.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30397 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libgme/multi_buffer.c')
| -rw-r--r-- | apps/codecs/libgme/multi_buffer.c | 390 |
1 files changed, 225 insertions, 165 deletions
diff --git a/apps/codecs/libgme/multi_buffer.c b/apps/codecs/libgme/multi_buffer.c index 26cb8cd..554778c 100644 --- a/apps/codecs/libgme/multi_buffer.c +++ b/apps/codecs/libgme/multi_buffer.c @@ -1,4 +1,4 @@ -// Blip_Buffer 0.4.1. http://www.slack.net/~ant/ +// Multi_Buffer 0.4.1. http://www.slack.net/~ant/ #include "multi_buffer.h" @@ -15,212 +15,272 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "blargg_source.h" -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -// Stereo_Buffer - -void Buffer_init( struct Stereo_Buffer* this ) -{ - Blip_init( &this->bufs [0] ); - Blip_init( &this->bufs [1] ); - Blip_init( &this->bufs [2] ); - - this->chan.center = &this->bufs [0]; - this->chan.left = &this->bufs [1]; - this->chan.right = &this->bufs [2]; - - this->length_ = 0; - this->sample_rate_ = 0; - this->channels_changed_count_ = 1; - this->samples_per_frame_ = 2; +// Tracked_Blip_Buffer + +int const blip_buffer_extra = 32; // TODO: explain why this value + +void Tracked_init( struct Tracked_Blip_Buffer* this ) +{ + Blip_init( &this->blip ); + this->last_non_silence = 0; } -blargg_err_t Buffer_set_sample_rate( struct Stereo_Buffer* this, long rate, int msec ) +void Tracked_clear( struct Tracked_Blip_Buffer* this ) { - int i; - for ( i = 0; i < buf_count; i++ ) - RETURN_ERR( Blip_set_sample_rate( &this->bufs[i], rate, msec ) ); - - this->sample_rate_ = Blip_sample_rate( &this->bufs [0] ); - this->length_ = Blip_length( &this->bufs [0] ); - return 0; + this->last_non_silence = 0; + Blip_clear( &this->blip ); } -void Buffer_clock_rate( struct Stereo_Buffer* this, long rate ) +void Tracked_end_frame( struct Tracked_Blip_Buffer* this, blip_time_t t ) { - int i; - for ( i = 0; i < buf_count; i++ ) - Blip_set_clock_rate( &this->bufs [i], rate ); + Blip_end_frame( &this->blip, t ); + if ( this->blip.modified ) + { + this->blip.modified = false; + this->last_non_silence = Blip_samples_avail( &this->blip ) + blip_buffer_extra; + } } -void Buffer_bass_freq( struct Stereo_Buffer* this, int bass ) +unsigned Tracked_non_silent( struct Tracked_Blip_Buffer* this ) { - unsigned i; - for ( i = 0; i < buf_count; i++ ) - Blip_bass_freq( &this->bufs [i], bass ); + return this->last_non_silence | unsettled( &this->blip ); } -struct channel_t Buffer_channel( struct Stereo_Buffer* this ) +static inline void remove_( struct Tracked_Blip_Buffer* this, int n ) { - return this->chan; + if ( (this->last_non_silence -= n) < 0 ) + this->last_non_silence = 0; } -void Buffer_clear( struct Stereo_Buffer* this ) +void Tracked_remove_silence( struct Tracked_Blip_Buffer* this, int n ) { - this->stereo_added = 0; - this->was_stereo = false; - int i; - for ( i = 0; i < buf_count; i++ ) - Blip_clear( &this->bufs [i], 1 ); + remove_( this, n ); + Blip_remove_silence( &this->blip, n ); } -void Buffer_end_frame( struct Stereo_Buffer* this, blip_time_t clock_count ) +void Tracked_remove_samples( struct Tracked_Blip_Buffer* this, int n ) +{ + remove_( this, n ); + Blip_remove_samples( &this->blip, n ); +} + +void Tracked_remove_all_samples( struct Tracked_Blip_Buffer* this ) +{ + int avail = Blip_samples_avail( &this->blip ); + if ( !Tracked_non_silent( this ) ) + Tracked_remove_silence( this, avail ); + else + Tracked_remove_samples( this, avail ); +} + +int Tracked_read_samples( struct Tracked_Blip_Buffer* this, blip_sample_t out [], int count ) +{ + count = Blip_read_samples( &this->blip, out, count, false ); + remove_( this, count ); + return count; +} + +// Stereo_Mixer + +// mixers use a single index value to improve performance on register-challenged processors +// offset goes from negative to zero + +void Mixer_init( struct Stereo_Mixer* this ) { - this->stereo_added = 0; - unsigned i; - for ( i = 0; i < buf_count; i++ ) + this->samples_read = 0; +} + +static void mix_mono( struct Stereo_Mixer* this, blip_sample_t out_ [], int count ) +{ + int const bass = this->bufs [2]->blip.bass_shift_; + delta_t const* center = this->bufs [2]->blip.buffer_ + this->samples_read; + int center_sum = this->bufs [2]->blip.reader_accum_; + + typedef blip_sample_t stereo_blip_sample_t [stereo]; + stereo_blip_sample_t* BLARGG_RESTRICT out = (stereo_blip_sample_t*) out_ + count; + int offset = -count; + do { - this->stereo_added |= Blip_clear_modified( &this->bufs [i] ) << i; - Blip_end_frame( &this->bufs [i], clock_count ); + int s = center_sum >> delta_bits; + + center_sum -= center_sum >> bass; + center_sum += center [offset]; + + BLIP_CLAMP( s, s ); + + out [offset] [0] = (blip_sample_t) s; + out [offset] [1] = (blip_sample_t) s; } + while ( ++offset ); + + this->bufs [2]->blip.reader_accum_ = center_sum; } -long Buffer_read_samples( struct Stereo_Buffer* this, blip_sample_t* out, long count ) +static void mix_stereo( struct Stereo_Mixer* this, blip_sample_t out_ [], int count ) { - require( !(count & 1) ); // count must be even - count = (unsigned) count / 2; - - long avail = Blip_samples_avail( &this->bufs [0] ); - if ( count > avail ) - count = avail; - if ( count ) + blip_sample_t* BLARGG_RESTRICT out = out_ + count * stereo; + // do left + center and right + center separately to reduce register load + struct Tracked_Blip_Buffer* const* buf = &this->bufs [2]; + while ( true ) // loop runs twice { - int bufs_used = this->stereo_added | this->was_stereo; - //dprintf( "%X\n", bufs_used ); - if ( bufs_used <= 1 ) - { - Buffer_mix_mono( this, out, count ); - Blip_remove_samples( &this->bufs [0], count ); - Blip_remove_silence( &this->bufs [1], count ); - Blip_remove_silence( &this->bufs [2], count ); - } - else if ( bufs_used & 1 ) - { - Buffer_mix_stereo( this, out, count ); - Blip_remove_samples( &this->bufs [0], count ); - Blip_remove_samples( &this->bufs [1], count ); - Blip_remove_samples( &this->bufs [2], count ); - } - else - { - Buffer_mix_stereo_no_center( this, out, count ); - Blip_remove_silence( &this->bufs [0], count ); - Blip_remove_samples( &this->bufs [1], count ); - Blip_remove_samples( &this->bufs [2], count ); - } - - // to do: this might miss opportunities for optimization - if ( !Blip_samples_avail( &this->bufs [0] ) ) + --buf; + --out; + + int const bass = this->bufs [2]->blip.bass_shift_; + delta_t const* side = (*buf)->blip.buffer_ + this->samples_read; + delta_t const* center = this->bufs [2]->blip.buffer_ + this->samples_read; + + int side_sum = (*buf)->blip.reader_accum_; + int center_sum = this->bufs [2]->blip.reader_accum_; + + int offset = -count; + do { - this->was_stereo = this->stereo_added; - this->stereo_added = 0; + int s = (center_sum + side_sum) >> delta_bits; + + side_sum -= side_sum >> bass; + center_sum -= center_sum >> bass; + + side_sum += side [offset]; + center_sum += center [offset]; + + BLIP_CLAMP( s, s ); + + ++offset; // before write since out is decremented to slightly before end + out [offset * stereo] = (blip_sample_t) s; } + while ( offset ); + + (*buf)->blip.reader_accum_ = side_sum; + + if ( buf != this->bufs ) + continue; + + // only end center once + this->bufs [2]->blip.reader_accum_ = center_sum; + break; } - - return count * 2; } -unsigned Buffer_channels_changed_count( struct Stereo_Buffer* this ) +void Mixer_read_pairs( struct Stereo_Mixer* this, blip_sample_t out [], int count ) { - return this->channels_changed_count_; + // TODO: if caller never marks buffers as modified, uses mono + // except that buffer isn't cleared, so caller can encounter + // subtle problems and not realize the cause. + this->samples_read += count; + if ( Tracked_non_silent( this->bufs [0] ) | Tracked_non_silent( this->bufs [1] ) ) + mix_stereo( this, out, count ); + else + mix_mono( this, out, count ); } -void Buffer_channels_changed( struct Stereo_Buffer* this ) +// Multi_Buffer + +void Buffer_init( struct Multi_Buffer* this ) { - this->channels_changed_count_++; + int const spf = 2; + + Tracked_init( &this->bufs [0] ); + Tracked_init( &this->bufs [1] ); + Tracked_init( &this->bufs [2] ); + + Mixer_init( &this->mixer ); + + this->length_ = 0; + this->sample_rate_ = 0; + this->channels_changed_count_ = 1; + this->channel_types_ = NULL; + this->channel_count_ = 0; + this->samples_per_frame_ = spf; + this->immediate_removal_ = true; + + this->mixer.bufs [2] = &this->bufs [2]; + this->mixer.bufs [0] = &this->bufs [0]; + this->mixer.bufs [1] = &this->bufs [1]; + + this->chan.center = &this->bufs [2].blip; + this->chan.left = &this->bufs [0].blip; + this->chan.right = &this->bufs [1].blip; } -void Buffer_mix_stereo( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) +blargg_err_t Buffer_set_sample_rate( struct Multi_Buffer* this, int rate, int msec ) { - blip_sample_t* BLIP_RESTRICT out = out_; - int const bass = BLIP_READER_BASS( this->bufs [1] ); - BLIP_READER_BEGIN( left, this->bufs [1] ); - BLIP_READER_BEGIN( right, this->bufs [2] ); - BLIP_READER_BEGIN( center, this->bufs [0] ); - - for ( ; count; --count ) - { - int c = BLIP_READER_READ( center ); - blargg_long l = c + BLIP_READER_READ( left ); - blargg_long r = c + BLIP_READER_READ( right ); - if ( (int16_t) l != l ) - l = 0x7FFF - (l >> 24); - - BLIP_READER_NEXT( center, bass ); - if ( (int16_t) r != r ) - r = 0x7FFF - (r >> 24); - - BLIP_READER_NEXT( left, bass ); - BLIP_READER_NEXT( right, bass ); - - out [0] = l; - out [1] = r; - out += 2; - } - - BLIP_READER_END( center, this->bufs [0] ); - BLIP_READER_END( right, this->bufs [2] ); - BLIP_READER_END( left, this->bufs [1] ); + int i; + for ( i = bufs_size; --i >= 0; ) + RETURN_ERR( Blip_set_sample_rate( &this->bufs [i].blip, rate, msec ) ); + + this->sample_rate_ = Blip_sample_rate( &this->bufs [0].blip ); + this->length_ = Blip_length( &this->bufs [0].blip ); + return 0; } -void Buffer_mix_stereo_no_center( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) +void Buffer_clock_rate( struct Multi_Buffer* this, int rate ) { - blip_sample_t* BLIP_RESTRICT out = out_; - int const bass = BLIP_READER_BASS( this->bufs [1] ); - BLIP_READER_BEGIN( left, this->bufs [1] ); - BLIP_READER_BEGIN( right, this->bufs [2] ); - - for ( ; count; --count ) - { - blargg_long l = BLIP_READER_READ( left ); - if ( (int16_t) l != l ) - l = 0x7FFF - (l >> 24); - - blargg_long r = BLIP_READER_READ( right ); - if ( (int16_t) r != r ) - r = 0x7FFF - (r >> 24); - - BLIP_READER_NEXT( left, bass ); - BLIP_READER_NEXT( right, bass ); - - out [0] = l; - out [1] = r; - out += 2; - } - - BLIP_READER_END( right, this->bufs [2] ); - BLIP_READER_END( left, this->bufs [1] ); + int i; + for ( i = bufs_size; --i >= 0; ) + Blip_set_clock_rate( &this->bufs [i].blip, rate ); +} + +void Buffer_bass_freq( struct Multi_Buffer* this, int bass ) +{ + int i; + for ( i = bufs_size; --i >= 0; ) + Blip_bass_freq( &this->bufs [i].blip, bass ); +} + +blargg_err_t Buffer_set_channel_count( struct Multi_Buffer* this, int n, int const* types ) +{ + this->channel_count_ = n; + this->channel_types_ = types; + return 0; } -void Buffer_mix_mono( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) +struct channel_t Buffer_channel( struct Multi_Buffer* this, int i ) { - blip_sample_t* BLIP_RESTRICT out = out_; - int const bass = BLIP_READER_BASS( this->bufs [0] ); - BLIP_READER_BEGIN( center, this->bufs [0] ); - - for ( ; count; --count ) + (void) i; + return this->chan; +} + +void Buffer_clear( struct Multi_Buffer* this ) +{ + int i; + this->mixer.samples_read = 0; + for ( i = bufs_size; --i >= 0; ) + Tracked_clear( &this->bufs [i] ); +} + +void Buffer_end_frame( struct Multi_Buffer* this, blip_time_t clock_count ) +{ + int i; + for ( i = bufs_size; --i >= 0; ) + Tracked_end_frame( &this->bufs [i], clock_count ); +} + +int Buffer_read_samples( struct Multi_Buffer* this, blip_sample_t out [], int out_size ) +{ + require( (out_size & 1) == 0 ); // must read an even number of samples + out_size = min( out_size, Buffer_samples_avail( this ) ); + + int pair_count = (int) (out_size >> 1); + if ( pair_count ) { - blargg_long s = BLIP_READER_READ( center ); - if ( (int16_t) s != s ) - s = 0x7FFF - (s >> 24); - - BLIP_READER_NEXT( center, bass ); - out [0] = s; - out [1] = s; - out += 2; + Mixer_read_pairs( &this->mixer, out, pair_count ); + + if ( Buffer_samples_avail( this ) <= 0 || this->immediate_removal_ ) + { + int i; + for ( i = bufs_size; --i >= 0; ) + { + buf_t* b = &this->bufs [i]; + // TODO: might miss non-silence settling since it checks END of last read + if ( !Tracked_non_silent( b ) ) + Tracked_remove_silence( b, this->mixer.samples_read ); + else + Tracked_remove_samples( b, this->mixer.samples_read ); + } + this->mixer.samples_read = 0; + } } - - BLIP_READER_END( center, this->bufs [0] ); + + return out_size; } |