From 17ecc56e83cfa2eda27ad664f53f6b9dc37ce8a1 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 20 Oct 2013 13:03:58 +0200 Subject: decoder/sidplay: update file name --- Makefile.am | 3 +- src/decoder/SidplayDecoderPlugin.cxx | 434 +++++++++++++++++++++++++++++++++ src/decoder/sidplay_decoder_plugin.cxx | 434 --------------------------------- 3 files changed, 436 insertions(+), 435 deletions(-) create mode 100644 src/decoder/SidplayDecoderPlugin.cxx delete mode 100644 src/decoder/sidplay_decoder_plugin.cxx diff --git a/Makefile.am b/Makefile.am index d70828e22..a4f443f50 100644 --- a/Makefile.am +++ b/Makefile.am @@ -617,7 +617,8 @@ DECODER_LIBS += libmodplug_decoder_plugin.a $(MODPLUG_LIBS) endif if ENABLE_SIDPLAY -libdecoder_plugins_a_SOURCES += src/decoder/sidplay_decoder_plugin.cxx +libdecoder_plugins_a_SOURCES += \ + src/decoder/SidplayDecoderPlugin.cxx endif if ENABLE_FLUIDSYNTH diff --git a/src/decoder/SidplayDecoderPlugin.cxx b/src/decoder/SidplayDecoderPlugin.cxx new file mode 100644 index 000000000..3dbede9b5 --- /dev/null +++ b/src/decoder/SidplayDecoderPlugin.cxx @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "../DecoderAPI.hxx" +#include "tag/TagHandler.hxx" +#include "util/Domain.hxx" +#include "system/ByteOrder.hxx" +#include "Log.hxx" + +#include +#include +#include +#include + +#include +#include +#include + +#define SUBTUNE_PREFIX "tune_" + +static constexpr Domain sidplay_domain("sidplay"); + +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 filter_setting; + +static GKeyFile * +sidplay_load_songlength_db(const char *path) +{ + GError *error = nullptr; + gchar *data; + gsize size; + + if (!g_file_get_contents(path, &data, &size, &error)) { + FormatError(sidplay_domain, + "unable to read songlengths file %s: %s", + path, error->message); + g_error_free(error); + return nullptr; + } + + /* replace any ; comment characters with # */ + for (gsize i = 0; i < size; i++) + if (data[i] == ';') + data[i] = '#'; + + GKeyFile *db = g_key_file_new(); + bool success = g_key_file_load_from_data(db, data, size, + G_KEY_FILE_NONE, &error); + g_free(data); + if (!success) { + FormatError(sidplay_domain, + "unable to parse songlengths file %s: %s", + path, error->message); + g_error_free(error); + g_key_file_free(db); + return nullptr; + } + + g_key_file_set_list_separator(db, ' '); + return db; +} + +static bool +sidplay_init(const config_param ¶m) +{ + /* read the songlengths database file */ + songlength_file = param.GetBlockValue("songlength_database"); + if (songlength_file != nullptr) + songlength_database = sidplay_load_songlength_db(songlength_file); + + default_songlength = param.GetBlockValue("default_songlength", 0u); + + all_files_are_containers = + param.GetBlockValue("all_files_are_containers", true); + + path_with_subtune=g_pattern_spec_new( + "*/" SUBTUNE_PREFIX "???.sid"); + + filter_setting = param.GetBlockValue("filter", true); + + return true; +} + +static void +sidplay_finish() +{ + g_pattern_spec_free(path_with_subtune); + + if(songlength_database) + g_key_file_free(songlength_database); +} + +/** + * 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, nullptr)) + 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 unsigned +get_song_num(const char *path_fs) +{ + if(g_pattern_match(path_with_subtune, + strlen(path_fs), path_fs, nullptr)) { + char *sub=g_strrstr(path_fs, "/" SUBTUNE_PREFIX); + if(!sub) return 1; + + sub+=strlen("/" SUBTUNE_PREFIX); + int song_num=strtol(sub, nullptr, 10); + + if (errno == EINVAL) + return 1; + else + return song_num; + } else + return 1; +} + +/* get the song length in seconds */ +static int +get_song_length(const char *path_fs) +{ + if (songlength_database == nullptr) + return -1; + + gchar *sid_file=get_container_name(path_fs); + SidTuneMod tune(sid_file); + g_free(sid_file); + if(!tune) { + LogWarning(sidplay_domain, + "failed to load file for calculating md5 sum"); + return -1; + } + char md5sum[SIDTUNE_MD5_LENGTH+1]; + tune.createMD5(md5sum); + + const unsigned song_num = get_song_num(path_fs); + + gsize num_items; + gchar **values=g_key_file_get_string_list(songlength_database, + "Database", md5sum, &num_items, nullptr); + if(!values || song_num>num_items) { + g_strfreev(values); + return -1; + } + + int minutes=strtol(values[song_num-1], nullptr, 10); + if(errno==EINVAL) minutes=0; + + int seconds; + char *ptr=strchr(values[song_num-1], ':'); + if(ptr) { + seconds=strtol(ptr+1, nullptr, 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) +{ + int channels; + + /* load the tune */ + + char *path_container=get_container_name(path_fs); + SidTune tune(path_container, nullptr, true); + g_free(path_container); + if (!tune) { + LogWarning(sidplay_domain, "failed to load file"); + return; + } + + int song_num=get_song_num(path_fs); + tune.selectSong(song_num); + + int song_len=get_song_length(path_fs); + if(song_len==-1) song_len=default_songlength; + + /* initialize the player */ + + sidplay2 player; + int iret = player.load(&tune); + if (iret != 0) { + FormatWarning(sidplay_domain, + "sidplay2.load() failed: %s", player.error()); + return; + } + + /* initialize the builder */ + + ReSIDBuilder builder("ReSID"); + if (!builder) { + LogWarning(sidplay_domain, + "failed to initialize ReSIDBuilder"); + return; + } + + builder.create(player.info().maxsids); + if (!builder) { + LogWarning(sidplay_domain, "ReSIDBuilder.create() failed"); + return; + } + + builder.filter(filter_setting); + if (!builder) { + LogWarning(sidplay_domain, "ReSIDBuilder.filter() failed"); + return; + } + + /* configure the player */ + + sid2_config_t config = player.config(); + + config.clockDefault = SID2_CLOCK_PAL; + config.clockForced = true; + config.clockSpeed = SID2_CLOCK_CORRECT; + config.frequency = 48000; + config.optimisation = SID2_DEFAULT_OPTIMISATION; + + config.precision = 16; + config.sidDefault = SID2_MOS6581; + config.sidEmulation = &builder; + config.sidModel = SID2_MODEL_CORRECT; + config.sidSamples = true; + config.sampleFormat = IsLittleEndian() + ? SID2_LITTLE_SIGNED + : SID2_BIG_SIGNED; + if (tune.isStereo()) { + config.playback = sid2_stereo; + channels = 2; + } else { + config.playback = sid2_mono; + channels = 1; + } + + iret = player.config(config); + if (iret != 0) { + FormatWarning(sidplay_domain, + "sidplay2.config() failed: %s", player.error()); + return; + } + + /* initialize the MPD decoder */ + + const AudioFormat audio_format(48000, SampleFormat::S16, channels); + assert(audio_format.IsValid()); + + decoder_initialized(decoder, audio_format, true, (float)song_len); + + /* .. and play */ + + const unsigned timebase = player.timebase(); + song_len *= timebase; + + DecoderCommand cmd; + do { + char buffer[4096]; + size_t nbytes; + + nbytes = player.play(buffer, sizeof(buffer)); + if (nbytes == 0) + break; + + decoder_timestamp(decoder, (double)player.time() / timebase); + + cmd = decoder_data(decoder, nullptr, buffer, nbytes, 0); + + if (cmd == DecoderCommand::SEEK) { + unsigned data_time = player.time(); + unsigned target_time = (unsigned) + (decoder_seek_where(decoder) * timebase); + + /* can't rewind so return to zero and seek forward */ + if(target_time 0 && player.time() >= (unsigned)song_len) + break; + + } while (cmd != DecoderCommand::STOP); +} + +static bool +sidplay_scan_file(const char *path_fs, + const struct tag_handler *handler, void *handler_ctx) +{ + int song_num=get_song_num(path_fs); + char *path_container=get_container_name(path_fs); + + SidTune tune(path_container, nullptr, true); + g_free(path_container); + if (!tune) + return false; + + const SidTuneInfo &info = tune.getInfo(); + + /* title */ + const char *title; + if (info.numberOfInfoStrings > 0 && info.infoString[0] != nullptr) + title=info.infoString[0]; + else + title=""; + + if(info.songs>1) { + char tag_title[1024]; + snprintf(tag_title, sizeof(tag_title), + "%s (%d/%d)", + title, song_num, info.songs); + tag_handler_invoke_tag(handler, handler_ctx, + TAG_TITLE, tag_title); + } else + tag_handler_invoke_tag(handler, handler_ctx, TAG_TITLE, title); + + /* artist */ + if (info.numberOfInfoStrings > 1 && info.infoString[1] != nullptr) + tag_handler_invoke_tag(handler, handler_ctx, TAG_ARTIST, + info.infoString[1]); + + /* track */ + char track[16]; + sprintf(track, "%d", song_num); + tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track); + + /* time */ + int song_len=get_song_length(path_fs); + if (song_len >= 0) + tag_handler_invoke_duration(handler, handler_ctx, song_len); + + return true; +} + +static char * +sidplay_container_scan(const char *path_fs, const unsigned int tnum) +{ + SidTune tune(path_fs, nullptr, true); + if (!tune) + return nullptr; + + const SidTuneInfo &info=tune.getInfo(); + + /* Don't treat sids containing a single tune + as containers */ + if(!all_files_are_containers && info.songs<2) + return nullptr; + + /* 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 nullptr; +} + +static const char *const sidplay_suffixes[] = { + "sid", + "mus", + "str", + "prg", + "P00", + nullptr +}; + +extern const struct decoder_plugin sidplay_decoder_plugin; +const struct decoder_plugin sidplay_decoder_plugin = { + "sidplay", + sidplay_init, + sidplay_finish, + nullptr, /* stream_decode() */ + sidplay_file_decode, + sidplay_scan_file, + nullptr, /* stream_tag() */ + sidplay_container_scan, + sidplay_suffixes, + nullptr, /* mime_types */ +}; diff --git a/src/decoder/sidplay_decoder_plugin.cxx b/src/decoder/sidplay_decoder_plugin.cxx deleted file mode 100644 index 3dbede9b5..000000000 --- a/src/decoder/sidplay_decoder_plugin.cxx +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "../DecoderAPI.hxx" -#include "tag/TagHandler.hxx" -#include "util/Domain.hxx" -#include "system/ByteOrder.hxx" -#include "Log.hxx" - -#include -#include -#include -#include - -#include -#include -#include - -#define SUBTUNE_PREFIX "tune_" - -static constexpr Domain sidplay_domain("sidplay"); - -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 filter_setting; - -static GKeyFile * -sidplay_load_songlength_db(const char *path) -{ - GError *error = nullptr; - gchar *data; - gsize size; - - if (!g_file_get_contents(path, &data, &size, &error)) { - FormatError(sidplay_domain, - "unable to read songlengths file %s: %s", - path, error->message); - g_error_free(error); - return nullptr; - } - - /* replace any ; comment characters with # */ - for (gsize i = 0; i < size; i++) - if (data[i] == ';') - data[i] = '#'; - - GKeyFile *db = g_key_file_new(); - bool success = g_key_file_load_from_data(db, data, size, - G_KEY_FILE_NONE, &error); - g_free(data); - if (!success) { - FormatError(sidplay_domain, - "unable to parse songlengths file %s: %s", - path, error->message); - g_error_free(error); - g_key_file_free(db); - return nullptr; - } - - g_key_file_set_list_separator(db, ' '); - return db; -} - -static bool -sidplay_init(const config_param ¶m) -{ - /* read the songlengths database file */ - songlength_file = param.GetBlockValue("songlength_database"); - if (songlength_file != nullptr) - songlength_database = sidplay_load_songlength_db(songlength_file); - - default_songlength = param.GetBlockValue("default_songlength", 0u); - - all_files_are_containers = - param.GetBlockValue("all_files_are_containers", true); - - path_with_subtune=g_pattern_spec_new( - "*/" SUBTUNE_PREFIX "???.sid"); - - filter_setting = param.GetBlockValue("filter", true); - - return true; -} - -static void -sidplay_finish() -{ - g_pattern_spec_free(path_with_subtune); - - if(songlength_database) - g_key_file_free(songlength_database); -} - -/** - * 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, nullptr)) - 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 unsigned -get_song_num(const char *path_fs) -{ - if(g_pattern_match(path_with_subtune, - strlen(path_fs), path_fs, nullptr)) { - char *sub=g_strrstr(path_fs, "/" SUBTUNE_PREFIX); - if(!sub) return 1; - - sub+=strlen("/" SUBTUNE_PREFIX); - int song_num=strtol(sub, nullptr, 10); - - if (errno == EINVAL) - return 1; - else - return song_num; - } else - return 1; -} - -/* get the song length in seconds */ -static int -get_song_length(const char *path_fs) -{ - if (songlength_database == nullptr) - return -1; - - gchar *sid_file=get_container_name(path_fs); - SidTuneMod tune(sid_file); - g_free(sid_file); - if(!tune) { - LogWarning(sidplay_domain, - "failed to load file for calculating md5 sum"); - return -1; - } - char md5sum[SIDTUNE_MD5_LENGTH+1]; - tune.createMD5(md5sum); - - const unsigned song_num = get_song_num(path_fs); - - gsize num_items; - gchar **values=g_key_file_get_string_list(songlength_database, - "Database", md5sum, &num_items, nullptr); - if(!values || song_num>num_items) { - g_strfreev(values); - return -1; - } - - int minutes=strtol(values[song_num-1], nullptr, 10); - if(errno==EINVAL) minutes=0; - - int seconds; - char *ptr=strchr(values[song_num-1], ':'); - if(ptr) { - seconds=strtol(ptr+1, nullptr, 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) -{ - int channels; - - /* load the tune */ - - char *path_container=get_container_name(path_fs); - SidTune tune(path_container, nullptr, true); - g_free(path_container); - if (!tune) { - LogWarning(sidplay_domain, "failed to load file"); - return; - } - - int song_num=get_song_num(path_fs); - tune.selectSong(song_num); - - int song_len=get_song_length(path_fs); - if(song_len==-1) song_len=default_songlength; - - /* initialize the player */ - - sidplay2 player; - int iret = player.load(&tune); - if (iret != 0) { - FormatWarning(sidplay_domain, - "sidplay2.load() failed: %s", player.error()); - return; - } - - /* initialize the builder */ - - ReSIDBuilder builder("ReSID"); - if (!builder) { - LogWarning(sidplay_domain, - "failed to initialize ReSIDBuilder"); - return; - } - - builder.create(player.info().maxsids); - if (!builder) { - LogWarning(sidplay_domain, "ReSIDBuilder.create() failed"); - return; - } - - builder.filter(filter_setting); - if (!builder) { - LogWarning(sidplay_domain, "ReSIDBuilder.filter() failed"); - return; - } - - /* configure the player */ - - sid2_config_t config = player.config(); - - config.clockDefault = SID2_CLOCK_PAL; - config.clockForced = true; - config.clockSpeed = SID2_CLOCK_CORRECT; - config.frequency = 48000; - config.optimisation = SID2_DEFAULT_OPTIMISATION; - - config.precision = 16; - config.sidDefault = SID2_MOS6581; - config.sidEmulation = &builder; - config.sidModel = SID2_MODEL_CORRECT; - config.sidSamples = true; - config.sampleFormat = IsLittleEndian() - ? SID2_LITTLE_SIGNED - : SID2_BIG_SIGNED; - if (tune.isStereo()) { - config.playback = sid2_stereo; - channels = 2; - } else { - config.playback = sid2_mono; - channels = 1; - } - - iret = player.config(config); - if (iret != 0) { - FormatWarning(sidplay_domain, - "sidplay2.config() failed: %s", player.error()); - return; - } - - /* initialize the MPD decoder */ - - const AudioFormat audio_format(48000, SampleFormat::S16, channels); - assert(audio_format.IsValid()); - - decoder_initialized(decoder, audio_format, true, (float)song_len); - - /* .. and play */ - - const unsigned timebase = player.timebase(); - song_len *= timebase; - - DecoderCommand cmd; - do { - char buffer[4096]; - size_t nbytes; - - nbytes = player.play(buffer, sizeof(buffer)); - if (nbytes == 0) - break; - - decoder_timestamp(decoder, (double)player.time() / timebase); - - cmd = decoder_data(decoder, nullptr, buffer, nbytes, 0); - - if (cmd == DecoderCommand::SEEK) { - unsigned data_time = player.time(); - unsigned target_time = (unsigned) - (decoder_seek_where(decoder) * timebase); - - /* can't rewind so return to zero and seek forward */ - if(target_time 0 && player.time() >= (unsigned)song_len) - break; - - } while (cmd != DecoderCommand::STOP); -} - -static bool -sidplay_scan_file(const char *path_fs, - const struct tag_handler *handler, void *handler_ctx) -{ - int song_num=get_song_num(path_fs); - char *path_container=get_container_name(path_fs); - - SidTune tune(path_container, nullptr, true); - g_free(path_container); - if (!tune) - return false; - - const SidTuneInfo &info = tune.getInfo(); - - /* title */ - const char *title; - if (info.numberOfInfoStrings > 0 && info.infoString[0] != nullptr) - title=info.infoString[0]; - else - title=""; - - if(info.songs>1) { - char tag_title[1024]; - snprintf(tag_title, sizeof(tag_title), - "%s (%d/%d)", - title, song_num, info.songs); - tag_handler_invoke_tag(handler, handler_ctx, - TAG_TITLE, tag_title); - } else - tag_handler_invoke_tag(handler, handler_ctx, TAG_TITLE, title); - - /* artist */ - if (info.numberOfInfoStrings > 1 && info.infoString[1] != nullptr) - tag_handler_invoke_tag(handler, handler_ctx, TAG_ARTIST, - info.infoString[1]); - - /* track */ - char track[16]; - sprintf(track, "%d", song_num); - tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track); - - /* time */ - int song_len=get_song_length(path_fs); - if (song_len >= 0) - tag_handler_invoke_duration(handler, handler_ctx, song_len); - - return true; -} - -static char * -sidplay_container_scan(const char *path_fs, const unsigned int tnum) -{ - SidTune tune(path_fs, nullptr, true); - if (!tune) - return nullptr; - - const SidTuneInfo &info=tune.getInfo(); - - /* Don't treat sids containing a single tune - as containers */ - if(!all_files_are_containers && info.songs<2) - return nullptr; - - /* 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 nullptr; -} - -static const char *const sidplay_suffixes[] = { - "sid", - "mus", - "str", - "prg", - "P00", - nullptr -}; - -extern const struct decoder_plugin sidplay_decoder_plugin; -const struct decoder_plugin sidplay_decoder_plugin = { - "sidplay", - sidplay_init, - sidplay_finish, - nullptr, /* stream_decode() */ - sidplay_file_decode, - sidplay_scan_file, - nullptr, /* stream_tag() */ - sidplay_container_scan, - sidplay_suffixes, - nullptr, /* mime_types */ -}; -- cgit v1.2.3