decoder/sidplay: subtunes

This commit is contained in:
Mike Dawson 2009-08-30 19:48:56 +02:00 committed by Max Kellermann
parent f2ff2409ad
commit 85ce9aa7de
2 changed files with 125 additions and 7 deletions

1
NEWS
View File

@ -15,6 +15,7 @@ ver 0.16 (20??/??/??)
- sndfile: new decoder plugin based on libsndfile - sndfile: new decoder plugin based on libsndfile
- flac: load external cue sheet when no internal one - flac: load external cue sheet when no internal one
- mpg123: new decoder plugin based on libmpg123 - mpg123: new decoder plugin based on libmpg123
- sidplay: support sub-tunes
* encoders: * encoders:
- twolame: new encoder plugin based on libtwolame - twolame: new encoder plugin based on libtwolame
* output: * output:

View File

@ -21,6 +21,8 @@ extern "C" {
#include "../decoder_api.h" #include "../decoder_api.h"
} }
#include <errno.h>
#include <stdlib.h>
#include <glib.h> #include <glib.h>
#include <sidplay/sidplay2.h> #include <sidplay/sidplay2.h>
@ -29,6 +31,72 @@ extern "C" {
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "sidplay" #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 static void
sidplay_file_decode(struct decoder *decoder, const char *path_fs) 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 */ /* 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) { if (!tune) {
g_warning("failed to load file"); g_warning("failed to load file");
return; return;
} }
tune.selectSong(1); int song_num=get_song_num(path_fs);
tune.selectSong(song_num);
/* initialize the player */ /* initialize the player */
@ -126,22 +197,68 @@ sidplay_file_decode(struct decoder *decoder, const char *path_fs)
static struct tag * static struct tag *
sidplay_tag_dup(const char *path_fs) 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) if (!tune)
return NULL; return NULL;
const SidTuneInfo &info = tune.getInfo(); const SidTuneInfo &info = tune.getInfo();
struct tag *tag = tag_new(); struct tag *tag = tag_new();
/* title */
const char *title;
if (info.numberOfInfoStrings > 0 && info.infoString[0] != NULL) 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) if (info.numberOfInfoStrings > 1 && info.infoString[1] != NULL)
tag_add_item(tag, TAG_ITEM_ARTIST, info.infoString[1]); 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; 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[] = { static const char *const sidplay_suffixes[] = {
"sid", "sid",
NULL NULL
@ -150,12 +267,12 @@ static const char *const sidplay_suffixes[] = {
extern const struct decoder_plugin sidplay_decoder_plugin; extern const struct decoder_plugin sidplay_decoder_plugin;
const struct decoder_plugin sidplay_decoder_plugin = { const struct decoder_plugin sidplay_decoder_plugin = {
"sidplay", "sidplay",
NULL, /* init() */ sidplay_init,
NULL, /* finish() */ sidplay_finish,
NULL, /* stream_decode() */ NULL, /* stream_decode() */
sidplay_file_decode, sidplay_file_decode,
sidplay_tag_dup, sidplay_tag_dup,
NULL, /* container_scan */ sidplay_container_scan,
sidplay_suffixes, sidplay_suffixes,
NULL, /* mime_types */ NULL, /* mime_types */
}; };