Update GME, including support for tag-specified fade times for formats which support it, which are SPC and SFM.
This commit is contained in:
parent
b8110b85de
commit
c594690aab
10 changed files with 456 additions and 411 deletions
|
@ -103,6 +103,9 @@ public:
|
|||
// on others this has no effect. Should be called only once *before* set_sample_rate().
|
||||
virtual void set_buffer( class Multi_Buffer* ) { }
|
||||
|
||||
// Mutes native effects of a given sound engine. Currently only applies to the SPC emulator.
|
||||
virtual void mute_effects( bool mute ) { }
|
||||
|
||||
// Sound equalization (treble/bass)
|
||||
|
||||
// Frequency equalizer parameters (see gme.txt)
|
||||
|
@ -178,7 +181,7 @@ protected:
|
|||
public:
|
||||
gme_t();
|
||||
~gme_t();
|
||||
BLARGG_DEPRECATED( const char** voice_names() const { return CONST_CAST(const char**,voice_names_); } )
|
||||
const char** voice_names() const { return CONST_CAST(const char**,voice_names_); }
|
||||
|
||||
protected:
|
||||
virtual void unload();
|
||||
|
|
|
@ -28,6 +28,13 @@ public:
|
|||
// Enables gaussian, cubic or sinc interpolation
|
||||
void interpolation_level( int level = 0 ) { smp.dsp.spc_dsp.interpolation_level( level ); }
|
||||
|
||||
// Enables an analog signal simulation filter
|
||||
void enable_filter( bool enable = true ) { _enable_filter = enable; if (enable) filter.clear(); }
|
||||
|
||||
// Enables native echo
|
||||
void enable_echo( bool enable = true ) { smp.dsp.spc_dsp.enable_echo( enable ); }
|
||||
virtual void mute_effects( bool mute ) { enable_echo(!mute); }
|
||||
|
||||
SuperFamicom::SMP const* get_smp() const;
|
||||
SuperFamicom::SMP * get_smp();
|
||||
|
||||
|
@ -82,6 +89,8 @@ private:
|
|||
Spc_Filter filter;
|
||||
SuperFamicom::SMP smp;
|
||||
|
||||
bool _enable_filter;
|
||||
|
||||
byte const* trailer_() const;
|
||||
int trailer_size_() const;
|
||||
blargg_err_t play_and_filter( int count, sample_t out [] );
|
||||
|
|
|
@ -27,6 +27,8 @@ Sfm_Emu::Sfm_Emu()
|
|||
set_gain( 1.4 );
|
||||
set_max_initial_silence( 30 );
|
||||
set_silence_lookahead( 30 ); // Some SFMs may have a lot of initialization code
|
||||
enable_filter( false );
|
||||
enable_echo( true );
|
||||
}
|
||||
|
||||
Sfm_Emu::~Sfm_Emu() { }
|
||||
|
@ -68,7 +70,7 @@ static void copy_info( track_info_t* out, const Bml_Parser& in )
|
|||
if ( value )
|
||||
out->fade_length = strtoul( value, &end, 10 );
|
||||
else
|
||||
out->fade_length = 0;
|
||||
out->fade_length = -1;
|
||||
}
|
||||
|
||||
blargg_err_t Sfm_Emu::track_info_( track_info_t* out, int ) const
|
||||
|
@ -297,9 +299,9 @@ blargg_err_t Sfm_Emu::start_track_( int track )
|
|||
value = metadata.enumValue("smp:ports");
|
||||
if (value)
|
||||
{
|
||||
for (auto &n : smp.sfm_last)
|
||||
for (int i = 0; i < _countof(smp.sfm_last); i++)
|
||||
{
|
||||
n = strtol(value, &end, 10);
|
||||
smp.sfm_last[i] = strtol(value, &end, 10);
|
||||
if (*end == ',')
|
||||
value = end + 1;
|
||||
else
|
||||
|
@ -482,10 +484,10 @@ void Sfm_Emu::create_updated_metadata( Bml_Parser &out ) const
|
|||
oss.str("");
|
||||
oss.clear();
|
||||
first = true;
|
||||
for (auto n : smp.sfm_last)
|
||||
for (int i = 0; i < _countof(smp.sfm_last); i++)
|
||||
{
|
||||
if (!first) oss << ",";
|
||||
oss << (unsigned long)n;
|
||||
oss << (unsigned long)smp.sfm_last[i];
|
||||
first = false;
|
||||
}
|
||||
out.setValue("smp:ports", oss.str().c_str());
|
||||
|
@ -621,7 +623,7 @@ blargg_err_t Sfm_Emu::save_( gme_writer_t writer, void* your_data ) const
|
|||
blargg_err_t Sfm_Emu::play_and_filter( int count, sample_t out [] )
|
||||
{
|
||||
smp.render( out, count );
|
||||
filter.run( out, count );
|
||||
if ( _enable_filter ) filter.run( out, count );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,13 @@ public:
|
|||
// Enables gaussian, cubic or sinc interpolation
|
||||
void interpolation_level( int level = 0 ) { smp.dsp.spc_dsp.interpolation_level( level ); }
|
||||
|
||||
// Enables an analog signal simulation filter
|
||||
void enable_filter( bool enable = true ) { _enable_filter = enable; if (enable) filter.clear(); }
|
||||
|
||||
// Enables native echo
|
||||
void enable_echo(bool enable = true) { smp.dsp.spc_dsp.enable_echo(enable); }
|
||||
virtual void mute_effects(bool mute) { enable_echo(!mute); }
|
||||
|
||||
SuperFamicom::SMP const* get_smp() const;
|
||||
SuperFamicom::SMP * get_smp();
|
||||
|
||||
|
@ -65,6 +72,8 @@ private:
|
|||
Spc_Filter filter;
|
||||
SuperFamicom::SMP smp;
|
||||
|
||||
bool _enable_filter;
|
||||
|
||||
Bml_Parser metadata;
|
||||
void create_updated_metadata(Bml_Parser &out) const;
|
||||
|
||||
|
|
|
@ -257,8 +257,8 @@ gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, int track )
|
|||
COPY( length );
|
||||
COPY( intro_length );
|
||||
COPY( loop_length );
|
||||
COPY( fade_length );
|
||||
|
||||
info->i4 = -1;
|
||||
info->i5 = -1;
|
||||
info->i6 = -1;
|
||||
info->i7 = -1;
|
||||
|
@ -360,6 +360,7 @@ void gme_set_equalizer ( Music_Emu* gme, gme_equalizer_t const* eq ) { gme
|
|||
void gme_equalizer ( Music_Emu const* gme, gme_equalizer_t* o ) { *o = gme->equalizer(); }
|
||||
const char* gme_voice_name ( Music_Emu const* gme, int i ) { return gme->voice_name( i ); }
|
||||
gme_err_t gme_save ( Music_Emu const* gme, gme_writer_t writer, void* your_data ) { return gme->save( writer, your_data ); }
|
||||
void gme_mute_effects ( Music_Emu* gme, gme_bool disable ) { gme->mute_effects(disable); }
|
||||
|
||||
void gme_effects( Music_Emu const* gme, gme_effects_t* out )
|
||||
{
|
||||
|
|
|
@ -97,7 +97,10 @@ struct gme_info_t
|
|||
otherwise a default of 150000 (2.5 minutes). */
|
||||
int play_length;
|
||||
|
||||
int i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15; /* reserved */
|
||||
/* Fade duration, in milliseconds, if the file specifies it */
|
||||
int fade_length;
|
||||
|
||||
int i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15; /* reserved */
|
||||
|
||||
/* empty string ("") if not available */
|
||||
const char* system;
|
||||
|
@ -135,6 +138,9 @@ void gme_mute_voice( gme_t*, int index, gme_bool mute );
|
|||
voices, 0 unmutes them all, 0x01 mutes just the first voice, etc. */
|
||||
void gme_mute_voices( gme_t*, int muting_mask );
|
||||
|
||||
/* Disables native effects, and possibly others. */
|
||||
void gme_mute_effects( gme_t*, gme_bool mute );
|
||||
|
||||
/* Frequency equalizer parameters (see gme.txt) */
|
||||
typedef struct gme_equalizer_t
|
||||
{
|
||||
|
|
|
@ -70,17 +70,16 @@ static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] =
|
|||
|
||||
#define WRITE_SAMPLES( l, r, out ) \
|
||||
{\
|
||||
if ( out >= m.out_end )\
|
||||
{\
|
||||
int count = sample_count();\
|
||||
m.out_begin = (SPC_DSP::sample_t *) realloc( m.out_begin, (count ? count * 2 : 8192) * sizeof(SPC_DSP::sample_t) );\
|
||||
out = m.out_begin + count;\
|
||||
m.out_end = m.out_begin + count * 2;\
|
||||
}\
|
||||
out [0] = l;\
|
||||
out [1] = r;\
|
||||
out += 2;\
|
||||
if ( out >= m.out_end )\
|
||||
{\
|
||||
check( out == m.out_end );\
|
||||
check( m.out_end != &m.extra [extra_size] || \
|
||||
(m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\
|
||||
out = m.extra;\
|
||||
m.out_end = &m.extra [extra_size];\
|
||||
}\
|
||||
}\
|
||||
|
||||
void SPC_DSP::set_output( sample_t* out, int size )
|
||||
|
@ -88,8 +87,7 @@ void SPC_DSP::set_output( sample_t* out, int size )
|
|||
require( (size & 1) == 0 ); // must be even
|
||||
if ( !out )
|
||||
{
|
||||
out = m.extra;
|
||||
size = extra_size;
|
||||
size = 0;
|
||||
}
|
||||
m.out_begin = out;
|
||||
m.out = out;
|
||||
|
@ -739,7 +737,7 @@ MISC_CLOCK( 30 )
|
|||
if ( m.every_other_sample )
|
||||
{
|
||||
m.kon = m.new_kon;
|
||||
m.t_koff = REG(koff) | m.mute_mask;
|
||||
m.t_koff = REG(koff);
|
||||
}
|
||||
|
||||
run_counters();
|
||||
|
@ -893,6 +891,10 @@ inline void SPC_DSP::voice_output( voice_t const* v, int ch )
|
|||
if ( abs_amp > m.max_level[v - (const SPC_DSP::voice_t *)&m.voices][ch] )
|
||||
m.max_level[v - (const SPC_DSP::voice_t *)&m.voices][ch] = abs_amp;
|
||||
|
||||
// FIX: audibly mute, rather than do it in a way the SPC code can easily detect
|
||||
if ( m.mute_mask & ( 1 << ( v - m.voices ) ) )
|
||||
amp = 0;
|
||||
|
||||
// Add to output total
|
||||
m.t_main_out [ch] += amp;
|
||||
CLAMP16( m.t_main_out [ch] );
|
||||
|
@ -1067,7 +1069,7 @@ inline int SPC_DSP::echo_output( int ch )
|
|||
vol ^= vol >> 7;
|
||||
|
||||
int out = (int16_t) ((m.t_main_out [ch] * vol) >> 7) +
|
||||
(int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7);
|
||||
(int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7) * m.enable_echo;
|
||||
CLAMP16( out );
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
// doesn't generate any.
|
||||
typedef short sample_t;
|
||||
void set_output( sample_t* out, int out_size );
|
||||
sample_t* get_output();
|
||||
|
||||
// Number of samples written to output since it was last set, always
|
||||
// a multiple of 2. Undefined if more samples were generated than
|
||||
|
@ -91,11 +92,10 @@ public:
|
|||
};
|
||||
|
||||
public:
|
||||
enum { extra_size = 16 };
|
||||
sample_t* extra() { return m.extra; }
|
||||
sample_t const* out_pos() const { return m.out; }
|
||||
void disable_surround( bool disable = true );
|
||||
void interpolation_level( int level = 0 ) { m.interpolation_level = level; }
|
||||
void enable_echo( bool enable = true ) { m.enable_echo = enable ? 1 : 0; }
|
||||
public:
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
|
||||
|
@ -184,10 +184,10 @@ public:
|
|||
int mute_mask;
|
||||
int surround_threshold;
|
||||
int interpolation_level;
|
||||
int enable_echo;
|
||||
sample_t* out;
|
||||
sample_t* out_end;
|
||||
sample_t* out_begin;
|
||||
sample_t extra [extra_size];
|
||||
|
||||
int max_level[voice_count][2];
|
||||
};
|
||||
|
@ -299,6 +299,11 @@ inline bool SPC_DSP::check_kon()
|
|||
return old;
|
||||
}
|
||||
|
||||
inline SPC_DSP::sample_t* SPC_DSP::get_output()
|
||||
{
|
||||
return m.out_begin;
|
||||
}
|
||||
|
||||
#if !SPC_NO_COPY_STATE_FUNCS
|
||||
|
||||
class SPC_State_Copier {
|
||||
|
|
|
@ -18,6 +18,7 @@ extern gme_err_t readCallback( void* data, void* out, long count );
|
|||
Music_Emu* emu;
|
||||
id<CogSource> source;
|
||||
long length;
|
||||
long fade;
|
||||
}
|
||||
|
||||
- (void)setSource:(id<CogSource>)s;
|
||||
|
|
|
@ -122,6 +122,13 @@ gme_err_t readCallback( void* data, void* out, long count )
|
|||
DLog(@"Setting default: %li", length);
|
||||
}
|
||||
|
||||
if (info->fade_length >= 0) {
|
||||
fade = info->fade_length;
|
||||
}
|
||||
else {
|
||||
fade = 8000;
|
||||
}
|
||||
|
||||
gme_free_info( info );
|
||||
|
||||
DLog(@"Length: %li", length);
|
||||
|
@ -134,7 +141,7 @@ gme_err_t readCallback( void* data, void* out, long count )
|
|||
return NO;
|
||||
}
|
||||
|
||||
length += 8000;
|
||||
length += fade;
|
||||
|
||||
|
||||
[self willChangeValueForKey:@"properties"];
|
||||
|
@ -167,7 +174,7 @@ gme_err_t readCallback( void* data, void* out, long count )
|
|||
if ( IsRepeatOneSet() )
|
||||
gme_set_fade( emu, -1, 0 );
|
||||
else
|
||||
gme_set_fade( emu, (int)(length - 8000), 8000 );
|
||||
gme_set_fade( emu, (int)(length - fade), fade );
|
||||
|
||||
gme_play(emu, numSamples, (short int *)buf);
|
||||
|
||||
|
|
Loading…
Reference in a new issue