Mercurial > audlegacy-plugins
diff src/console/Nsfe_Emu.cxx @ 316:fb513e10174e trunk
[svn] - merge libconsole-blargg into mainline libconsole:
+ obsoletes plugins-ugly:sapplug
author | nenolod |
---|---|
date | Thu, 30 Nov 2006 19:54:33 -0800 |
parents | 4ddab3548cd0 |
children | 31c9d8f37474 |
line wrap: on
line diff
--- a/src/console/Nsfe_Emu.cxx Wed Nov 29 14:42:11 2006 -0800 +++ b/src/console/Nsfe_Emu.cxx Thu Nov 30 19:54:33 2006 -0800 @@ -1,10 +1,10 @@ - -// Game_Music_Emu 0.3.0. http://www.slack.net/~ant/ +// Game_Music_Emu 0.5.1. http://www.slack.net/~ant/ #include "Nsfe_Emu.h" #include "blargg_endian.h" #include <string.h> +#include <ctype.h> /* Copyright (C) 2005-2006 Shay Green. This module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser @@ -12,84 +12,61 @@ version 2.1 of the License, or (at your option) any later version. This module is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for -more details. You should have received a copy of the GNU Lesser General -Public License along with this module; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include BLARGG_SOURCE_BEGIN +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#define NSFE_TAG( a, b, c, d ) (d*0x1000000L + c*0x10000L + b*0x100L + a) +#include "blargg_source.h" -Nsfe_Info::Nsfe_Info() -{ - playlist_enabled = false; -} +Nsfe_Info::Nsfe_Info() { playlist_disabled = false; } Nsfe_Info::~Nsfe_Info() { } -void Nsfe_Info::enable_playlist( bool b ) -{ - playlist_enabled = b; - info_.track_count = (b && playlist_size()) ? playlist_size() : track_count_; -} - -int Nsfe_Info::remap_track( int i ) const +inline void Nsfe_Info::unload() { - if ( !playlist_enabled || !playlist_size() ) - return i; - - return playlist_entry( i ); -} - -void Nsfe_Emu::start_track( int i ) -{ - Nsf_Emu::start_track( remap_track( i ) ); + track_name_data.clear(); + track_names.clear(); + playlist.clear(); + track_times.clear(); } -const char* Nsfe_Info::track_name( unsigned i ) const +// TODO: if no playlist, treat as if there is a playlist that is just 1,2,3,4,5... ? +void Nsfe_Info::disable_playlist( bool b ) { - i = remap_track( i ); - if ( i < track_names.size() ) - return track_names [i]; - - return ""; + playlist_disabled = b; + info.track_count = playlist.size(); + if ( !info.track_count || playlist_disabled ) + info.track_count = actual_track_count_; } -long Nsfe_Info::track_time( unsigned i ) const +int Nsfe_Info::remap_track( int track ) const { - i = remap_track( i ); - if ( i < track_times.size() ) - return track_times [i]; - - return 0; -} - -// Read little-endian 32-bit int -static blargg_err_t read_le32( Emu_Reader& in, long* out ) -{ - unsigned char buf [4]; - BLARGG_RETURN_ERR( in.read( buf, sizeof buf ) ); - *out = get_le32( buf ); - return blargg_success; + if ( !playlist_disabled && (unsigned) track < playlist.size() ) + track = playlist [track]; + return track; } // Read multiple strings and separate into individual strings -static blargg_err_t read_strs( Emu_Reader& in, long size, std::vector<char>& chars, - std::vector<const char*>& strs ) +static blargg_err_t read_strs( Data_Reader& in, long size, blargg_vector<char>& chars, + blargg_vector<const char*>& strs ) { - chars.resize( size + 1 ); + RETURN_ERR( chars.resize( size + 1 ) ); chars [size] = 0; // in case last string doesn't have terminator - BLARGG_RETURN_ERR( in.read( &chars [0], size ) ); + RETURN_ERR( in.read( &chars [0], size ) ); + RETURN_ERR( strs.resize( 128 ) ); + int count = 0; for ( int i = 0; i < size; i++ ) { - strs.push_back( &chars [i] ); + if ( (int) strs.size() <= count ) + RETURN_ERR( strs.resize( count * 2 ) ); + strs [count++] = &chars [i]; while ( i < size && chars [i] ) i++; } - return blargg_success; + return strs.resize( count ); } // Copy in to out, where out has out_max characters allocated. Truncate to @@ -100,21 +77,28 @@ strncpy( out, in, out_max - 1 ); } -struct nsfe_info_t { - unsigned char load_addr [2]; - unsigned char init_addr [2]; - unsigned char play_addr [2]; - unsigned char speed_flags; - unsigned char chip_flags; - unsigned char track_count; - unsigned char first_track; +struct nsfe_info_t +{ + byte load_addr [2]; + byte init_addr [2]; + byte play_addr [2]; + byte speed_flags; + byte chip_flags; + byte track_count; + byte first_track; + byte unused [6]; }; +BOOST_STATIC_ASSERT( sizeof (nsfe_info_t) == 16 ); -blargg_err_t Nsfe_Info::load( const header_t& nsfe_tag, Emu_Reader& in, Nsf_Emu* nsf_emu ) +blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu ) { // check header - if ( memcmp( nsfe_tag.tag, "NSFE", 4 ) ) - return "Not an NSFE file"; + byte signature [4]; + blargg_err_t err = in.read( signature, sizeof signature ); + if ( err ) + return (err == in.eof_error ? gme_wrong_file_type : err); + if ( memcmp( signature, "NSFE", 4 ) ) + return gme_wrong_file_type; // free previous info track_name_data.clear(); @@ -136,7 +120,7 @@ 0, 0, // flags {0,0,0,0} // unused }; - Nsf_Emu::header_t& header = info_; + Nsf_Emu::header_t& header = info; header = base_header; // parse tags @@ -144,83 +128,82 @@ while ( phase != 3 ) { // read size and tag - long size = 0; - long tag = 0; - BLARGG_RETURN_ERR( read_le32( in, &size ) ); - BLARGG_RETURN_ERR( read_le32( in, &tag ) ); + byte block_header [2] [4]; + RETURN_ERR( in.read( block_header, sizeof block_header ) ); + blargg_long size = get_le32( block_header [0] ); + blargg_long tag = get_le32( block_header [1] ); + + //dprintf( "tag: %c%c%c%c\n", char(tag), char(tag>>8), char(tag>>16), char(tag>>24) ); switch ( tag ) { - case NSFE_TAG('I','N','F','O'): { + case BLARGG_4CHAR('O','F','N','I'): { check( phase == 0 ); if ( size < 8 ) - return "Bad NSFE file"; + return "Corrupt file"; - nsfe_info_t info; - info.track_count = 1; - info.first_track = 0; + nsfe_info_t finfo; + finfo.track_count = 1; + finfo.first_track = 0; - int s = size; - if ( s > (int) sizeof info ) - s = sizeof info; - BLARGG_RETURN_ERR( in.read( &info, s ) ); - BLARGG_RETURN_ERR( in.skip( size - s ) ); + RETURN_ERR( in.read( &finfo, min( size, (blargg_long) sizeof finfo ) ) ); + if ( size > (int) sizeof finfo ) + RETURN_ERR( in.skip( size - sizeof finfo ) ); phase = 1; - info_.speed_flags = info.speed_flags; - info_.chip_flags = info.chip_flags; - info_.track_count = info.track_count; - this->track_count_ = info.track_count; - info_.first_track = info.first_track; - std::memcpy( info_.load_addr, info.load_addr, 2 * 3 ); + info.speed_flags = finfo.speed_flags; + info.chip_flags = finfo.chip_flags; + info.track_count = finfo.track_count; + this->actual_track_count_ = finfo.track_count; + info.first_track = finfo.first_track; + memcpy( info.load_addr, finfo.load_addr, 2 * 3 ); break; } - case NSFE_TAG('B','A','N','K'): - if ( size > (int) sizeof info_.banks ) - return "Bad NSFE file"; - BLARGG_RETURN_ERR( in.read( info_.banks, size ) ); + case BLARGG_4CHAR('K','N','A','B'): + if ( size > (int) sizeof info.banks ) + return "Corrupt file"; + RETURN_ERR( in.read( info.banks, size ) ); break; - case NSFE_TAG('a','u','t','h'): { - std::vector<char> chars; - std::vector<const char*> strs; - BLARGG_RETURN_ERR( read_strs( in, size, chars, strs ) ); + case BLARGG_4CHAR('h','t','u','a'): { + blargg_vector<char> chars; + blargg_vector<const char*> strs; + RETURN_ERR( read_strs( in, size, chars, strs ) ); int n = strs.size(); if ( n > 3 ) - copy_str( strs [3], info_.ripper, sizeof info_.ripper ); + copy_str( strs [3], info.dumper, sizeof info.dumper ); if ( n > 2 ) - copy_str( strs [2], info_.copyright, sizeof info_.copyright ); + copy_str( strs [2], info.copyright, sizeof info.copyright ); if ( n > 1 ) - copy_str( strs [1], info_.author, sizeof info_.author ); + copy_str( strs [1], info.author, sizeof info.author ); if ( n > 0 ) - copy_str( strs [0], info_.game, sizeof info_.game ); + copy_str( strs [0], info.game, sizeof info.game ); break; } - case NSFE_TAG('t','i','m','e'): { - track_times.resize( size / 4 ); - for ( unsigned i = 0; i < track_times.size(); i++ ) - BLARGG_RETURN_ERR( read_le32( in, &track_times [i] ) ); + case BLARGG_4CHAR('e','m','i','t'): + RETURN_ERR( track_times.resize( size / 4 ) ); + RETURN_ERR( in.read( track_times.begin(), track_times.size() * 4 ) ); break; - } - case NSFE_TAG('t','l','b','l'): - BLARGG_RETURN_ERR( read_strs( in, size, track_name_data, track_names ) ); + case BLARGG_4CHAR('l','b','l','t'): + RETURN_ERR( read_strs( in, size, track_name_data, track_names ) ); break; - case NSFE_TAG('p','l','s','t'): - playlist.resize( size ); - BLARGG_RETURN_ERR( in.read( &playlist [0], size ) ); + case BLARGG_4CHAR('t','s','l','p'): + RETURN_ERR( playlist.resize( size ) ); + RETURN_ERR( in.read( &playlist [0], size ) ); break; - case NSFE_TAG('D','A','T','A'): { + case BLARGG_4CHAR('A','T','A','D'): { check( phase == 1 ); phase = 2; + disable_playlist( false ); if ( !nsf_emu ) { in.skip( size ); @@ -228,41 +211,118 @@ else { Subset_Reader sub( &in, size ); // limit emu to nsf data - BLARGG_RETURN_ERR( nsf_emu->load( info_, sub ) ); - check( sub.remain() == 0 ); + Remaining_Reader rem( &header, sizeof header, &sub ); + RETURN_ERR( nsf_emu->load( rem ) ); + check( rem.remain() == 0 ); } + disable_playlist( false ); // TODO: fix this crappy hack (unload() disables playlist) break; } - case NSFE_TAG('N','E','N','D'): + case BLARGG_4CHAR('D','N','E','N'): check( phase == 2 ); phase = 3; break; default: // tags that can be skipped start with a lowercase character - check( std::islower( (tag >> 24) & 0xff ) ); - BLARGG_RETURN_ERR( in.skip( size ) ); + check( islower( (tag >> 24) & 0xFF ) ); + RETURN_ERR( in.skip( size ) ); break; } } - enable_playlist( playlist_enabled ); + return 0; +} + +blargg_err_t Nsfe_Info::track_info_( track_info_t* out, int track ) const +{ + int remapped = remap_track( track ); + if ( (unsigned) remapped < track_times.size() ) + { + long length = (BOOST::int32_t) get_le32( track_times [remapped] ); + if ( length > 0 ) + out->length = length; + } + if ( (unsigned) remapped < track_names.size() ) + Gme_File::copy_field_( out->song, track_names [remapped] ); - return blargg_success; + GME_COPY_FIELD( info, out, game ); + GME_COPY_FIELD( info, out, author ); + GME_COPY_FIELD( info, out, copyright ); + GME_COPY_FIELD( info, out, dumper ); + return 0; +} + +Nsfe_Emu::Nsfe_Emu() +{ + loading = false; + set_type( gme_nsfe_type ); +} + +Nsfe_Emu::~Nsfe_Emu() { } + +void Nsfe_Emu::unload() +{ + if ( !loading ) + info.unload(); // TODO: extremely hacky! + Nsf_Emu::unload(); +} + +blargg_err_t Nsfe_Emu::track_info_( track_info_t* out, int track ) const +{ + return info.track_info_( out, track ); } -blargg_err_t Nsfe_Info::load( Emu_Reader& in, Nsf_Emu* nsf_emu ) +struct Nsfe_File : Gme_Info_ { - header_t h; - BLARGG_RETURN_ERR( in.read( &h, sizeof h ) ); - return load( h, in, nsf_emu ); + Nsfe_Info info; + + Nsfe_File() { set_type( gme_nsfe_type ); } + + blargg_err_t load_( Data_Reader& in ) + { + RETURN_ERR( info.load( in, 0 ) ); + set_track_count( info.info.track_count ); + return 0; + } + + blargg_err_t track_info_( track_info_t* out, int track ) const + { + return info.track_info_( out, track ); + } +}; + +static Music_Emu* new_nsfe_emu () { return BLARGG_NEW Nsfe_Emu ; } +static Music_Emu* new_nsfe_file() { return BLARGG_NEW Nsfe_File; } + +gme_type_t_ const gme_nsfe_type [1] = { "Nintendo NES", 0, &new_nsfe_emu, &new_nsfe_file, "NSFE", 1 }; + +blargg_err_t Nsfe_Emu::load_( Data_Reader& in ) +{ + if ( loading ) + return Nsf_Emu::load_( in ); + + // TODO: this hacky recursion-avoidance could have subtle problems + loading = true; + blargg_err_t err = info.load( in, this ); + loading = false; + return err; } -blargg_err_t Nsfe_Info::load_file( const char* path, Nsf_Emu* emu ) +void Nsfe_Emu::disable_playlist( bool b ) { - Std_File_Reader in; - BLARGG_RETURN_ERR( in.open( path ) ); - return load( in, emu ); + info.disable_playlist( b ); + set_track_count( info.info.track_count ); } +void Nsfe_Emu::clear_playlist_() +{ + disable_playlist(); + Nsf_Emu::clear_playlist_(); +} + +blargg_err_t Nsfe_Emu::start_track_( int track ) +{ + return Nsf_Emu::start_track_( info.remap_track( track ) ); +}