From f965bb340bf573e5538b3613c8b957d5b1d03b0e Mon Sep 17 00:00:00 2001
From: Wohlstand <[EMAIL REDACTED]>
Date: Wed, 8 Jun 2022 20:58:41 +0300
Subject: [PATCH] By @kode54: Add support for more track info fields
---
gme/Gme_File.cpp | 20 ++++++++++--
gme/Gme_File.h | 59 +++++++++++++++++++++--------------
gme/M3u_Playlist.cpp | 73 ++++++++++++++++++++++++++++++++++++--------
gme/M3u_Playlist.h | 16 ++++++----
4 files changed, 124 insertions(+), 44 deletions(-)
diff --git a/gme/Gme_File.cpp b/gme/Gme_File.cpp
index 22b4133..24bcada 100644
--- a/gme/Gme_File.cpp
+++ b/gme/Gme_File.cpp
@@ -183,14 +183,24 @@ blargg_err_t Gme_File::track_info( track_info_t* out, int track ) const
out->loop_length = -1;
out->intro_length = -1;
out->fade_length = -1;
+ out->play_length = -1;
+ out->repeat_count = -1;
out->song [0] = 0;
out->game [0] = 0;
out->author [0] = 0;
+ out->composer [0] = 0;
+ out->engineer [0] = 0;
+ out->sequencer [0] = 0;
+ out->tagger [0] = 0;
out->copyright [0] = 0;
+ out->date [0] = 0;
out->comment [0] = 0;
out->dumper [0] = 0;
out->system [0] = 0;
+ out->disc [0] = 0;
+ out->track [0] = 0;
+ out->ost [0] = 0;
copy_field_( out->system, type()->system );
@@ -203,9 +213,14 @@ blargg_err_t Gme_File::track_info( track_info_t* out, int track ) const
{
M3u_Playlist::info_t const& i = playlist.info();
copy_field_( out->game , i.title );
- copy_field_( out->author, i.engineer );
- copy_field_( out->author, i.composer );
+ copy_field_( out->author, i.artist );
+ copy_field_( out->engineer, i.engineer );
+ copy_field_( out->composer, i.composer );
+ copy_field_( out->sequencer, i.sequencer );
+ copy_field_( out->copyright, i.copyright );
copy_field_( out->dumper, i.ripping );
+ copy_field_( out->tagger, i.tagging );
+ copy_field_( out->date, i.date );
M3u_Playlist::entry_t const& e = playlist [track];
copy_field_( out->song, e.name );
@@ -213,6 +228,7 @@ blargg_err_t Gme_File::track_info( track_info_t* out, int track ) const
if ( e.intro >= 0 ) out->intro_length = e.intro;
if ( e.loop >= 0 ) out->loop_length = e.loop;
if ( e.fade >= 0 ) out->fade_length = e.fade;
+ if ( e.repeat >= 0 ) out->repeat_count = e.repeat;
}
return 0;
}
diff --git a/gme/Gme_File.h b/gme/Gme_File.h
index 6b886e7..5bb220c 100644
--- a/gme/Gme_File.h
+++ b/gme/Gme_File.h
@@ -18,7 +18,7 @@ struct gme_type_t_
int track_count; /* non-zero for formats with a fixed number of tracks */
Music_Emu* (*new_emu)(); /* Create new emulator for this type (useful in C++ only) */
Music_Emu* (*new_info)(); /* Create new info reader for this type */
-
+
/* internal */
const char* extension_;
int flags_;
@@ -27,81 +27,94 @@ struct gme_type_t_
struct track_info_t
{
long track_count;
-
+
/* times in milliseconds; -1 if unknown */
long length;
long intro_length;
long loop_length;
long fade_length;
-
+ long repeat_count;
+
+ /* Length if available, otherwise intro_length+loop_length*2 if available,
+ * otherwise a default of 150000 (2.5 minutes) */
+ long play_length;
+
/* empty string if not available */
char system [256];
char game [256];
char song [256];
char author [256];
+ char composer [256];
+ char engineer [256];
+ char sequencer [256];
+ char tagger [256];
char copyright [256];
+ char date [256];
char comment [256];
char dumper [256];
+ char disc [256];
+ char track [256];
+ char ost [256];
};
enum { gme_max_field = 255 };
struct Gme_File {
public:
// File loading
-
+
// Each loads game music data from a file and returns an error if
// file is wrong type or is seriously corrupt. They also set warning
// string for minor problems.
-
+
// Load from file on disk
blargg_err_t load_file( const char* path );
-
+
// Load from custom data source (see Data_Reader.h)
blargg_err_t load( Data_Reader& );
-
+
// Load from file already read into memory. Keeps pointer to data, so you
// must not free it until you're done with the file.
blargg_err_t load_mem( void const* data, long size );
-
+
// Load an m3u playlist. Must be done after loading main music file.
blargg_err_t load_m3u( const char* path );
blargg_err_t load_m3u( Data_Reader& in );
-
+
// Clears any loaded m3u playlist and any internal playlist that the music
// format supports (NSFE for example).
void clear_playlist();
-
+
// Informational
-
+
// Type of emulator. For example if this returns gme_nsfe_type, this object
// is an NSFE emulator, and you can cast to an Nsfe_Emu* if necessary.
gme_type_t type() const;
-
+
// Most recent warning string, or NULL if none. Clears current warning after
// returning.
const char* warning();
-
+
// Number of tracks or 0 if no file has been loaded
int track_count() const;
-
+
// Get information for a track (length, name, author, etc.)
// See gme.h for definition of struct track_info_t.
blargg_err_t track_info( track_info_t* out, int track ) const;
-
+
// User data/cleanup
-
+
// Set/get pointer to data you want to associate with this emulator.
// You can use this for whatever you want.
void set_user_data( void* p ) { user_data_ = p; }
void* user_data() const { return user_data_; }
-
+
// Register cleanup function to be called when deleting emulator, or NULL to
// clear it. Passes user_data to cleanup function.
void set_user_cleanup( gme_user_cleanup_t func ) { user_cleanup_ = func; }
-
+
bool is_archive = false;
virtual blargg_err_t load_archive( const char* ) { return gme_wrong_file_type; }
-
+
public:
// deprecated
int error_count() const; // use warning()
@@ -116,7 +129,7 @@ struct Gme_File {
void set_warning( const char* s ) { warning_ = s; }
void set_type( gme_type_t t ) { type_ = t; }
blargg_err_t load_remaining_( void const* header, long header_size, Data_Reader& remaining );
-
+
// Overridable
virtual void unload(); // called before loading file and if loading fails
virtual blargg_err_t load_( Data_Reader& ); // default loads then calls load_mem_()
@@ -125,14 +138,14 @@ struct Gme_File {
virtual void pre_load();
virtual void post_load_();
virtual void clear_playlist_() { }
-
+
public:
blargg_err_t remap_track_( int* track_io ) const; // need by Music_Emu
private:
// noncopyable
Gme_File( const Gme_File& );
Gme_File& operator = ( const Gme_File& );
-
+
gme_type_t type_;
int track_count_;
int raw_track_count_;
@@ -142,7 +155,7 @@ struct Gme_File {
M3u_Playlist playlist;
char playlist_warning [64];
blargg_vector<byte> file_data; // only if loaded into memory using default load
-
+
blargg_err_t load_m3u_( blargg_err_t );
blargg_err_t post_load( blargg_err_t err );
public:
diff --git a/gme/M3u_Playlist.cpp b/gme/M3u_Playlist.cpp
index abff866..dab65b9 100644
--- a/gme/M3u_Playlist.cpp
+++ b/gme/M3u_Playlist.cpp
@@ -330,12 +330,13 @@ static int parse_line( char* in, M3u_Playlist::entry_t& entry )
return result;
}
-static void parse_comment( char* in, M3u_Playlist::info_t& info, bool first )
+static void parse_comment( char* in, M3u_Playlist::info_t& info, char *& last_comment_value, bool first )
{
in = skip_white( in + 1 );
const char* field = in;
- while ( *in && *in != ':' )
- in++;
+ if ( *field != '@' )
+ while ( *in && *in != ':' )
+ in++;
if ( *in == ':' )
{
@@ -343,10 +344,13 @@ static void parse_comment( char* in, M3u_Playlist::info_t& info, bool first )
if ( *text )
{
*in = 0;
- if ( !strcmp( "Composer", field ) ) info.composer = text;
- else if ( !strcmp( "Engineer", field ) ) info.engineer = text;
- else if ( !strcmp( "Ripping" , field ) ) info.ripping = text;
- else if ( !strcmp( "Tagging" , field ) ) info.tagging = text;
+ if ( !strcmp( "Composer" , field ) ) info.composer = text;
+ else if ( !strcmp( "Engineer" , field ) ) info.engineer = text;
+ else if ( !strcmp( "Ripping" , field ) ) info.ripping = text;
+ else if ( !strcmp( "Tagging" , field ) ) info.tagging = text;
+ else if ( !strcmp( "Game" , field ) ) info.title = text;
+ else if ( !strcmp( "Artist" , field ) ) info.artist = text;
+ else if ( !strcmp( "Copyright", field ) ) info.copyright = text;
else
text = 0;
if ( text )
@@ -354,6 +358,43 @@ static void parse_comment( char* in, M3u_Playlist::info_t& info, bool first )
*in = ':';
}
}
+ else if ( *field == '@' )
+ {
+ ++field;
+ in = (char*)field;
+ while ( *in && *in > ' ' )
+ in++;
+ const char* text = skip_white( in );
+ if ( *text )
+ {
+ *in = 0;
+ if ( !strcmp( "TITLE" , field ) ) info.title = text;
+ else if ( !strcmp( "ARTIST" , field ) ) info.artist = text;
+ else if ( !strcmp( "DATE" , field ) ) info.date = text;
+ else if ( !strcmp( "COMPOSER" , field ) ) info.composer = text;
+ else if ( !strcmp( "SEQUENCER", field ) ) info.sequencer = text;
+ else if ( !strcmp( "ENGINEER" , field ) ) info.engineer = text;
+ else if ( !strcmp( "RIPPER" , field ) ) info.ripping = text;
+ else if ( !strcmp( "TAGGER" , field ) ) info.tagging = text;
+ else
+ text = 0;
+ if ( text )
+ {
+ last_comment_value = (char*)text;
+ return;
+ }
+ }
+ }
+ else if ( last_comment_value )
+ {
+ size_t len = strlen( last_comment_value );
+ last_comment_value[ len ] = ',';
+ last_comment_value[ len + 1 ] = ' ';
+ size_t field_len = strlen( field );
+ memmove( last_comment_value + len + 2, field, field_len );
+ last_comment_value[ len + 2 + field_len ] = 0;
+ return;
+ }
if ( first )
info.title = field;
@@ -361,11 +402,15 @@ static void parse_comment( char* in, M3u_Playlist::info_t& info, bool first )
blargg_err_t M3u_Playlist::parse_()
{
- info_.title = "";
- info_.composer = "";
- info_.engineer = "";
- info_.ripping = "";
- info_.tagging = "";
+ info_.title = "";
+ info_.artist = "";
+ info_.date = "";
+ info_.composer = "";
+ info_.sequencer = "";
+ info_.engineer = "";
+ info_.ripping = "";
+ info_.tagging = "";
+ info_.copyright = "";
int const CR = 13;
int const LF = 10;
@@ -377,6 +422,7 @@ blargg_err_t M3u_Playlist::parse_()
int line = 0;
int count = 0;
char* in = data.begin();
+ char* last_comment_value = 0;
while ( in < data.end() )
{
// find end of line and terminate it
@@ -395,7 +441,7 @@ blargg_err_t M3u_Playlist::parse_()
// parse line
if ( *begin == '#' )
{
- parse_comment( begin, info_, first_comment );
+ parse_comment( begin, info_, last_comment_value, first_comment );
first_comment = false;
}
else if ( *begin )
@@ -409,6 +455,7 @@ blargg_err_t M3u_Playlist::parse_()
first_error_ = line;
first_comment = false;
}
+ else last_comment_value = 0;
}
if ( count <= 0 )
return "Not an m3u playlist";
diff --git a/gme/M3u_Playlist.h b/gme/M3u_Playlist.h
index 1b32c53..2af7480 100644
--- a/gme/M3u_Playlist.h
+++ b/gme/M3u_Playlist.h
@@ -13,21 +13,25 @@ class M3u_Playlist {
blargg_err_t load( const char* path );
blargg_err_t load( Data_Reader& in );
blargg_err_t load( void const* data, long size );
-
+
// Line number of first parse error, 0 if no error. Any lines with parse
// errors are ignored.
int first_error() const { return first_error_; }
-
+
struct info_t
{
const char* title;
+ const char* artist;
+ const char* date;
const char* composer;
+ const char* sequencer;
const char* engineer;
const char* ripping;
const char* tagging;
+ const char* copyright;
};
info_t const& info() const { return info_; }
-
+
struct entry_t
{
const char* file; // filename without stupid ::TYPE suffix
@@ -44,15 +48,15 @@ class M3u_Playlist {
};
entry_t const& operator [] ( int i ) const { return entries [i]; }
int size() const { return entries.size(); }
-
+
void clear();
-
+
private:
blargg_vector<entry_t> entries;
blargg_vector<char> data;
int first_error_;
info_t info_;
-
+
blargg_err_t parse();
blargg_err_t parse_();
};