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 #include +#include #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; imessage); + 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; }