decoder/sidplay: subtunes
This commit is contained in:
parent
f2ff2409ad
commit
85ce9aa7de
1
NEWS
1
NEWS
@ -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:
|
||||||
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user