GME: Implemented functionality to update the metadata on an instance of gme_t, for SFM only. Also extended the SFM metadata to include log looping, track length/fade, and textual information.
parent
9b7b8d5fd7
commit
bb0f0ed511
|
@ -328,7 +328,7 @@ void Bml_Parser::setValue(std::string const& path, long value)
|
||||||
setValue( path, str.str().c_str() );
|
setValue( path, str.str().c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bml_Parser::serialize(std::string & out)
|
void Bml_Parser::serialize(std::string & out) const
|
||||||
{
|
{
|
||||||
std::ostringstream strOut;
|
std::ostringstream strOut;
|
||||||
serialize(strOut, &document, 0);
|
serialize(strOut, &document, 0);
|
||||||
|
@ -342,13 +342,15 @@ void Bml_Parser::serialize(std::ostringstream & out, Bml_Node const* node, unsig
|
||||||
if ( indent )
|
if ( indent )
|
||||||
{
|
{
|
||||||
out << node->getName();
|
out << node->getName();
|
||||||
if (node->getValue()) out << ":" << node->getValue();
|
if (node->getValue() && strlen(node->getValue())) out << ":" << node->getValue();
|
||||||
out << std::endl;
|
out << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0, j = node->getChildCount(); i < j; ++i)
|
for (unsigned i = 0, j = node->getChildCount(); i < j; ++i)
|
||||||
{
|
{
|
||||||
Bml_Node const& child = node->getChild(i);
|
Bml_Node const& child = node->getChild(i);
|
||||||
|
if ( (!child.getValue() || !strlen(child.getValue())) && !child.getChildCount() )
|
||||||
|
continue;
|
||||||
serialize( out, &child, indent + 1 );
|
serialize( out, &child, indent + 1 );
|
||||||
if ( indent == 0 ) out << std::endl;
|
if ( indent == 0 ) out << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,8 @@ public:
|
||||||
void setValue(std::string const& path, long value);
|
void setValue(std::string const& path, long value);
|
||||||
void setValue(std::string const& path, const char * value);
|
void setValue(std::string const& path, const char * value);
|
||||||
|
|
||||||
void serialize(std::string & out);
|
void serialize(std::string & out) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void serialize(std::ostringstream & out, Bml_Node const* node, unsigned int indent) const;
|
void serialize(std::ostringstream & out, Bml_Node const* node, unsigned int indent) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,6 +41,8 @@ public:
|
||||||
// Info for currently playing track
|
// Info for currently playing track
|
||||||
using Gme_File::track_info;
|
using Gme_File::track_info;
|
||||||
blargg_err_t track_info( track_info_t* out ) const;
|
blargg_err_t track_info( track_info_t* out ) const;
|
||||||
|
blargg_err_t set_track_info( const track_info_t* in );
|
||||||
|
blargg_err_t set_track_info( const track_info_t* in, int track_number );
|
||||||
|
|
||||||
struct Hash_Function
|
struct Hash_Function
|
||||||
{
|
{
|
||||||
|
@ -48,7 +50,7 @@ public:
|
||||||
};
|
};
|
||||||
virtual blargg_err_t hash_( Hash_Function& ) const BLARGG_PURE( ; )
|
virtual blargg_err_t hash_( Hash_Function& ) const BLARGG_PURE( ; )
|
||||||
|
|
||||||
virtual blargg_err_t save( gme_writer_t, void* your_data) const { return "Not supported by this format"; }
|
blargg_err_t save( gme_writer_t writer, void* your_data) const;
|
||||||
|
|
||||||
// Track status/control
|
// Track status/control
|
||||||
|
|
||||||
|
@ -166,6 +168,11 @@ protected:
|
||||||
// Skip count samples. Count will always be even.
|
// Skip count samples. Count will always be even.
|
||||||
virtual blargg_err_t skip_( int count );
|
virtual blargg_err_t skip_( int count );
|
||||||
|
|
||||||
|
// Save current state of file to specified writer.
|
||||||
|
virtual blargg_err_t save_( gme_writer_t, void* ) const { return "Not supported by this format"; }
|
||||||
|
|
||||||
|
// Set track info
|
||||||
|
virtual blargg_err_t set_track_info_( const track_info_t*, int ) { return "Not supported by this format"; }
|
||||||
|
|
||||||
// Implementation
|
// Implementation
|
||||||
public:
|
public:
|
||||||
|
@ -221,6 +228,21 @@ inline blargg_err_t Music_Emu::track_info( track_info_t* out ) const
|
||||||
return track_info( out, current_track_ );
|
return track_info( out, current_track_ );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline blargg_err_t Music_Emu::save(gme_writer_t writer, void *your_data) const
|
||||||
|
{
|
||||||
|
return save_( writer, your_data );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blargg_err_t Music_Emu::set_track_info(const track_info_t *in)
|
||||||
|
{
|
||||||
|
return set_track_info_( in, current_track_ );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blargg_err_t Music_Emu::set_track_info(const track_info_t *in, int track)
|
||||||
|
{
|
||||||
|
return set_track_info_( in, track );
|
||||||
|
}
|
||||||
|
|
||||||
inline int Music_Emu::sample_rate() const { return sample_rate_; }
|
inline int Music_Emu::sample_rate() const { return sample_rate_; }
|
||||||
inline int Music_Emu::voice_count() const { return voice_count_; }
|
inline int Music_Emu::voice_count() const { return voice_count_; }
|
||||||
inline int Music_Emu::current_track() const { return current_track_; }
|
inline int Music_Emu::current_track() const { return current_track_; }
|
||||||
|
|
|
@ -38,12 +38,65 @@ static void hash_sfm_file( byte const* data, int data_size, Music_Emu::Hash_Func
|
||||||
out.hash_( data, data_size );
|
out.hash_( data, data_size );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void copy_field( char* out, size_t size, const Bml_Parser& in, char const* in_path )
|
||||||
|
{
|
||||||
|
const char * value = in.enumValue( in_path );
|
||||||
|
if ( value ) strncpy( out, value, size - 1 ), out[ size - 1 ] = 0;
|
||||||
|
else out[ 0 ] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_info( track_info_t* out, const Bml_Parser& in )
|
||||||
|
{
|
||||||
|
copy_field( out->song, sizeof(out->song), in, "information:title" );
|
||||||
|
copy_field( out->game, sizeof(out->game), in, "information:game" );
|
||||||
|
copy_field( out->author, sizeof(out->author), in, "information:author" );
|
||||||
|
copy_field( out->composer, sizeof(out->composer), in, "information:composer" );
|
||||||
|
copy_field( out->copyright, sizeof(out->copyright), in, "information:copyright" );
|
||||||
|
copy_field( out->date, sizeof(out->date), in, "information:date" );
|
||||||
|
copy_field( out->track, sizeof(out->track), in, "information:track" );
|
||||||
|
copy_field( out->disc, sizeof(out->disc), in, "information:disc" );
|
||||||
|
copy_field( out->dumper, sizeof(out->dumper), in, "information:dumper" );
|
||||||
|
|
||||||
|
char * end;
|
||||||
|
const char * value = in.enumValue( "timing:length" );
|
||||||
|
if ( value )
|
||||||
|
out->length = strtoul( value, &end, 10 );
|
||||||
|
else
|
||||||
|
out->length = 0;
|
||||||
|
|
||||||
|
value = in.enumValue( "timing:fade" );
|
||||||
|
if ( value )
|
||||||
|
out->fade_length = strtoul( value, &end, 10 );
|
||||||
|
else
|
||||||
|
out->fade_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
blargg_err_t Sfm_Emu::track_info_( track_info_t* out, int ) const
|
blargg_err_t Sfm_Emu::track_info_( track_info_t* out, int ) const
|
||||||
{
|
{
|
||||||
const char * title = metadata.enumValue("information:title");
|
copy_info( out, metadata );
|
||||||
if (title) strncpy( out->song, title, 255 );
|
return blargg_ok;
|
||||||
else out->song[0] = 0;
|
}
|
||||||
out->song[255] = '\0';
|
|
||||||
|
static void set_track_info( const track_info_t* in, Bml_Parser& out )
|
||||||
|
{
|
||||||
|
out.setValue( "information:title", in->song );
|
||||||
|
out.setValue( "information:game", in->game );
|
||||||
|
out.setValue( "information:author", in->author );
|
||||||
|
out.setValue( "information:composer", in->composer );
|
||||||
|
out.setValue( "information:copyright", in->copyright );
|
||||||
|
out.setValue( "information:date", in->date );
|
||||||
|
out.setValue( "information:track", in->track );
|
||||||
|
out.setValue( "information:disc", in->disc );
|
||||||
|
out.setValue( "information:dumper", in->dumper );
|
||||||
|
|
||||||
|
out.setValue( "timing:length", in->length );
|
||||||
|
out.setValue( "timing:fade", in->fade_length );
|
||||||
|
}
|
||||||
|
|
||||||
|
blargg_err_t Sfm_Emu::set_track_info_( const track_info_t* in, int )
|
||||||
|
{
|
||||||
|
::set_track_info(in, metadata);
|
||||||
|
|
||||||
return blargg_ok;
|
return blargg_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,19 +125,19 @@ struct Sfm_File : Gme_Info_
|
||||||
if ( file_size < 8 )
|
if ( file_size < 8 )
|
||||||
return "SFM file too small";
|
return "SFM file too small";
|
||||||
int metadata_size = get_le32( data.begin() + 4 );
|
int metadata_size = get_le32( data.begin() + 4 );
|
||||||
byte temp = data[ 8 + metadata_size ];
|
metadata.parseDocument( (const char *)data.begin() + 8, metadata_size );
|
||||||
data[ 8 + metadata_size ] = '\0';
|
|
||||||
metadata.parseDocument( (const char *)data.begin() + 8 );
|
|
||||||
data[ 8 + metadata_size ] = temp;
|
|
||||||
return blargg_ok;
|
return blargg_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
blargg_err_t track_info_( track_info_t* out, int ) const
|
blargg_err_t track_info_( track_info_t* out, int ) const
|
||||||
{
|
{
|
||||||
const char * title = metadata.enumValue("information:title");
|
copy_info( out, metadata );
|
||||||
if (title) strncpy( out->song, title, 255 );
|
return blargg_ok;
|
||||||
else out->song[0] = 0;
|
}
|
||||||
out->song[255] = '\0';
|
|
||||||
|
blargg_err_t set_track_info_( const track_info_t* in, int )
|
||||||
|
{
|
||||||
|
::set_track_info( in, metadata );
|
||||||
return blargg_ok;
|
return blargg_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +146,11 @@ struct Sfm_File : Gme_Info_
|
||||||
hash_sfm_file( data.begin(), data.end() - data.begin(), out );
|
hash_sfm_file( data.begin(), data.end() - data.begin(), out );
|
||||||
return blargg_ok;
|
return blargg_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blargg_err_t save_( gme_writer_t writer, void* your_data )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static Music_Emu* new_sfm_emu () { return BLARGG_NEW Sfm_Emu ; }
|
static Music_Emu* new_sfm_emu () { return BLARGG_NEW Sfm_Emu ; }
|
||||||
|
@ -131,7 +189,15 @@ blargg_err_t Sfm_Emu::load_mem_( byte const in [], int size )
|
||||||
};
|
};
|
||||||
set_voice_names( names );
|
set_voice_names( names );
|
||||||
|
|
||||||
return check_sfm_header( in );
|
RETURN_ERR( check_sfm_header( in ) );
|
||||||
|
|
||||||
|
const byte * ptr = file_begin();
|
||||||
|
int metadata_size = get_le32(ptr + 4);
|
||||||
|
if ( file_size() < metadata_size + Sfm_Emu::sfm_min_file_size )
|
||||||
|
return "SFM file too small";
|
||||||
|
metadata.parseDocument((const char *) ptr + 8, metadata_size);
|
||||||
|
|
||||||
|
return blargg_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emulation
|
// Emulation
|
||||||
|
@ -164,12 +230,7 @@ blargg_err_t Sfm_Emu::start_track_( int track )
|
||||||
resampler.clear();
|
resampler.clear();
|
||||||
filter.clear();
|
filter.clear();
|
||||||
const byte * ptr = file_begin();
|
const byte * ptr = file_begin();
|
||||||
if ( file_size() < Sfm_Emu::sfm_min_file_size )
|
|
||||||
return "SFM file too small";
|
|
||||||
int metadata_size = get_le32(ptr + 4);
|
int metadata_size = get_le32(ptr + 4);
|
||||||
if ( file_size() < metadata_size + Sfm_Emu::sfm_min_file_size )
|
|
||||||
return "SFM file too small";
|
|
||||||
metadata.parseDocument((const char *) ptr + 8, metadata_size);
|
|
||||||
|
|
||||||
memcpy( smp.iplrom, ipl_rom, 64 );
|
memcpy( smp.iplrom, ipl_rom, 64 );
|
||||||
|
|
||||||
|
@ -179,11 +240,17 @@ blargg_err_t Sfm_Emu::start_track_( int track )
|
||||||
|
|
||||||
memcpy( smp.dsp.spc_dsp.m.regs, ptr + 8 + metadata_size + 65536, 128 );
|
memcpy( smp.dsp.spc_dsp.m.regs, ptr + 8 + metadata_size + 65536, 128 );
|
||||||
|
|
||||||
smp.set_sfm_queue( ptr + 8 + metadata_size + 65536 + 128, ptr + file_size() );
|
const uint8_t* log_begin = ptr + 8 + metadata_size + 65536 + 128;
|
||||||
|
const uint8_t* log_end = ptr + file_size();
|
||||||
|
size_t loop_begin = log_end - log_begin;
|
||||||
|
|
||||||
char * end;
|
char * end;
|
||||||
const char * value;
|
const char * value;
|
||||||
|
|
||||||
|
loop_begin = META_ENUM_INT("timing:loopstart", loop_begin);
|
||||||
|
|
||||||
|
smp.set_sfm_queue( log_begin, log_end, log_begin + loop_begin );
|
||||||
|
|
||||||
uint32_t test = META_ENUM_INT("smp:test", 0);
|
uint32_t test = META_ENUM_INT("smp:test", 0);
|
||||||
smp.status.clock_speed = (test >> 6) & 3;
|
smp.status.clock_speed = (test >> 6) & 3;
|
||||||
smp.status.timer_speed = (test >> 4) & 3;
|
smp.status.timer_speed = (test >> 4) & 3;
|
||||||
|
@ -375,32 +442,32 @@ blargg_err_t Sfm_Emu::start_track_( int track )
|
||||||
|
|
||||||
#undef META_ENUM_INT
|
#undef META_ENUM_INT
|
||||||
|
|
||||||
blargg_err_t Sfm_Emu::save( gme_writer_t writer, void* your_data ) const
|
void Sfm_Emu::create_updated_metadata( Bml_Parser &out ) const
|
||||||
{
|
{
|
||||||
bool first;
|
bool first;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
Bml_Parser metadata;
|
|
||||||
const byte * ptr = file_begin();
|
|
||||||
int metadata_size = get_le32(ptr + 4);
|
|
||||||
metadata.parseDocument((const char *) ptr + 8, metadata_size);
|
|
||||||
|
|
||||||
metadata.setValue( "smp:test", (smp.status.clock_speed << 6) | (smp.status.timer_speed << 4) | (smp.status.timers_enable << 3) | (smp.status.ram_disable << 2) | (smp.status.ram_writable << 1) | (smp.status.timers_disable << 0) );
|
metadata.serialize(name);
|
||||||
metadata.setValue( "smp:iplrom", smp.status.iplrom_enable );
|
|
||||||
metadata.setValue( "smp:dspaddr", smp.status.dsp_addr );
|
out.parseDocument(name.c_str());
|
||||||
|
|
||||||
|
out.setValue( "smp:test", (smp.status.clock_speed << 6) | (smp.status.timer_speed << 4) | (smp.status.timers_enable << 3) | (smp.status.ram_disable << 2) | (smp.status.ram_writable << 1) | (smp.status.timers_disable << 0) );
|
||||||
|
out.setValue( "smp:iplrom", smp.status.iplrom_enable );
|
||||||
|
out.setValue( "smp:dspaddr", smp.status.dsp_addr );
|
||||||
|
|
||||||
oss.str("");
|
oss.str("");
|
||||||
oss.clear();
|
oss.clear();
|
||||||
oss << smp.status.ram00f8 << "," << smp.status.ram00f9;
|
oss << smp.status.ram00f8 << "," << smp.status.ram00f9;
|
||||||
metadata.setValue( "smp:ram", oss.str().c_str() );
|
out.setValue( "smp:ram", oss.str().c_str() );
|
||||||
|
|
||||||
name = "smp:regs:";
|
name = "smp:regs:";
|
||||||
metadata.setValue( name + "pc", smp.regs.pc );
|
out.setValue( name + "pc", smp.regs.pc );
|
||||||
metadata.setValue( name + "a", smp.regs.a );
|
out.setValue( name + "a", smp.regs.a );
|
||||||
metadata.setValue( name + "x", smp.regs.x );
|
out.setValue( name + "x", smp.regs.x );
|
||||||
metadata.setValue( name + "y", smp.regs.y );
|
out.setValue( name + "y", smp.regs.y );
|
||||||
metadata.setValue( name + "s", smp.regs.s );
|
out.setValue( name + "s", smp.regs.s );
|
||||||
metadata.setValue( name + "psw", smp.regs.p );
|
out.setValue( name + "psw", smp.regs.p );
|
||||||
|
|
||||||
oss.str("");
|
oss.str("");
|
||||||
oss.clear();
|
oss.clear();
|
||||||
|
@ -411,7 +478,7 @@ blargg_err_t Sfm_Emu::save( gme_writer_t writer, void* your_data ) const
|
||||||
oss << (unsigned long)n;
|
oss << (unsigned long)n;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
metadata.setValue("smp:ports", oss.str().c_str());
|
out.setValue("smp:ports", oss.str().c_str());
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
|
@ -420,19 +487,19 @@ blargg_err_t Sfm_Emu::save( gme_writer_t writer, void* your_data ) const
|
||||||
oss.clear();
|
oss.clear();
|
||||||
oss << "smp:timer[" << i << "]:";
|
oss << "smp:timer[" << i << "]:";
|
||||||
name = oss.str();
|
name = oss.str();
|
||||||
metadata.setValue( name + "enable", t.enable );
|
out.setValue( name + "enable", t.enable );
|
||||||
metadata.setValue( name + "target", t.target );
|
out.setValue( name + "target", t.target );
|
||||||
oss.str("");
|
oss.str("");
|
||||||
oss.clear();
|
oss.clear();
|
||||||
oss << (unsigned long)t.stage0_ticks << "," << (unsigned long)t.stage1_ticks << ","
|
oss << (unsigned long)t.stage0_ticks << "," << (unsigned long)t.stage1_ticks << ","
|
||||||
<< (unsigned long)t.stage2_ticks << "," << (unsigned long)t.stage3_ticks;
|
<< (unsigned long)t.stage2_ticks << "," << (unsigned long)t.stage3_ticks;
|
||||||
metadata.setValue( name + "stage", oss.str().c_str() );
|
out.setValue( name + "stage", oss.str().c_str() );
|
||||||
metadata.setValue( name + "line", t.current_line );
|
out.setValue( name + "line", t.current_line );
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata.setValue( "dsp:clock", smp.dsp.clock / 4096 );
|
out.setValue( "dsp:clock", smp.dsp.clock / 4096 );
|
||||||
|
|
||||||
metadata.setValue( "dsp:echohistaddr", smp.dsp.spc_dsp.m.echo_hist_pos - smp.dsp.spc_dsp.m.echo_hist );
|
out.setValue( "dsp:echohistaddr", smp.dsp.spc_dsp.m.echo_hist_pos - smp.dsp.spc_dsp.m.echo_hist );
|
||||||
|
|
||||||
oss.str("");
|
oss.str("");
|
||||||
oss.clear();
|
oss.clear();
|
||||||
|
@ -442,41 +509,41 @@ blargg_err_t Sfm_Emu::save( gme_writer_t writer, void* your_data ) const
|
||||||
<< smp.dsp.spc_dsp.m.echo_hist[i][1];
|
<< smp.dsp.spc_dsp.m.echo_hist[i][1];
|
||||||
if ( i != 7 ) oss << ",";
|
if ( i != 7 ) oss << ",";
|
||||||
}
|
}
|
||||||
metadata.setValue( "dsp:echohistdata", oss.str().c_str() );
|
out.setValue( "dsp:echohistdata", oss.str().c_str() );
|
||||||
|
|
||||||
metadata.setValue( "dsp:sample", smp.dsp.spc_dsp.m.phase );
|
out.setValue( "dsp:sample", smp.dsp.spc_dsp.m.phase );
|
||||||
metadata.setValue( "dsp:kon", smp.dsp.spc_dsp.m.kon );
|
out.setValue( "dsp:kon", smp.dsp.spc_dsp.m.kon );
|
||||||
metadata.setValue( "dsp:noise", smp.dsp.spc_dsp.m.noise );
|
out.setValue( "dsp:noise", smp.dsp.spc_dsp.m.noise );
|
||||||
metadata.setValue( "dsp:counter", smp.dsp.spc_dsp.m.counter );
|
out.setValue( "dsp:counter", smp.dsp.spc_dsp.m.counter );
|
||||||
metadata.setValue( "dsp:echooffset", smp.dsp.spc_dsp.m.echo_offset );
|
out.setValue( "dsp:echooffset", smp.dsp.spc_dsp.m.echo_offset );
|
||||||
metadata.setValue( "dsp:echolength", smp.dsp.spc_dsp.m.echo_length );
|
out.setValue( "dsp:echolength", smp.dsp.spc_dsp.m.echo_length );
|
||||||
metadata.setValue( "dsp:koncache", smp.dsp.spc_dsp.m.new_kon );
|
out.setValue( "dsp:koncache", smp.dsp.spc_dsp.m.new_kon );
|
||||||
metadata.setValue( "dsp:endx", smp.dsp.spc_dsp.m.endx_buf );
|
out.setValue( "dsp:endx", smp.dsp.spc_dsp.m.endx_buf );
|
||||||
metadata.setValue( "dsp:envx", smp.dsp.spc_dsp.m.envx_buf );
|
out.setValue( "dsp:envx", smp.dsp.spc_dsp.m.envx_buf );
|
||||||
metadata.setValue( "dsp:outx", smp.dsp.spc_dsp.m.outx_buf );
|
out.setValue( "dsp:outx", smp.dsp.spc_dsp.m.outx_buf );
|
||||||
metadata.setValue( "dsp:pmon", smp.dsp.spc_dsp.m.t_pmon );
|
out.setValue( "dsp:pmon", smp.dsp.spc_dsp.m.t_pmon );
|
||||||
metadata.setValue( "dsp:non", smp.dsp.spc_dsp.m.t_non );
|
out.setValue( "dsp:non", smp.dsp.spc_dsp.m.t_non );
|
||||||
metadata.setValue( "dsp:eon", smp.dsp.spc_dsp.m.t_eon );
|
out.setValue( "dsp:eon", smp.dsp.spc_dsp.m.t_eon );
|
||||||
metadata.setValue( "dsp:dir", smp.dsp.spc_dsp.m.t_dir );
|
out.setValue( "dsp:dir", smp.dsp.spc_dsp.m.t_dir );
|
||||||
metadata.setValue( "dsp:koff", smp.dsp.spc_dsp.m.t_koff );
|
out.setValue( "dsp:koff", smp.dsp.spc_dsp.m.t_koff );
|
||||||
metadata.setValue( "dsp:brrnext", smp.dsp.spc_dsp.m.t_brr_next_addr );
|
out.setValue( "dsp:brrnext", smp.dsp.spc_dsp.m.t_brr_next_addr );
|
||||||
metadata.setValue( "dsp:adsr0", smp.dsp.spc_dsp.m.t_adsr0 );
|
out.setValue( "dsp:adsr0", smp.dsp.spc_dsp.m.t_adsr0 );
|
||||||
metadata.setValue( "dsp:brrheader", smp.dsp.spc_dsp.m.t_brr_header );
|
out.setValue( "dsp:brrheader", smp.dsp.spc_dsp.m.t_brr_header );
|
||||||
metadata.setValue( "dsp:brrdata", smp.dsp.spc_dsp.m.t_brr_byte );
|
out.setValue( "dsp:brrdata", smp.dsp.spc_dsp.m.t_brr_byte );
|
||||||
metadata.setValue( "dsp:srcn", smp.dsp.spc_dsp.m.t_srcn );
|
out.setValue( "dsp:srcn", smp.dsp.spc_dsp.m.t_srcn );
|
||||||
metadata.setValue( "dsp:esa", smp.dsp.spc_dsp.m.t_esa );
|
out.setValue( "dsp:esa", smp.dsp.spc_dsp.m.t_esa );
|
||||||
metadata.setValue( "dsp:echodisable", !smp.dsp.spc_dsp.m.t_echo_enabled );
|
out.setValue( "dsp:echodisable", !smp.dsp.spc_dsp.m.t_echo_enabled );
|
||||||
metadata.setValue( "dsp:diraddr", smp.dsp.spc_dsp.m.t_dir_addr );
|
out.setValue( "dsp:diraddr", smp.dsp.spc_dsp.m.t_dir_addr );
|
||||||
metadata.setValue( "dsp:pitch", smp.dsp.spc_dsp.m.t_pitch );
|
out.setValue( "dsp:pitch", smp.dsp.spc_dsp.m.t_pitch );
|
||||||
metadata.setValue( "dsp:output", smp.dsp.spc_dsp.m.t_output );
|
out.setValue( "dsp:output", smp.dsp.spc_dsp.m.t_output );
|
||||||
metadata.setValue( "dsp:looped", smp.dsp.spc_dsp.m.t_looped );
|
out.setValue( "dsp:looped", smp.dsp.spc_dsp.m.t_looped );
|
||||||
metadata.setValue( "dsp:echoaddr", smp.dsp.spc_dsp.m.t_echo_ptr );
|
out.setValue( "dsp:echoaddr", smp.dsp.spc_dsp.m.t_echo_ptr );
|
||||||
|
|
||||||
#define META_WRITE_LEVELS(n, o) \
|
#define META_WRITE_LEVELS(n, o) \
|
||||||
oss.str(""); \
|
oss.str(""); \
|
||||||
oss.clear(); \
|
oss.clear(); \
|
||||||
oss << (o)[0] << "," << (o)[1]; \
|
oss << (o)[0] << "," << (o)[1]; \
|
||||||
metadata.setValue((n), oss.str().c_str());
|
out.setValue((n), oss.str().c_str());
|
||||||
|
|
||||||
META_WRITE_LEVELS("dsp:mainout", smp.dsp.spc_dsp.m.t_main_out);
|
META_WRITE_LEVELS("dsp:mainout", smp.dsp.spc_dsp.m.t_main_out);
|
||||||
META_WRITE_LEVELS("dsp:echoout", smp.dsp.spc_dsp.m.t_echo_out);
|
META_WRITE_LEVELS("dsp:echoout", smp.dsp.spc_dsp.m.t_echo_out);
|
||||||
|
@ -491,7 +558,7 @@ blargg_err_t Sfm_Emu::save( gme_writer_t writer, void* your_data ) const
|
||||||
oss << "dsp:voice[" << i << "]:";
|
oss << "dsp:voice[" << i << "]:";
|
||||||
name = oss.str();
|
name = oss.str();
|
||||||
SuperFamicom::SPC_DSP::voice_t const& voice = smp.dsp.spc_dsp.m.voices[i];
|
SuperFamicom::SPC_DSP::voice_t const& voice = smp.dsp.spc_dsp.m.voices[i];
|
||||||
metadata.setValue( name + "brrhistaddr", voice.buf_pos );
|
out.setValue( name + "brrhistaddr", voice.buf_pos );
|
||||||
oss.str("");
|
oss.str("");
|
||||||
oss.clear();
|
oss.clear();
|
||||||
for (int j = 0; j < SuperFamicom::SPC_DSP::brr_buf_size; ++j)
|
for (int j = 0; j < SuperFamicom::SPC_DSP::brr_buf_size; ++j)
|
||||||
|
@ -500,29 +567,36 @@ blargg_err_t Sfm_Emu::save( gme_writer_t writer, void* your_data ) const
|
||||||
if ( j != SuperFamicom::SPC_DSP::brr_buf_size - 1 )
|
if ( j != SuperFamicom::SPC_DSP::brr_buf_size - 1 )
|
||||||
oss << ",";
|
oss << ",";
|
||||||
}
|
}
|
||||||
metadata.setValue( name + "brrhistdata", oss.str().c_str() );
|
out.setValue( name + "brrhistdata", oss.str().c_str() );
|
||||||
metadata.setValue( name + "interpaddr", voice.interp_pos );
|
out.setValue( name + "interpaddr", voice.interp_pos );
|
||||||
metadata.setValue( name + "brraddr", voice.brr_addr );
|
out.setValue( name + "brraddr", voice.brr_addr );
|
||||||
metadata.setValue( name + "brroffset", voice.brr_offset );
|
out.setValue( name + "brroffset", voice.brr_offset );
|
||||||
metadata.setValue( name + "vbit", voice.vbit );
|
out.setValue( name + "vbit", voice.vbit );
|
||||||
metadata.setValue( name + "vidx", voice.regs - smp.dsp.spc_dsp.m.regs);
|
out.setValue( name + "vidx", voice.regs - smp.dsp.spc_dsp.m.regs);
|
||||||
metadata.setValue( name + "kondelay", voice.kon_delay );
|
out.setValue( name + "kondelay", voice.kon_delay );
|
||||||
metadata.setValue( name + "envmode", voice.env_mode );
|
out.setValue( name + "envmode", voice.env_mode );
|
||||||
metadata.setValue( name + "env", voice.env );
|
out.setValue( name + "env", voice.env );
|
||||||
metadata.setValue( name + "envxout", voice.t_envx_out );
|
out.setValue( name + "envxout", voice.t_envx_out );
|
||||||
metadata.setValue( name + "envcache", voice.hidden_env );
|
out.setValue( name + "envcache", voice.hidden_env );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata.serialize( name );
|
blargg_err_t Sfm_Emu::save_( gme_writer_t writer, void* your_data ) const
|
||||||
|
{
|
||||||
|
std::string meta_serialized;
|
||||||
|
|
||||||
|
Bml_Parser metadata;
|
||||||
|
create_updated_metadata( metadata );
|
||||||
|
metadata.serialize( meta_serialized );
|
||||||
|
|
||||||
RETURN_ERR( writer( your_data, "SFM1", 4 ) );
|
RETURN_ERR( writer( your_data, "SFM1", 4 ) );
|
||||||
|
|
||||||
uint8_t temp[4];
|
uint8_t temp[4];
|
||||||
uint32_t meta_length = (uint32_t) name.length();
|
uint32_t meta_length = (uint32_t) meta_serialized.length();
|
||||||
set_le32( temp, meta_length );
|
set_le32( temp, meta_length );
|
||||||
RETURN_ERR( writer( your_data, temp, 4 ) );
|
RETURN_ERR( writer( your_data, temp, 4 ) );
|
||||||
|
|
||||||
RETURN_ERR( writer( your_data, name.c_str(), meta_length ) );
|
RETURN_ERR( writer( your_data, meta_serialized.c_str(), meta_length ) );
|
||||||
|
|
||||||
RETURN_ERR( writer( your_data, smp.apuram, 65536 ) );
|
RETURN_ERR( writer( your_data, smp.apuram, 65536 ) );
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,6 @@ public:
|
||||||
|
|
||||||
static gme_type_t static_type() { return gme_sfm_type; }
|
static gme_type_t static_type() { return gme_sfm_type; }
|
||||||
|
|
||||||
virtual blargg_err_t save( gme_writer_t, void* ) const;
|
|
||||||
|
|
||||||
// Implementation
|
// Implementation
|
||||||
public:
|
public:
|
||||||
Sfm_Emu();
|
Sfm_Emu();
|
||||||
|
@ -53,12 +51,14 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual blargg_err_t load_mem_( byte const [], int );
|
virtual blargg_err_t load_mem_( byte const [], int );
|
||||||
virtual blargg_err_t track_info_( track_info_t*, int track ) const;
|
virtual blargg_err_t track_info_( track_info_t*, int track ) const;
|
||||||
|
virtual blargg_err_t set_track_info_( const track_info_t*, int track );
|
||||||
virtual blargg_err_t set_sample_rate_( int );
|
virtual blargg_err_t set_sample_rate_( int );
|
||||||
virtual blargg_err_t start_track_( int );
|
virtual blargg_err_t start_track_( int );
|
||||||
virtual blargg_err_t play_( int, sample_t [] );
|
virtual blargg_err_t play_( int, sample_t [] );
|
||||||
virtual blargg_err_t skip_( int );
|
virtual blargg_err_t skip_( int );
|
||||||
virtual void mute_voices_( int );
|
virtual void mute_voices_( int );
|
||||||
virtual void set_tempo_( double );
|
virtual void set_tempo_( double );
|
||||||
|
virtual blargg_err_t save_( gme_writer_t, void* ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Spc_Emu_Resampler resampler;
|
Spc_Emu_Resampler resampler;
|
||||||
|
@ -66,6 +66,7 @@ private:
|
||||||
SuperFamicom::SMP smp;
|
SuperFamicom::SMP smp;
|
||||||
|
|
||||||
Bml_Parser metadata;
|
Bml_Parser metadata;
|
||||||
|
void create_updated_metadata(Bml_Parser &out) const;
|
||||||
|
|
||||||
blargg_err_t play_and_filter( int count, sample_t out [] );
|
blargg_err_t play_and_filter( int count, sample_t out [] );
|
||||||
};
|
};
|
||||||
|
|
|
@ -224,6 +224,8 @@ void gme_delete( Music_Emu* gme ) { delete gme; }
|
||||||
|
|
||||||
gme_type_t gme_type( Music_Emu const* gme ) { return gme->type(); }
|
gme_type_t gme_type( Music_Emu const* gme ) { return gme->type(); }
|
||||||
|
|
||||||
|
const char* gme_type_system( gme_type_t_ const* type ) { return type->system; }
|
||||||
|
|
||||||
const char* gme_warning( Music_Emu* gme ) { return gme->warning(); }
|
const char* gme_warning( Music_Emu* gme ) { return gme->warning(); }
|
||||||
|
|
||||||
int gme_track_count( Music_Emu const* gme ) { return gme->track_count(); }
|
int gme_track_count( Music_Emu const* gme ) { return gme->track_count(); }
|
||||||
|
@ -301,6 +303,37 @@ gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, int track )
|
||||||
return blargg_ok;
|
return blargg_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gme_err_t gme_set_track_info( Music_Emu * me, gme_info_t* in, int track )
|
||||||
|
{
|
||||||
|
track_info_t* info = BLARGG_NEW track_info_t;
|
||||||
|
CHECK_ALLOC( info );
|
||||||
|
|
||||||
|
#define COPY(name) info->name = in->name;
|
||||||
|
|
||||||
|
COPY( length );
|
||||||
|
COPY( intro_length );
|
||||||
|
COPY( loop_length );
|
||||||
|
|
||||||
|
#undef COPY
|
||||||
|
#define COPY(name) if ( in->name ) strncpy( info->name, in->name, sizeof(info->name) - 1 ), info->name[sizeof(info->name)-1] = '\0'; else info->name[0] = '\0';
|
||||||
|
|
||||||
|
COPY( system );
|
||||||
|
COPY( game );
|
||||||
|
COPY( song );
|
||||||
|
COPY( author );
|
||||||
|
COPY( copyright );
|
||||||
|
COPY( comment );
|
||||||
|
COPY( dumper );
|
||||||
|
|
||||||
|
#undef COPY
|
||||||
|
|
||||||
|
blargg_err_t err = me->set_track_info( info, track );
|
||||||
|
|
||||||
|
delete info;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
void gme_free_info( gme_info_t* info )
|
void gme_free_info( gme_info_t* info )
|
||||||
{
|
{
|
||||||
delete STATIC_CAST(gme_info_t_*,info);
|
delete STATIC_CAST(gme_info_t_*,info);
|
||||||
|
@ -316,6 +349,7 @@ void gme_set_fade ( Music_Emu* gme, int start_msec, int length_msec )
|
||||||
gme_bool gme_track_ended ( Music_Emu const* gme ) { return gme->track_ended(); }
|
gme_bool gme_track_ended ( Music_Emu const* gme ) { return gme->track_ended(); }
|
||||||
int gme_tell ( Music_Emu const* gme ) { return gme->tell(); }
|
int gme_tell ( Music_Emu const* gme ) { return gme->tell(); }
|
||||||
gme_err_t gme_seek ( Music_Emu* gme, int msec ) { return gme->seek( msec ); }
|
gme_err_t gme_seek ( Music_Emu* gme, int msec ) { return gme->seek( msec ); }
|
||||||
|
gme_err_t gme_skip ( Music_Emu* gme, int samples ) { return gme->skip( samples ); }
|
||||||
int gme_voice_count ( Music_Emu const* gme ) { return gme->voice_count(); }
|
int gme_voice_count ( Music_Emu const* gme ) { return gme->voice_count(); }
|
||||||
void gme_ignore_silence ( Music_Emu* gme, gme_bool disable ) { gme->ignore_silence( disable != 0 ); }
|
void gme_ignore_silence ( Music_Emu* gme, gme_bool disable ) { gme->ignore_silence( disable != 0 ); }
|
||||||
void gme_set_tempo ( Music_Emu* gme, double t ) { gme->set_tempo( t ); }
|
void gme_set_tempo ( Music_Emu* gme, double t ) { gme->set_tempo( t ); }
|
||||||
|
|
|
@ -55,6 +55,9 @@ int gme_tell( const gme_t* );
|
||||||
/* Seeks to new time in track. Seeking backwards or far forward can take a while. */
|
/* Seeks to new time in track. Seeking backwards or far forward can take a while. */
|
||||||
gme_err_t gme_seek( gme_t*, int msec );
|
gme_err_t gme_seek( gme_t*, int msec );
|
||||||
|
|
||||||
|
/* Skips the specified number of samples. */
|
||||||
|
gme_err_t gme_skip( gme_t*, int samples );
|
||||||
|
|
||||||
|
|
||||||
/******** Informational ********/
|
/******** Informational ********/
|
||||||
|
|
||||||
|
@ -78,6 +81,8 @@ Must be freed after use. */
|
||||||
typedef struct gme_info_t gme_info_t;
|
typedef struct gme_info_t gme_info_t;
|
||||||
gme_err_t gme_track_info( const gme_t*, gme_info_t** out, int track );
|
gme_err_t gme_track_info( const gme_t*, gme_info_t** out, int track );
|
||||||
|
|
||||||
|
gme_err_t gme_set_track_info( gme_t*, const gme_info_t* in, int track );
|
||||||
|
|
||||||
/* Frees track information */
|
/* Frees track information */
|
||||||
void gme_free_info( gme_info_t* );
|
void gme_free_info( gme_info_t* );
|
||||||
|
|
||||||
|
|
|
@ -22,14 +22,6 @@ void SMP::port_write(uint8_t port, uint8_t data) {
|
||||||
uint8_t SMP::op_busread(uint16_t addr) {
|
uint8_t SMP::op_busread(uint16_t addr) {
|
||||||
unsigned result;
|
unsigned result;
|
||||||
|
|
||||||
if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) ) {
|
|
||||||
int start = 0x100 * dsp.read( SPC_DSP::r_esa );
|
|
||||||
int end = start + 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F);
|
|
||||||
if ( end > 0x10000 )
|
|
||||||
end = 0x10000;
|
|
||||||
if ( addr >= start || addr < end) synchronize_dsp();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
case 0xf0: //TEST -- write-only register
|
case 0xf0: //TEST -- write-only register
|
||||||
return 0x00;
|
return 0x00;
|
||||||
|
@ -42,7 +34,6 @@ uint8_t SMP::op_busread(uint16_t addr) {
|
||||||
|
|
||||||
case 0xf3: //DSPDATA
|
case 0xf3: //DSPDATA
|
||||||
//0x80-0xff are read-only mirrors of 0x00-0x7f
|
//0x80-0xff are read-only mirrors of 0x00-0x7f
|
||||||
synchronize_dsp();
|
|
||||||
return dsp.read(status.dsp_addr & 0x7f);
|
return dsp.read(status.dsp_addr & 0x7f);
|
||||||
|
|
||||||
case 0xf4: //CPUIO0
|
case 0xf4: //CPUIO0
|
||||||
|
@ -50,8 +41,11 @@ uint8_t SMP::op_busread(uint16_t addr) {
|
||||||
case 0xf6: //CPUIO2
|
case 0xf6: //CPUIO2
|
||||||
case 0xf7: //CPUIO3
|
case 0xf7: //CPUIO3
|
||||||
if (sfm_queue && sfm_queue < sfm_queue_end) {
|
if (sfm_queue && sfm_queue < sfm_queue_end) {
|
||||||
sfm_last[addr - 0xf4] = *sfm_queue;
|
result = *sfm_queue;
|
||||||
return *sfm_queue++;
|
if (++sfm_queue == sfm_queue_end)
|
||||||
|
sfm_queue = sfm_queue_repeat;
|
||||||
|
sfm_last[addr - 0xf4] = result;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return sfm_last[addr - 0xf4];
|
return sfm_last[addr - 0xf4];
|
||||||
|
|
||||||
|
@ -86,7 +80,6 @@ uint8_t SMP::op_busread(uint16_t addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::op_buswrite(uint16_t addr, uint8_t data) {
|
void SMP::op_buswrite(uint16_t addr, uint8_t data) {
|
||||||
synchronize_dsp();
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
case 0xf0: //TEST
|
case 0xf0: //TEST
|
||||||
if(regs.p.p) break; //writes only valid when P flag is clear
|
if(regs.p.p) break; //writes only valid when P flag is clear
|
||||||
|
|
|
@ -139,7 +139,7 @@ void SMP::reset() {
|
||||||
|
|
||||||
SMP::SMP() : dsp( *this ), timer0( *this ), timer1( *this ), timer2( *this ), clock( 0 ) {
|
SMP::SMP() : dsp( *this ), timer0( *this ), timer1( *this ), timer2( *this ), clock( 0 ) {
|
||||||
for(auto& byte : iplrom) byte = 0;
|
for(auto& byte : iplrom) byte = 0;
|
||||||
set_sfm_queue(0, 0);
|
set_sfm_queue(0, 0, 0);
|
||||||
set_tempo(1.0);
|
set_tempo(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,9 @@ struct SMP : Processor::SPC700 {
|
||||||
private:
|
private:
|
||||||
uint8_t const* sfm_queue;
|
uint8_t const* sfm_queue;
|
||||||
uint8_t const* sfm_queue_end;
|
uint8_t const* sfm_queue_end;
|
||||||
|
uint8_t const* sfm_queue_repeat;
|
||||||
public:
|
public:
|
||||||
void set_sfm_queue(const uint8_t* queue, const uint8_t* queue_end);
|
void set_sfm_queue(const uint8_t* queue, const uint8_t* queue_end, const uint8_t* queue_repeat);
|
||||||
|
|
||||||
const uint8_t* get_sfm_queue() const;
|
const uint8_t* get_sfm_queue() const;
|
||||||
size_t get_sfm_queue_remain() const;
|
size_t get_sfm_queue_remain() const;
|
||||||
|
@ -120,7 +121,7 @@ public:
|
||||||
|
|
||||||
inline void SMP::set_tempo(double speed) { dsp_clock_step = (int64_t)(4096.0 / speed); }
|
inline void SMP::set_tempo(double speed) { dsp_clock_step = (int64_t)(4096.0 / speed); }
|
||||||
|
|
||||||
inline void SMP::set_sfm_queue(const uint8_t *queue, const uint8_t *queue_end) { sfm_queue = queue; sfm_queue_end = queue_end; sfm_last[0] = 0; sfm_last[1] = 0; sfm_last[2] = 0; sfm_last[3] = 0; }
|
inline void SMP::set_sfm_queue(const uint8_t *queue, const uint8_t *queue_end, const uint8_t *queue_repeat) { sfm_queue = queue; sfm_queue_end = queue_end; sfm_queue_repeat = queue_repeat; sfm_last[0] = 0; sfm_last[1] = 0; sfm_last[2] = 0; sfm_last[3] = 0; }
|
||||||
|
|
||||||
inline const uint8_t* SMP::get_sfm_queue() const { return sfm_queue; }
|
inline const uint8_t* SMP::get_sfm_queue() const { return sfm_queue; }
|
||||||
inline size_t SMP::get_sfm_queue_remain() const { return sfm_queue_end - sfm_queue; }
|
inline size_t SMP::get_sfm_queue_remain() const { return sfm_queue_end - sfm_queue; }
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
void SMP::add_clocks(unsigned clocks) {
|
void SMP::add_clocks(unsigned clocks) {
|
||||||
step(clocks);
|
step(clocks);
|
||||||
//synchronize_dsp();
|
synchronize_dsp();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMP::cycle_edge() {
|
void SMP::cycle_edge() {
|
||||||
|
|
Loading…
Reference in New Issue