aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--configure.ac9
-rw-r--r--doc/mpdconf.example22
-rw-r--r--src/decoder/sidplay_plugin.cxx87
4 files changed, 117 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 91f01c382..e06543b8c 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,7 @@ ver 0.16 (20??/??/??)
- flac: load external cue sheet when no internal one
- mpg123: new decoder plugin based on libmpg123
- sidplay: support sub-tunes
+ - sidplay: implemented songlength database
* encoders:
- twolame: new encoder plugin based on libtwolame
* output:
diff --git a/configure.ac b/configure.ac
index 681feae6c..e730c6977 100644
--- a/configure.ac
+++ b/configure.ac
@@ -554,12 +554,17 @@ if test x$enable_sidplay != xno; then
# library name triggers an autoconf bug
AC_CHECK_LIB(resid-builder, main,
[found_sidplay=yes], [found_sidplay=no])
+
+ if test x$found_sidplay = xyes; then
+ AC_HAVE_LIBRARY(sidutils,, [found_sidplay=no])
+ fi
+
MPD_AUTO_RESULT(sidplay, [sidplay decoder plugin],
- [libresid-builder not found])
+ [libresid-builder or libsidutils not found])
fi
if test x$enable_sidplay = xyes; then
- AC_SUBST(SIDPLAY_LIBS,"-lsidplay2 -lresid-builder")
+ AC_SUBST(SIDPLAY_LIBS,"-lsidplay2 -lresid-builder -lsidutils")
AC_SUBST(SIDPLAY_CFLAGS,)
AC_DEFINE(ENABLE_SIDPLAY, 1, [Define for libsidplay2 support])
diff --git a/doc/mpdconf.example b/doc/mpdconf.example
index 4e3b19a5a..8ce3a1b9f 100644
--- a/doc/mpdconf.example
+++ b/doc/mpdconf.example
@@ -363,3 +363,25 @@ input {
#id3v1_encoding "ISO-8859-1"
#
###############################################################################
+
+
+# SIDPlay decoder #############################################################
+#
+# songlength_database:
+# Location of your songlengths file, as distributed with the HVSC.
+# The sidplay plugin checks this for matching MD5 fingerprints.
+# See http://www.c64.org/HVSC/DOCUMENTS/Songlengths.faq
+#
+# default_songlength:
+# This is the default playing time in seconds for songs not in the
+# songlength database, or in case you're not using a database.
+# A value of 0 means play indefinitely.
+#
+#decoder {
+# plugin "sidplay"
+# songlength_database "/media/C64Music/DOCUMENTS/Songlengths.txt"
+# default_songlength "120"
+#}
+#
+###############################################################################
+
diff --git a/src/decoder/sidplay_plugin.cxx b/src/decoder/sidplay_plugin.cxx
index ab67a8b81..f490586ac 100644
--- a/src/decoder/sidplay_plugin.cxx
+++ b/src/decoder/sidplay_plugin.cxx
@@ -27,6 +27,7 @@ extern "C" {
#include <sidplay/sidplay2.h>
#include <sidplay/builders/resid.h>
+#include <sidplay/utils/SidTuneMod.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "sidplay"
@@ -34,12 +35,48 @@ extern "C" {
#define SUBTUNE_PREFIX "tune_"
static GPatternSpec *path_with_subtune;
+static const char *songlength_file;
+static GKeyFile *songlength_database;
static bool all_files_are_containers;
+static unsigned default_songlength;
static bool
sidplay_init(const struct config_param *param)
{
+ GError *err=NULL;
+ gchar *songlen_data;
+ gsize songlen_data_size;
+
+ /* read the songlengths database file */
+ songlength_file=config_get_block_string(param,
+ "songlength_database", NULL);
+ if(songlength_file) {
+ if(g_file_get_contents(songlength_file, &songlen_data, &songlen_data_size, NULL)) {
+ /* replace any ; comment characters with # */
+ for(int i=0; i<songlen_data_size; i++)
+ if(songlen_data[i]==';') songlen_data[i]='#';
+
+ songlength_database=g_key_file_new();
+ if(!g_key_file_load_from_data(songlength_database,
+ songlen_data, songlen_data_size,
+ G_KEY_FILE_NONE, &err)) {
+ g_warning("unable to parse songlengths file %s: %s",
+ songlength_file, err->message);
+ g_key_file_free(songlength_database);
+ songlength_database=NULL;
+ }
+ g_key_file_set_list_separator(songlength_database, ' ');
+ g_free(songlen_data);
+ } else {
+ g_warning("unable to read songlengths file %s: %s",
+ songlength_file, err->message);
+ }
+ }
+
+ default_songlength=config_get_block_unsigned(param,
+ "default_songlength", 0);
+
all_files_are_containers=config_get_block_bool(param,
"all_files_are_containers", true);
@@ -53,6 +90,9 @@ void
sidplay_finish()
{
g_pattern_spec_free(path_with_subtune);
+
+ if(songlength_database)
+ g_key_file_free(songlength_database);
}
/**
@@ -97,6 +137,49 @@ get_song_num(const char *path_fs)
return 1;
}
+/* get the song length in seconds */
+static int
+get_song_length(const char *path_fs)
+{
+ if (songlength_database == NULL)
+ return -1;
+
+ gchar *sid_file=get_container_name(path_fs);
+ SidTuneMod tune(sid_file);
+ g_free(sid_file);
+ if(!tune) {
+ g_warning("failed to load file for calculating md5 sum");
+ return -1;
+ }
+ char md5sum[SIDTUNE_MD5_LENGTH+1];
+ tune.createMD5(md5sum);
+
+ int song_num=get_song_num(path_fs);
+
+ gsize num_items;
+ gchar **values=g_key_file_get_string_list(songlength_database,
+ "Database", md5sum, &num_items, NULL);
+ if(!values || song_num>num_items) {
+ g_strfreev(values);
+ return -1;
+ }
+
+ int minutes=strtol(values[song_num-1], NULL, 10);
+ if(errno==EINVAL) minutes=0;
+
+ int seconds;
+ char *ptr=strchr(values[song_num-1], ':');
+ if(ptr) {
+ seconds=strtol(ptr+1, NULL, 10);
+ if(errno==EINVAL) seconds=0;
+ } else
+ seconds=0;
+
+ g_strfreev(values);
+
+ return (minutes*60)+seconds;
+}
+
static void
sidplay_file_decode(struct decoder *decoder, const char *path_fs)
{
@@ -232,6 +315,10 @@ sidplay_tag_dup(const char *path_fs)
tag_add_item(tag, TAG_ITEM_TRACK, track);
g_free(track);
+ /* time */
+ int song_len=get_song_length(path_fs);
+ if(song_len!=-1) tag->time=song_len;
+
return tag;
}