diff --git a/NEWS b/NEWS index 1046b4066..d47e97a48 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ ver 0.19.18 (not yet released) - sidplay: detect libsidplay2 with pkg-config - sidplay: log detailed error message - sidplay: read the "date" tag + - sidplay: allow building with libsidplayfp instead of libsidplay2 * output - shout: recognize setting "encoder" instead of "encoding" * require gcc 4.7 or newer diff --git a/configure.ac b/configure.ac index b67b5aeff..1a3a20c12 100644 --- a/configure.ac +++ b/configure.ac @@ -1333,6 +1333,14 @@ AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enab dnl --------------------------------- sidplay --------------------------------- if test x$enable_sidplay != xno; then + dnl Check for libsidplayfp first + PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp libsidutils], + [found_sidplayfp=yes], + [found_sidplayfp=no]) + found_sidplay=$found_sidplayfp +fi + +if test x$enable_sidplay != xno && test x$found_sidplayfp = xno; then PKG_CHECK_MODULES([SIDPLAY], [libsidplay2 libsidutils], [found_sidplay=yes], [found_sidplay=no]) @@ -1341,7 +1349,7 @@ if test x$enable_sidplay != xno; then [libsidplay2 not found]) fi -if test x$enable_sidplay != xno; then +if test x$enable_sidplay != xno && test x$found_sidplayfp = xno; then AC_CHECK_LIB([resid-builder], [main], [found_sidplay=yes], [found_sidplay=no]) @@ -1352,6 +1360,9 @@ fi if test x$enable_sidplay = xyes; then SIDPLAY_LIBS="$SIDPLAY_LIBS -lresid-builder" AC_DEFINE(ENABLE_SIDPLAY, 1, [Define for libsidplay2 support]) + if test x$found_sidplayfp = xyes; then + AC_DEFINE(HAVE_SIDPLAYFP, 1, [Define if libsidplayfp is used instead of libsidplay2]) + fi fi AM_CONDITIONAL(ENABLE_SIDPLAY, test x$enable_sidplay = xyes) diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx index 1ab73d056..db4070bfb 100644 --- a/src/decoder/plugins/SidplayDecoderPlugin.cxx +++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx @@ -23,6 +23,7 @@ #include "tag/TagHandler.hxx" #include "fs/Path.hxx" #include "fs/AllocatedPath.hxx" +#include "util/Macros.hxx" #include "util/FormatString.hxx" #include "util/Domain.hxx" #include "util/Error.hxx" @@ -32,10 +33,21 @@ #include +#ifdef HAVE_SIDPLAYFP +#include +#include +#include +#include +#include +#include +#include +#include +#else #include #include #include #include +#endif #define SUBTUNE_PREFIX "tune_" @@ -52,7 +64,12 @@ static SidDatabase * sidplay_load_songlength_db(const Path path) { SidDatabase *db = new SidDatabase(); - if (db->open(path.c_str()) < 0) { +#ifdef HAVE_SIDPLAYFP + bool error = !db->open(path.c_str()); +#else + bool error = db->open(path.c_str()) < 0; +#endif + if (error) { FormatError(sidplay_domain, "unable to read songlengths file %s: %s", path.c_str(), db->error()); @@ -128,7 +145,23 @@ ParseContainerPath(Path path_fs) return { path_fs.GetDirectoryName(), track }; } -/* get the song length in seconds */ +#ifdef HAVE_SIDPLAYFP + +static SignedSongTime +get_song_length(SidTune &tune) +{ + if (songlength_database == nullptr) + return SignedSongTime::Negative(); + + const auto length = songlength_database->length(tune); + if (length < 0) + return SignedSongTime::Negative(); + + return SignedSongTime::FromS(length); +} + +#else + static SignedSongTime get_song_length(SidTuneMod &tune) { @@ -144,6 +177,8 @@ get_song_length(SidTuneMod &tune) return SignedSongTime::FromS(length); } +#endif + static void sidplay_file_decode(Decoder &decoder, Path path_fs) { @@ -152,10 +187,19 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) /* load the tune */ const auto container = ParseContainerPath(path_fs); +#ifdef HAVE_SIDPLAYFP + SidTune tune(container.path.c_str()); +#else SidTuneMod tune(container.path.c_str()); +#endif if (!tune.getStatus()) { +#ifdef HAVE_SIDPLAYFP + const char *error = tune.statusString(); +#else + const char *error = tune.getInfo().statusString; +#endif FormatWarning(sidplay_domain, "failed to load file: %s", - tune.getInfo().statusString); + error); return; } @@ -168,9 +212,17 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) /* initialize the player */ +#ifdef HAVE_SIDPLAYFP + sidplayfp player; +#else sidplay2 player; - int iret = player.load(&tune); - if (iret != 0) { +#endif +#ifdef HAVE_SIDPLAYFP + bool error = !player.load(&tune); +#else + bool error = player.load(&tune) < 0; +#endif + if (error) { FormatWarning(sidplay_domain, "sidplay2.load() failed: %s", player.error()); return; @@ -178,6 +230,23 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) /* initialize the builder */ +#ifdef HAVE_SIDPLAYFP + ReSIDfpBuilder builder("ReSID"); + if (!builder.getStatus()) { + FormatWarning(sidplay_domain, + "failed to initialize ReSIDfpBuilder: %s", + builder.error()); + return; + } + + builder.create(player.info().maxsids()); + if (!builder.getStatus()) { + FormatWarning(sidplay_domain, + "ReSIDfpBuilder.create() failed: %s", + builder.error()); + return; + } +#else ReSIDBuilder builder("ReSID"); builder.create(player.info().maxsids); if (!builder) { @@ -185,42 +254,80 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) builder.error()); return; } +#endif builder.filter(filter_setting); +#ifdef HAVE_SIDPLAYFP + if (!builder.getStatus()) { + FormatWarning(sidplay_domain, + "ReSIDfpBuilder.filter() failed: %s", + builder.error()); + return; + } +#else if (!builder) { FormatWarning(sidplay_domain, "ReSIDBuilder.filter() failed: %s", builder.error()); return; } +#endif /* configure the player */ - sid2_config_t config = player.config(); + auto config = player.config(); +#ifndef HAVE_SIDPLAYFP config.clockDefault = SID2_CLOCK_PAL; config.clockForced = true; config.clockSpeed = SID2_CLOCK_CORRECT; +#endif config.frequency = 48000; +#ifndef HAVE_SIDPLAYFP config.optimisation = SID2_DEFAULT_OPTIMISATION; config.precision = 16; config.sidDefault = SID2_MOS6581; +#endif config.sidEmulation = &builder; +#ifdef HAVE_SIDPLAYFP + config.samplingMethod = SidConfig::INTERPOLATE; + config.fastSampling = false; +#else config.sidModel = SID2_MODEL_CORRECT; config.sidSamples = true; config.sampleFormat = IsLittleEndian() ? SID2_LITTLE_SIGNED : SID2_BIG_SIGNED; - if (tune.isStereo()) { +#endif + +#ifdef HAVE_SIDPLAYFP + const bool stereo = tune.getInfo()->sidChips() >= 2; +#else + const bool stereo = tune.isStereo(); +#endif + + if (stereo) { +#ifdef HAVE_SIDPLAYFP + config.playback = SidConfig::STEREO; +#else config.playback = sid2_stereo; +#endif channels = 2; } else { +#ifdef HAVE_SIDPLAYFP + config.playback = SidConfig::MONO; +#else config.playback = sid2_mono; +#endif channels = 1; } - iret = player.config(config); - if (iret != 0) { +#ifdef HAVE_SIDPLAYFP + error = !player.config(config); +#else + error = player.config(config) < 0; +#endif + if (error) { FormatWarning(sidplay_domain, "sidplay2.config() failed: %s", player.error()); return; @@ -235,17 +342,21 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) /* .. and play */ +#ifdef HAVE_SIDPLAYFP + constexpr unsigned timebase = 1; +#else const unsigned timebase = player.timebase(); +#endif const unsigned end = duration.IsNegative() ? 0u : duration.ToScale(timebase); DecoderCommand cmd; do { - char buffer[4096]; + short buffer[4096]; size_t nbytes; - nbytes = player.play(buffer, sizeof(buffer)); + nbytes = player.play(buffer, ARRAY_SIZE(buffer)); if (nbytes == 0) break; @@ -266,7 +377,7 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) /* ignore data until target time is reached */ while(data_time i + ? info.infoString(i) + : nullptr; +#else return info.numberOfInfoStrings > i ? info.infoString[i] : nullptr; - +#endif } static bool @@ -298,24 +414,34 @@ sidplay_scan_file(Path path_fs, const auto container = ParseContainerPath(path_fs); const unsigned song_num = container.track; +#ifdef HAVE_SIDPLAYFP + SidTune tune(container.path.c_str()); +#else SidTuneMod tune(container.path.c_str()); +#endif if (!tune.getStatus()) return false; tune.selectSong(song_num); +#ifdef HAVE_SIDPLAYFP + const SidTuneInfo &info = *tune.getInfo(); + const unsigned n_tracks = info.songs(); +#else const SidTuneInfo &info = tune.getInfo(); + const unsigned n_tracks = info.songs; +#endif /* title */ const char *title = GetInfoString(info, 0); if (title == nullptr) title = ""; - if(info.songs>1) { + if (n_tracks > 1) { char tag_title[1024]; snprintf(tag_title, sizeof(tag_title), - "%s (%d/%d)", - title, song_num, info.songs); + "%s (%d/%u)", + title, song_num, n_tracks); tag_handler_invoke_tag(handler, handler_ctx, TAG_TITLE, tag_title); } else @@ -351,19 +477,25 @@ static char * sidplay_container_scan(Path path_fs, const unsigned int tnum) { SidTune tune(path_fs.c_str(), nullptr, true); - if (!tune) + if (!tune.getStatus()) return nullptr; - const SidTuneInfo &info=tune.getInfo(); +#ifdef HAVE_SIDPLAYFP + const SidTuneInfo &info = *tune.getInfo(); + const unsigned n_tracks = info.songs(); +#else + const SidTuneInfo &info = tune.getInfo(); + const unsigned n_tracks = info.songs; +#endif /* Don't treat sids containing a single tune as containers */ - if(!all_files_are_containers && info.songs<2) + if(!all_files_are_containers && n_tracks < 2) return nullptr; /* Construct container/tune path names, eg. Delta.sid/tune_001.sid */ - if(tnum<=info.songs) { + if (tnum <= n_tracks) { return FormatNew(SUBTUNE_PREFIX "%03u.sid", tnum); } else return nullptr;