diff options
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | src/decoder/sidplay_plugin.cxx | 133 |
2 files changed, 126 insertions, 8 deletions
@@ -15,6 +15,7 @@ ver 0.16 (20??/??/??) - sndfile: new decoder plugin based on libsndfile - flac: load external cue sheet when no internal one - mpg123: new decoder plugin based on libmpg123 + - sidplay: support sub-tunes * encoders: - twolame: new encoder plugin based on libtwolame * output: diff --git a/src/decoder/sidplay_plugin.cxx b/src/decoder/sidplay_plugin.cxx index 54ab746e2..ab67a8b81 100644 --- a/src/decoder/sidplay_plugin.cxx +++ b/src/decoder/sidplay_plugin.cxx @@ -21,6 +21,8 @@ extern "C" { #include "../decoder_api.h" } +#include <errno.h> +#include <stdlib.h> #include <glib.h> #include <sidplay/sidplay2.h> @@ -29,6 +31,72 @@ extern "C" { #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "sidplay" +#define SUBTUNE_PREFIX "tune_" + +static GPatternSpec *path_with_subtune; + +static bool all_files_are_containers; + +static bool +sidplay_init(const struct config_param *param) +{ + all_files_are_containers=config_get_block_bool(param, + "all_files_are_containers", true); + + path_with_subtune=g_pattern_spec_new( + "*/" SUBTUNE_PREFIX "???.sid"); + + return true; +} + +void +sidplay_finish() +{ + g_pattern_spec_free(path_with_subtune); +} + +/** + * returns the file path stripped of any /tune_xxx.sid subtune + * suffix + */ +static char * +get_container_name(const char *path_fs) +{ + char *path_container=g_strdup(path_fs); + + if(!g_pattern_match(path_with_subtune, + strlen(path_container), path_container, NULL)) + return path_container; + + char *ptr=g_strrstr(path_container, "/" SUBTUNE_PREFIX); + if(ptr) *ptr='\0'; + + return path_container; +} + +/** + * returns tune number from file.sid/tune_xxx.sid style path or 1 if + * no subtune is appended + */ +static int +get_song_num(const char *path_fs) +{ + if(g_pattern_match(path_with_subtune, + strlen(path_fs), path_fs, NULL)) { + char *sub=g_strrstr(path_fs, "/" SUBTUNE_PREFIX); + if(!sub) return 1; + + sub+=strlen("/" SUBTUNE_PREFIX); + int song_num=strtol(sub, NULL, 10); + + if (errno == EINVAL) + return 1; + else + return song_num; + } else + return 1; +} + static void sidplay_file_decode(struct decoder *decoder, const char *path_fs) { @@ -36,13 +104,16 @@ sidplay_file_decode(struct decoder *decoder, const char *path_fs) /* load the tune */ - SidTune tune(path_fs, NULL, true); + char *path_container=get_container_name(path_fs); + SidTune tune(path_container, NULL, true); + g_free(path_container); if (!tune) { g_warning("failed to load file"); return; } - tune.selectSong(1); + int song_num=get_song_num(path_fs); + tune.selectSong(song_num); /* initialize the player */ @@ -126,22 +197,68 @@ sidplay_file_decode(struct decoder *decoder, const char *path_fs) static struct tag * sidplay_tag_dup(const char *path_fs) { - SidTune tune(path_fs, NULL, true); + int song_num=get_song_num(path_fs); + char *path_container=get_container_name(path_fs); + + SidTune tune(path_container, NULL, true); + g_free(path_container); if (!tune) return NULL; const SidTuneInfo &info = tune.getInfo(); struct tag *tag = tag_new(); + /* title */ + const char *title; if (info.numberOfInfoStrings > 0 && info.infoString[0] != NULL) - tag_add_item(tag, TAG_ITEM_TITLE, info.infoString[0]); - + title=info.infoString[0]; + else + title=""; + + if(info.songs>1) { + char *tag_title=g_strdup_printf("%s (%d/%d)", + title, song_num, info.songs); + tag_add_item(tag, TAG_ITEM_TITLE, tag_title); + g_free(tag_title); + } else + tag_add_item(tag, TAG_ITEM_TITLE, title); + + /* artist */ if (info.numberOfInfoStrings > 1 && info.infoString[1] != NULL) tag_add_item(tag, TAG_ITEM_ARTIST, info.infoString[1]); + /* track */ + char *track=g_strdup_printf("%d", song_num); + tag_add_item(tag, TAG_ITEM_TRACK, track); + g_free(track); + return tag; } +static char * +sidplay_container_scan(const char *path_fs, const unsigned int tnum) +{ + SidTune tune(path_fs, NULL, true); + if (!tune) + return NULL; + + const SidTuneInfo &info=tune.getInfo(); + + /* Don't treat sids containing a single tune + as containers */ + if(!all_files_are_containers && info.songs<2) + return NULL; + + /* Construct container/tune path names, eg. + Delta.sid/tune_001.sid */ + if(tnum<=info.songs) { + char *subtune= g_strdup_printf( + SUBTUNE_PREFIX "%03u.sid", tnum); + return subtune; + } else + return NULL; +} + static const char *const sidplay_suffixes[] = { "sid", NULL @@ -150,12 +267,12 @@ static const char *const sidplay_suffixes[] = { extern const struct decoder_plugin sidplay_decoder_plugin; const struct decoder_plugin sidplay_decoder_plugin = { "sidplay", - NULL, /* init() */ - NULL, /* finish() */ + sidplay_init, + sidplay_finish, NULL, /* stream_decode() */ sidplay_file_decode, sidplay_tag_dup, - NULL, /* container_scan */ + sidplay_container_scan, sidplay_suffixes, NULL, /* mime_types */ }; |