forked from len0rd/rockbox
Submit a patch to the VGM codec by Mauricio Gama which saves some more RAM through changes of the buffer configuration and an update of the resampler code. Additionally enable VGM for low memory targets and update the manual.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30327 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
4070f4f17b
commit
4d01ace73f
6 changed files with 228 additions and 343 deletions
|
@ -37,8 +37,8 @@ gbs.c
|
|||
hes.c
|
||||
nsf.c
|
||||
sgc.c
|
||||
#if MEMORYSIZE > 2
|
||||
vgm.c
|
||||
#if MEMORYSIZE > 2
|
||||
kss.c
|
||||
#endif
|
||||
|
||||
|
|
|
@ -25,294 +25,194 @@ enum { shift = 14 };
|
|||
int const unit = 1 << shift;
|
||||
|
||||
blargg_err_t Resampler_setup( struct Resampler* this, int fm_rate, int fm_gain, int rate, int gain )
|
||||
{
|
||||
this->gain_ = (int)( ((1LL << gain_bits) * fm_gain * gain) / FP_ONE_GAIN );
|
||||
this->step = (int)( ((1LL << shift) * fm_rate) / rate + 1);
|
||||
this->rate_ = this->step;
|
||||
return 0;
|
||||
}
|
||||
{
|
||||
this->gain_ = (int)( ((1LL << gain_bits) * fm_gain * gain) / FP_ONE_GAIN );
|
||||
this->step = (int)( ((1LL << shift) * fm_rate) / rate + 1);
|
||||
this->rate_ = this->step;
|
||||
return 0;
|
||||
}
|
||||
|
||||
blargg_err_t Resampler_reset( struct Resampler* this, int pairs )
|
||||
{
|
||||
// expand allocations a bit
|
||||
Resampler_resize( this, pairs );
|
||||
this->resampler_size = this->oversamples_per_frame + (this->oversamples_per_frame >> 2);
|
||||
// expand allocations a bit
|
||||
this->sample_buffer_size = (pairs + (pairs >> 2)) * 2;
|
||||
Resampler_resize( this, pairs );
|
||||
this->resampler_size = this->oversamples_per_frame + (this->oversamples_per_frame >> 2);
|
||||
|
||||
this->buffer_size = this->resampler_size;
|
||||
this->pos = 0;
|
||||
this->write_pos = 0;
|
||||
return 0;
|
||||
this->buffer_size = this->resampler_size;
|
||||
this->pos = 0;
|
||||
this->write_pos = 0;
|
||||
|
||||
Resampler_clear( this );
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Resampler_resize( struct Resampler* this, int pairs )
|
||||
{
|
||||
int new_sample_buf_size = pairs * 2;
|
||||
if ( this->sample_buf_size != new_sample_buf_size )
|
||||
{
|
||||
this->sample_buf_size = new_sample_buf_size;
|
||||
this->oversamples_per_frame = (int) ((pairs * this->rate_ * 2LL) / unit) + 2;
|
||||
Resampler_clear( this );
|
||||
}
|
||||
int new_sample_buf_size = pairs * 2;
|
||||
if ( this->sample_buf_size != new_sample_buf_size )
|
||||
{
|
||||
if ( new_sample_buf_size > this->sample_buffer_size )
|
||||
{
|
||||
check(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this->sample_buf_size = new_sample_buf_size;
|
||||
this->oversamples_per_frame = (int) ((pairs * this->rate_ * 2LL) / unit) + 2;
|
||||
Resampler_clear( this );
|
||||
}
|
||||
}
|
||||
|
||||
static void mix_mono( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out_ )
|
||||
void mix_samples( struct Resampler* this, struct Blip_Buffer* blip_buf, sample_t out_ [] )
|
||||
{
|
||||
int const bass = BLIP_READER_BASS( stereo_buf->bufs [0] );
|
||||
BLIP_READER_BEGIN( sn, stereo_buf->bufs [0] );
|
||||
int const bass = BLIP_READER_BASS( *blip_buf );
|
||||
BLIP_READER_BEGIN( sn, *blip_buf );
|
||||
|
||||
int count = this->sample_buf_size >> 1;
|
||||
BLIP_READER_ADJ_( sn, count );
|
||||
int count = this->sample_buf_size >> 1;
|
||||
BLIP_READER_ADJ_( sn, count );
|
||||
|
||||
typedef dsample_t stereo_dsample_t [2];
|
||||
stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count;
|
||||
stereo_dsample_t const* BLARGG_RESTRICT in =
|
||||
(stereo_dsample_t const*) this->sample_buf + count;
|
||||
int offset = -count;
|
||||
int const gain = this->gain_;
|
||||
do
|
||||
{
|
||||
int s = BLIP_READER_READ_RAW( sn ) >> (blip_sample_bits - 16);
|
||||
BLIP_READER_NEXT_IDX_( sn, bass, offset );
|
||||
typedef sample_t stereo_dsample_t [2];
|
||||
stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count;
|
||||
stereo_dsample_t const* BLARGG_RESTRICT in =
|
||||
(stereo_dsample_t const*) this->sample_buf + count;
|
||||
int offset = -count;
|
||||
int const gain = this->gain_;
|
||||
do
|
||||
{
|
||||
int s = BLIP_READER_READ_RAW( sn ) >> (blip_sample_bits - 16);
|
||||
BLIP_READER_NEXT_IDX_( sn, bass, offset );
|
||||
|
||||
int l = (in [offset] [0] * gain >> gain_bits) + s;
|
||||
int r = (in [offset] [1] * gain >> gain_bits) + s;
|
||||
int l = (in [offset] [0] * gain >> gain_bits) + s;
|
||||
int r = (in [offset] [1] * gain >> gain_bits) + s;
|
||||
|
||||
BLIP_CLAMP( l, l );
|
||||
out [offset] [0] = (blip_sample_t) l;
|
||||
BLIP_CLAMP( l, l );
|
||||
out [offset] [0] = (blip_sample_t) l;
|
||||
|
||||
BLIP_CLAMP( r, r );
|
||||
out [offset] [1] = (blip_sample_t) r;
|
||||
}
|
||||
while ( ++offset );
|
||||
BLIP_CLAMP( r, r );
|
||||
out [offset] [1] = (blip_sample_t) r;
|
||||
}
|
||||
while ( ++offset );
|
||||
|
||||
BLIP_READER_END( sn, stereo_buf->bufs [0] );
|
||||
BLIP_READER_END( sn, *blip_buf );
|
||||
}
|
||||
|
||||
static void mix_stereo( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out_ )
|
||||
sample_t const* resample_( struct Resampler* this, sample_t** out_,
|
||||
sample_t const* out_end, sample_t const in [], int in_size )
|
||||
{
|
||||
int const bass = BLIP_READER_BASS( stereo_buf->bufs [0] );
|
||||
BLIP_READER_BEGIN( snc, stereo_buf->bufs [0] );
|
||||
BLIP_READER_BEGIN( snl, stereo_buf->bufs [1] );
|
||||
BLIP_READER_BEGIN( snr, stereo_buf->bufs [2] );
|
||||
in_size -= write_offset;
|
||||
if ( in_size > 0 )
|
||||
{
|
||||
sample_t* BLARGG_RESTRICT out = *out_;
|
||||
sample_t const* const in_end = in + in_size;
|
||||
|
||||
int count = this->sample_buf_size >> 1;
|
||||
BLIP_READER_ADJ_( snc, count );
|
||||
BLIP_READER_ADJ_( snl, count );
|
||||
BLIP_READER_ADJ_( snr, count );
|
||||
int const step = this->step;
|
||||
int pos = this->pos;
|
||||
|
||||
typedef dsample_t stereo_dsample_t [2];
|
||||
stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count;
|
||||
stereo_dsample_t const* BLARGG_RESTRICT in =
|
||||
(stereo_dsample_t const*) this->sample_buf + count;
|
||||
int offset = -count;
|
||||
int const gain = this->gain_;
|
||||
do
|
||||
{
|
||||
int sc = BLIP_READER_READ_RAW( snc ) >> (blip_sample_bits - 16);
|
||||
int sl = BLIP_READER_READ_RAW( snl ) >> (blip_sample_bits - 16);
|
||||
int sr = BLIP_READER_READ_RAW( snr ) >> (blip_sample_bits - 16);
|
||||
BLIP_READER_NEXT_IDX_( snc, bass, offset );
|
||||
BLIP_READER_NEXT_IDX_( snl, bass, offset );
|
||||
BLIP_READER_NEXT_IDX_( snr, bass, offset );
|
||||
// TODO: IIR filter, then linear resample
|
||||
// TODO: detect skipped sample, allowing merging of IIR and resample?
|
||||
|
||||
int l = (in [offset] [0] * gain >> gain_bits) + sl + sc;
|
||||
int r = (in [offset] [1] * gain >> gain_bits) + sr + sc;
|
||||
do
|
||||
{
|
||||
#define INTERP( i, out )\
|
||||
out = (in [0 + i] * (unit - pos) + ((in [2 + i] + in [4 + i] + in [6 + i]) << shift) +\
|
||||
in [8 + i] * pos) >> (shift + 2);
|
||||
|
||||
BLIP_CLAMP( l, l );
|
||||
out [offset] [0] = (blip_sample_t) l;
|
||||
int out_0;
|
||||
INTERP( 0, out_0 )
|
||||
INTERP( 1, out [0] = out_0; out [1] )
|
||||
out += stereo;
|
||||
|
||||
BLIP_CLAMP( r, r );
|
||||
out [offset] [1] = (blip_sample_t) r;
|
||||
}
|
||||
while ( ++offset );
|
||||
pos += step;
|
||||
in += ((unsigned) pos >> shift) * stereo;
|
||||
pos &= unit - 1;
|
||||
}
|
||||
while ( in < in_end && out < out_end );
|
||||
|
||||
BLIP_READER_END( snc, stereo_buf->bufs [0] );
|
||||
BLIP_READER_END( snl, stereo_buf->bufs [1] );
|
||||
BLIP_READER_END( snr, stereo_buf->bufs [2] );
|
||||
this->pos = pos;
|
||||
*out_ = out;
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
static void mix_stereo_no_center( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out_ )
|
||||
inline int resample_wrapper( struct Resampler* this, sample_t out [], int* out_size,
|
||||
sample_t const in [], int in_size )
|
||||
{
|
||||
int const bass = BLIP_READER_BASS( stereo_buf->bufs [0] );
|
||||
BLIP_READER_BEGIN( snl, stereo_buf->bufs [1] );
|
||||
BLIP_READER_BEGIN( snr, stereo_buf->bufs [2] );
|
||||
assert( Resampler_rate( this ) );
|
||||
|
||||
int count = this->sample_buf_size >> 1;
|
||||
BLIP_READER_ADJ_( snl, count );
|
||||
BLIP_READER_ADJ_( snr, count );
|
||||
sample_t* out_ = out;
|
||||
int result = resample_( this, &out_, out + *out_size, in, in_size ) - in;
|
||||
assert( out_ <= out + *out_size );
|
||||
assert( result <= in_size );
|
||||
|
||||
typedef dsample_t stereo_dsample_t [2];
|
||||
stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count;
|
||||
stereo_dsample_t const* BLARGG_RESTRICT in =
|
||||
(stereo_dsample_t const*) this->sample_buf + count;
|
||||
int offset = -count;
|
||||
int const gain = this->gain_;
|
||||
do
|
||||
{
|
||||
int sl = BLIP_READER_READ_RAW( snl ) >> (blip_sample_bits - 16);
|
||||
int sr = BLIP_READER_READ_RAW( snr ) >> (blip_sample_bits - 16);
|
||||
BLIP_READER_NEXT_IDX_( snl, bass, offset );
|
||||
BLIP_READER_NEXT_IDX_( snr, bass, offset );
|
||||
|
||||
int l = (in [offset] [0] * gain >> gain_bits) + sl;
|
||||
int r = (in [offset] [1] * gain >> gain_bits) + sr;
|
||||
|
||||
BLIP_CLAMP( l, l );
|
||||
out [offset] [0] = (blip_sample_t) l;
|
||||
|
||||
BLIP_CLAMP( r, r );
|
||||
out [offset] [1] = (blip_sample_t) r;
|
||||
}
|
||||
while ( ++offset );
|
||||
|
||||
BLIP_READER_END( snl, stereo_buf->bufs [1] );
|
||||
BLIP_READER_END( snr, stereo_buf->bufs [2] );
|
||||
*out_size = out_ - out;
|
||||
return result;
|
||||
}
|
||||
|
||||
static dsample_t const* resample_( struct Resampler* this, dsample_t** out_,
|
||||
dsample_t const* out_end, dsample_t const in [], int in_size )
|
||||
int skip_input( struct Resampler* this, int count )
|
||||
{
|
||||
in_size -= write_offset;
|
||||
if ( in_size > 0 )
|
||||
{
|
||||
dsample_t* BLIP_RESTRICT out = *out_;
|
||||
dsample_t const* const in_end = in + in_size;
|
||||
|
||||
int const step = this->step;
|
||||
int pos = this->pos;
|
||||
|
||||
// TODO: IIR filter, then linear resample
|
||||
// TODO: detect skipped sample, allowing merging of IIR and resample?
|
||||
|
||||
do
|
||||
{
|
||||
#define INTERP( i, out )\
|
||||
out = (in [0 + i] * (unit - pos) + ((in [2 + i] + in [4 + i] + in [6 + i]) << shift) +\
|
||||
in [8 + i] * pos) >> (shift + 2);
|
||||
|
||||
int out_0;
|
||||
INTERP( 0, out_0 )
|
||||
INTERP( 1, out [0] = out_0; out [1] )
|
||||
out += stereo;
|
||||
|
||||
pos += step;
|
||||
in += ((unsigned) pos >> shift) * stereo;
|
||||
pos &= unit - 1;
|
||||
}
|
||||
while ( in < in_end && out < out_end );
|
||||
|
||||
this->pos = pos;
|
||||
*out_ = out;
|
||||
}
|
||||
return in;
|
||||
this->write_pos -= count;
|
||||
if ( this->write_pos < 0 ) // occurs when downsampling
|
||||
{
|
||||
count += this->write_pos;
|
||||
this->write_pos = 0;
|
||||
}
|
||||
memmove( this->buf, &this->buf [count], this->write_pos * sizeof this->buf [0] );
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline int resample_wrapper( struct Resampler* this, dsample_t out [], int* out_size,
|
||||
dsample_t const in [], int in_size )
|
||||
void play_frame_( struct Resampler* this, struct Blip_Buffer* blip_buf, sample_t* out )
|
||||
{
|
||||
assert( Resampler_rate( this ) );
|
||||
int pair_count = this->sample_buf_size >> 1;
|
||||
blip_time_t blip_time = Blip_count_clocks( blip_buf, pair_count );
|
||||
int sample_count = this->oversamples_per_frame - this->write_pos + resampler_extra;
|
||||
|
||||
dsample_t* out_ = out;
|
||||
int result = resample_( this, &out_, out + *out_size, in, in_size ) - in;
|
||||
assert( out_ <= out + *out_size );
|
||||
assert( result <= in_size );
|
||||
int new_count = this->callback( this->callback_data, blip_time, sample_count, &this->buf [this->write_pos] );
|
||||
assert( new_count < this->resampler_size );
|
||||
|
||||
*out_size = out_ - out;
|
||||
return result;
|
||||
Blip_end_frame( blip_buf, blip_time );
|
||||
assert( Blip_samples_avail( blip_buf ) == pair_count );
|
||||
|
||||
this->write_pos += new_count;
|
||||
assert( (unsigned) this->write_pos <= this->buffer_size );
|
||||
|
||||
int count = this->sample_buf_size;
|
||||
if ( count )
|
||||
skip_input( this, resample_wrapper( this, this->sample_buf, &count, this->buf, this->write_pos ) );
|
||||
assert( count == this->sample_buf_size );
|
||||
|
||||
mix_samples( this, blip_buf, out );
|
||||
Blip_remove_samples( blip_buf, pair_count );
|
||||
}
|
||||
|
||||
static int skip_input( struct Resampler* this, int count )
|
||||
void Resampler_play( struct Resampler* this, int count, sample_t* out, struct Blip_Buffer* blip_buf )
|
||||
{
|
||||
this->write_pos -= count;
|
||||
if ( this->write_pos < 0 ) // occurs when downsampling
|
||||
{
|
||||
count += this->write_pos;
|
||||
this->write_pos = 0;
|
||||
}
|
||||
memmove( this->buf, &this->buf [count], this->write_pos * sizeof this->buf [0] );
|
||||
return count;
|
||||
}
|
||||
|
||||
static void play_frame_( struct Resampler* this, struct Stereo_Buffer* stereo_buf, dsample_t* out )
|
||||
{
|
||||
long pair_count = this->sample_buf_size >> 1;
|
||||
blip_time_t blip_time = Blip_count_clocks( &stereo_buf->bufs [0], pair_count );
|
||||
int sample_count = this->oversamples_per_frame - this->write_pos + resampler_extra;
|
||||
|
||||
int new_count = this->callback( this->callback_data, blip_time, sample_count, &this->buf [this->write_pos] );
|
||||
assert( new_count < resampler_size );
|
||||
|
||||
Buffer_end_frame( stereo_buf, blip_time );
|
||||
/* Blip_end_frame( &stereo_buf->bufs [0], blip_time ); */
|
||||
assert( Blip_samples_avail( &stereo_buf->bufs [0] ) == pair_count * 2 );
|
||||
|
||||
this->write_pos += new_count;
|
||||
assert( (unsigned) this->write_pos <= this->buffer_size );
|
||||
|
||||
new_count = this->sample_buf_size;
|
||||
if ( new_count )
|
||||
skip_input( this, resample_wrapper( this, this->sample_buf, &new_count, this->buf, this->write_pos ) );
|
||||
assert( new_count == (long) this->sample_buf_size );
|
||||
|
||||
int bufs_used = stereo_buf->stereo_added | stereo_buf->was_stereo;
|
||||
if ( bufs_used <= 1 ) {
|
||||
mix_mono( this, stereo_buf, out );
|
||||
Blip_remove_samples( &stereo_buf->bufs [0], pair_count );
|
||||
Blip_remove_silence( &stereo_buf->bufs [1], pair_count );
|
||||
Blip_remove_silence( &stereo_buf->bufs [2], pair_count );
|
||||
}
|
||||
else if ( bufs_used & 1 ) {
|
||||
mix_stereo( this, stereo_buf, out );
|
||||
Blip_remove_samples( &stereo_buf->bufs [0], pair_count );
|
||||
Blip_remove_samples( &stereo_buf->bufs [1], pair_count );
|
||||
Blip_remove_samples( &stereo_buf->bufs [2], pair_count );
|
||||
}
|
||||
else {
|
||||
mix_stereo_no_center( this, stereo_buf, out );
|
||||
Blip_remove_silence( &stereo_buf->bufs [0], pair_count );
|
||||
Blip_remove_samples( &stereo_buf->bufs [1], pair_count );
|
||||
Blip_remove_samples( &stereo_buf->bufs [2], pair_count );
|
||||
}
|
||||
|
||||
// to do: this might miss opportunities for optimization
|
||||
if ( !Blip_samples_avail( &stereo_buf->bufs [0] ) )
|
||||
{
|
||||
stereo_buf->was_stereo = stereo_buf->stereo_added;
|
||||
stereo_buf->stereo_added = 0;
|
||||
}
|
||||
|
||||
/* mix_mono( this, stereo_buf, out );
|
||||
Blip_remove_samples( &stereo_buf->bufs [0], pair_count ); */
|
||||
}
|
||||
|
||||
void Resampler_play( struct Resampler* this, long count, dsample_t* out, struct Stereo_Buffer* stereo_buf )
|
||||
{
|
||||
// empty extra buffer
|
||||
long remain = this->sample_buf_size - this->buf_pos;
|
||||
if ( remain )
|
||||
{
|
||||
if ( remain > count )
|
||||
remain = count;
|
||||
count -= remain;
|
||||
memcpy( out, &this->sample_buf [this->buf_pos], remain * sizeof *out );
|
||||
out += remain;
|
||||
this->buf_pos += remain;
|
||||
}
|
||||
|
||||
// entire frames
|
||||
while ( count >= (long) this->sample_buf_size )
|
||||
{
|
||||
play_frame_( this, stereo_buf, out );
|
||||
out += this->sample_buf_size;
|
||||
count -= this->sample_buf_size;
|
||||
}
|
||||
|
||||
// extra
|
||||
if ( count )
|
||||
{
|
||||
play_frame_( this, stereo_buf, this->sample_buf );
|
||||
this->buf_pos = count;
|
||||
memcpy( out, this->sample_buf, count * sizeof *out );
|
||||
out += count;
|
||||
}
|
||||
// empty extra buffer
|
||||
int remain = this->sample_buf_size - this->buf_pos;
|
||||
if ( remain )
|
||||
{
|
||||
if ( remain > count )
|
||||
remain = count;
|
||||
count -= remain;
|
||||
memcpy( out, &this->sample_buf [this->buf_pos], remain * sizeof *out );
|
||||
out += remain;
|
||||
this->buf_pos += remain;
|
||||
}
|
||||
|
||||
// entire frames
|
||||
while ( count >= this->sample_buf_size )
|
||||
{
|
||||
play_frame_( this, blip_buf, out );
|
||||
out += this->sample_buf_size;
|
||||
count -= this->sample_buf_size;
|
||||
}
|
||||
|
||||
// extra
|
||||
if ( count )
|
||||
{
|
||||
play_frame_( this, blip_buf, this->sample_buf );
|
||||
this->buf_pos = count;
|
||||
memcpy( out, this->sample_buf, count * sizeof *out );
|
||||
out += count;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
#ifndef RESAMPLER_H
|
||||
#define RESAMPLER_H
|
||||
|
||||
#include "blargg_config.h"
|
||||
#include "blargg_common.h"
|
||||
#include "multi_buffer.h"
|
||||
|
||||
typedef short dsample_t;
|
||||
typedef short sample_t;
|
||||
|
||||
enum { stereo = 2 };
|
||||
enum { max_buf_size = 3960 };
|
||||
|
@ -16,53 +16,61 @@ enum { write_offset = 8 * stereo };
|
|||
enum { gain_bits = 14 };
|
||||
|
||||
struct Resampler {
|
||||
int (*callback)( void*, blip_time_t, int, dsample_t* );
|
||||
void* callback_data;
|
||||
int (*callback)( void*, blip_time_t, int, sample_t* );
|
||||
void* callback_data;
|
||||
|
||||
dsample_t sample_buf [max_buf_size];
|
||||
int sample_buf_size;
|
||||
int oversamples_per_frame;
|
||||
int buf_pos;
|
||||
int resampler_size;
|
||||
int gain_;
|
||||
int sample_buffer_size;
|
||||
int sample_buf_size;
|
||||
int oversamples_per_frame;
|
||||
int buf_pos;
|
||||
int resampler_size;
|
||||
int gain_;
|
||||
|
||||
// Internal resampler
|
||||
dsample_t buf [max_resampler_size];
|
||||
int buffer_size;
|
||||
int buffer_size;
|
||||
int write_pos;
|
||||
|
||||
int write_pos;
|
||||
int rate_;
|
||||
int pos;
|
||||
int step;
|
||||
|
||||
int pos;
|
||||
int step;
|
||||
int rate_;
|
||||
|
||||
sample_t sample_buf [max_buf_size];
|
||||
sample_t buf [max_resampler_size]; // Internal resampler
|
||||
};
|
||||
|
||||
static inline void Resampler_init( struct Resampler* this )
|
||||
{
|
||||
this->pos = 0;
|
||||
this->write_pos = 0;
|
||||
this->rate_ = 0;
|
||||
this->pos = 0;
|
||||
this->write_pos = 0;
|
||||
this->rate_ = 0;
|
||||
this->sample_buf_size = 0;
|
||||
this->sample_buffer_size = 0;
|
||||
this->oversamples_per_frame = 0;
|
||||
}
|
||||
|
||||
blargg_err_t Resampler_reset( struct Resampler* this, int max_pairs );
|
||||
void Resampler_resize( struct Resampler* this, int pairs_per_frame );
|
||||
void Resampler_play( struct Resampler* this, int count, sample_t* out, struct Blip_Buffer* );
|
||||
|
||||
void Resampler_play( struct Resampler* this, long count, dsample_t* out, struct Stereo_Buffer* );
|
||||
|
||||
static inline void Resampler_set_callback(struct Resampler* this, int (*func)( void*, blip_time_t, int, dsample_t* ), void* user_data )
|
||||
static inline void Resampler_set_callback(struct Resampler* this, int (*func)( void*, blip_time_t, int, sample_t* ), void* user_data )
|
||||
{
|
||||
this->callback = func;
|
||||
this->callback_data = user_data;
|
||||
this->callback = func;
|
||||
this->callback_data = user_data;
|
||||
}
|
||||
|
||||
blargg_err_t Resampler_setup( struct Resampler* this, int fm_rate, int fm_gain, int rate, int gain );
|
||||
|
||||
static inline void Resampler_clear( struct Resampler* this )
|
||||
{
|
||||
this->buf_pos = this->sample_buf_size;
|
||||
this->buf_pos = this->sample_buf_size;
|
||||
|
||||
this->pos = 0;
|
||||
this->write_pos = 0;
|
||||
this->pos = 0;
|
||||
this->write_pos = 0;
|
||||
}
|
||||
|
||||
static inline int Resampler_rate( struct Resampler* this )
|
||||
{
|
||||
return this->rate_;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -89,8 +89,7 @@ void Vgm_init( struct Vgm_Emu* this )
|
|||
Synth_init( &this->pcm );
|
||||
|
||||
Buffer_init( &this->buf );
|
||||
Buffer_init( &this->stereo_buf );
|
||||
this->blip_buf = &this->stereo_buf.bufs [0];
|
||||
Blip_init( &this->blip_buf );
|
||||
|
||||
// Init fm chips
|
||||
Ym2413_init( &this->ym2413 );
|
||||
|
@ -279,7 +278,7 @@ blargg_err_t Vgm_load_mem( struct Vgm_Emu* this, byte const* new_data, long new_
|
|||
if ( !this->psg_rate )
|
||||
this->psg_rate = 3579545;
|
||||
|
||||
Buffer_clock_rate( &this->stereo_buf, this->psg_rate );
|
||||
Blip_set_clock_rate( &this->blip_buf, this->psg_rate );
|
||||
|
||||
// Disable FM
|
||||
this->fm_rate = 0;
|
||||
|
@ -342,14 +341,14 @@ blargg_err_t setup_fm( struct Vgm_Emu* this )
|
|||
{
|
||||
int fm_rate = 0;
|
||||
if ( !this->disable_oversampling )
|
||||
this->fm_rate = (this->sample_rate * 3) / 2; // oversample factor = 1.5
|
||||
fm_rate = (this->sample_rate * 3) / 2; // oversample factor = 1.5
|
||||
RETURN_ERR( init_fm( this, &fm_rate ) );
|
||||
|
||||
if ( uses_fm( this ) )
|
||||
{
|
||||
this->voice_count = 8;
|
||||
RETURN_ERR( Resampler_setup( &this->resampler, fm_rate, fm_gain, this->sample_rate, this->gain ) );
|
||||
RETURN_ERR( Resampler_reset( &this->resampler, Buffer_length( &this->stereo_buf ) * this->sample_rate / 1000 ) );
|
||||
RETURN_ERR( Resampler_reset( &this->resampler, Blip_length( &this->blip_buf ) * this->sample_rate / 1000 ) );
|
||||
Sms_apu_volume( &this->psg, ((this->gain/5)-(this->gain*5)/1000) * fm_gain );
|
||||
}
|
||||
else
|
||||
|
@ -399,7 +398,7 @@ static blargg_err_t play_( struct Vgm_Emu* this, long count, sample_t* out )
|
|||
return 0;
|
||||
}
|
||||
|
||||
Resampler_play( &this->resampler, count, out, &this->stereo_buf );
|
||||
Resampler_play( &this->resampler, count, out, &this->blip_buf );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -428,19 +427,16 @@ static inline blip_time_t to_psg_time( struct Vgm_Emu* this, vgm_time_t t )
|
|||
|
||||
static void write_pcm( struct Vgm_Emu* this, vgm_time_t vgm_time, int amp )
|
||||
{
|
||||
if ( this->blip_buf )
|
||||
{
|
||||
check( amp >= 0 );
|
||||
blip_time_t blip_time = to_psg_time( this, vgm_time );
|
||||
int old = this->dac_amp;
|
||||
int delta = amp - old;
|
||||
this->dac_amp = amp;
|
||||
Blip_set_modified( this->blip_buf );
|
||||
if ( old >= 0 ) // first write is ignored, to avoid click
|
||||
Synth_offset_inline( &this->pcm, blip_time, delta, this->blip_buf );
|
||||
else
|
||||
this->dac_amp |= this->dac_disabled;
|
||||
}
|
||||
check( amp >= 0 );
|
||||
blip_time_t blip_time = to_psg_time( this, vgm_time );
|
||||
int old = this->dac_amp;
|
||||
int delta = amp - old;
|
||||
this->dac_amp = amp;
|
||||
Blip_set_modified( &this->blip_buf );
|
||||
if ( old >= 0 ) // first write is ignored, to avoid click
|
||||
Synth_offset_inline( &this->pcm, blip_time, delta, &this->blip_buf );
|
||||
else
|
||||
this->dac_amp |= this->dac_disabled;
|
||||
}
|
||||
|
||||
blip_time_t run( struct Vgm_Emu* this, vgm_time_t end_time )
|
||||
|
@ -514,22 +510,7 @@ blip_time_t run( struct Vgm_Emu* this, vgm_time_t end_time )
|
|||
|
||||
case cmd_ym2612_port1:
|
||||
if ( Ym2612_run_until( &this->ym2612, to_fm_time( this, vgm_time ) ) )
|
||||
{
|
||||
if ( pos [0] == ym2612_dac_pan_port )
|
||||
{
|
||||
struct Blip_Buffer* blip_buf = NULL;
|
||||
switch ( pos [1] >> 6 )
|
||||
{
|
||||
case 0: blip_buf = NULL; break;
|
||||
case 1: blip_buf = &this->stereo_buf.bufs [2]; break;
|
||||
case 2: blip_buf = &this->stereo_buf.bufs [1]; break;
|
||||
case 3: blip_buf = &this->stereo_buf.bufs [0]; break;
|
||||
}
|
||||
this->blip_buf = blip_buf;
|
||||
}
|
||||
|
||||
Ym2612_write1( &this->ym2612, pos [0], pos [1] );
|
||||
}
|
||||
pos += 2;
|
||||
break;
|
||||
|
||||
|
@ -664,7 +645,7 @@ void update_fm_rates( struct Vgm_Emu* this, int* ym2413_rate, int* ym2612_rate )
|
|||
blargg_err_t Vgm_set_sample_rate( struct Vgm_Emu* this, long rate )
|
||||
{
|
||||
require( !this->sample_rate ); // sample rate can't be changed once set
|
||||
RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 30 ) );
|
||||
RETURN_ERR( Blip_set_sample_rate( &this->blip_buf, rate, 1000 / 30 ) );
|
||||
RETURN_ERR( Buffer_set_sample_rate( &this->buf, rate, 1000 / 20 ) );
|
||||
|
||||
// Set bass frequency
|
||||
|
@ -712,7 +693,7 @@ void Sound_mute_voices( struct Vgm_Emu* this, int mask )
|
|||
if ( uses_fm( this ) )
|
||||
{
|
||||
for ( i = sms_osc_count; --i >= 0; )
|
||||
Sms_apu_set_output( &this->psg, i, ( mask & 0x80 ) ? 0 : &this->stereo_buf.bufs [0], NULL, NULL );
|
||||
Sms_apu_set_output( &this->psg, i, ( mask & 0x80 ) ? 0 : &this->blip_buf, NULL, NULL );
|
||||
if ( Ym2612_enabled( &this->ym2612 ) )
|
||||
{
|
||||
Synth_volume( &this->pcm, (mask & 0x40) ? 0 : (int)((long long)(0.1115*FP_ONE_VOLUME) / 256 * fm_gain * this->gain / FP_ONE_VOLUME) );
|
||||
|
@ -743,7 +724,7 @@ void Sound_set_tempo( struct Vgm_Emu* this, int t )
|
|||
if ( this->file_begin )
|
||||
{
|
||||
this->vgm_rate = (long) ((44100LL * t) / FP_ONE_TEMPO);
|
||||
this->blip_time_factor = (int) (((1LL << blip_time_bits) * Blip_clock_rate( &this->stereo_buf.bufs [0] )) / this->vgm_rate);
|
||||
this->blip_time_factor = (int) (((1LL << blip_time_bits) * Blip_clock_rate( &this->blip_buf )) / this->vgm_rate);
|
||||
//debug_printf( "blip_time_factor: %ld\n", blip_time_factor );
|
||||
//debug_printf( "vgm_rate: %ld\n", vgm_rate );
|
||||
// TODO: remove? calculates vgm_rate more accurately (above differs at most by one Hz only)
|
||||
|
@ -761,8 +742,6 @@ blargg_err_t Vgm_start_track( struct Vgm_Emu* this )
|
|||
|
||||
Sms_apu_reset( &this->psg, get_le16( header( this )->noise_feedback ), header( this )->noise_width );
|
||||
|
||||
this->blip_buf = &this->stereo_buf.bufs [0];
|
||||
|
||||
this->dac_disabled = -1;
|
||||
this->pos = this->file_begin + header_size;
|
||||
this->pcm_data = this->pos;
|
||||
|
@ -785,7 +764,7 @@ blargg_err_t Vgm_start_track( struct Vgm_Emu* this )
|
|||
if ( Ym2612_enabled( &this->ym2612 ) )
|
||||
Ym2612_reset( &this->ym2612 );
|
||||
|
||||
Buffer_clear( &this->stereo_buf );
|
||||
Blip_clear( &this->blip_buf, 1 );
|
||||
Resampler_clear( &this->resampler );
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "ym2612_emu.h"
|
||||
#include "sms_apu.h"
|
||||
|
||||
typedef short sample_t;
|
||||
typedef int vgm_time_t;
|
||||
typedef int fm_time_t;
|
||||
|
||||
|
@ -85,7 +84,7 @@ struct Vgm_Emu {
|
|||
int dac_amp;
|
||||
int dac_disabled; // -1 if disabled
|
||||
|
||||
struct Blip_Buffer* blip_buf;
|
||||
struct Blip_Buffer blip_buf;
|
||||
|
||||
// general
|
||||
long clock_rate_;
|
||||
|
@ -124,10 +123,7 @@ struct Vgm_Emu {
|
|||
|
||||
struct Sms_Apu psg;
|
||||
struct Blip_Synth pcm;
|
||||
struct Stereo_Buffer stereo_buf;
|
||||
|
||||
struct Resampler resampler;
|
||||
|
||||
struct Stereo_Buffer buf;
|
||||
};
|
||||
|
||||
|
|
|
@ -227,13 +227,12 @@
|
|||
& \fname{.sgc}
|
||||
& Supports Sega Master System and Game Gear Sound Format.
|
||||
Progress bar and seek use subtracks instead of seconds.\\
|
||||
\nopt{clipv1,c200v2}{
|
||||
Video Game Music Format
|
||||
& \fname{.vgm}
|
||||
& \\
|
||||
Gzipped Video Game Music Format
|
||||
& \fname{.vgz}
|
||||
& \\}
|
||||
& \\
|
||||
MOD
|
||||
& \fname{.mod}
|
||||
& \\
|
||||
|
@ -251,6 +250,9 @@
|
|||
& \\
|
||||
\end{rbtabular}
|
||||
|
||||
\note{NSF and VGM might not play in realtime on all devices due to CPU
|
||||
performance requirements.}
|
||||
|
||||
\subsection{Codec featureset}
|
||||
\begin{rbtabular}{.95\textwidth}{lXXX}%
|
||||
{\textbf{Format} & \textbf{Seek} & \textbf{Resume} & \textbf{Gapless}}{}{}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue