decoder/sidplay: allow building with libsidplayfp instead of libsidplay2

https://bugs.musicpd.org/view.php?id=4558
This commit is contained in:
Max Kellermann 2016-07-29 15:31:02 +02:00
parent 7fb2f15a1a
commit 762f3afb9d
3 changed files with 165 additions and 21 deletions

1
NEWS
View File

@ -6,6 +6,7 @@ ver 0.19.18 (not yet released)
- sidplay: detect libsidplay2 with pkg-config - sidplay: detect libsidplay2 with pkg-config
- sidplay: log detailed error message - sidplay: log detailed error message
- sidplay: read the "date" tag - sidplay: read the "date" tag
- sidplay: allow building with libsidplayfp instead of libsidplay2
* output * output
- shout: recognize setting "encoder" instead of "encoding" - shout: recognize setting "encoder" instead of "encoding"
* require gcc 4.7 or newer * require gcc 4.7 or newer

View File

@ -1333,6 +1333,14 @@ AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enab
dnl --------------------------------- sidplay --------------------------------- dnl --------------------------------- sidplay ---------------------------------
if test x$enable_sidplay != xno; then 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], PKG_CHECK_MODULES([SIDPLAY], [libsidplay2 libsidutils],
[found_sidplay=yes], [found_sidplay=yes],
[found_sidplay=no]) [found_sidplay=no])
@ -1341,7 +1349,7 @@ if test x$enable_sidplay != xno; then
[libsidplay2 not found]) [libsidplay2 not found])
fi 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], AC_CHECK_LIB([resid-builder], [main],
[found_sidplay=yes], [found_sidplay=no]) [found_sidplay=yes], [found_sidplay=no])
@ -1352,6 +1360,9 @@ fi
if test x$enable_sidplay = xyes; then if test x$enable_sidplay = xyes; then
SIDPLAY_LIBS="$SIDPLAY_LIBS -lresid-builder" SIDPLAY_LIBS="$SIDPLAY_LIBS -lresid-builder"
AC_DEFINE(ENABLE_SIDPLAY, 1, [Define for libsidplay2 support]) 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 fi
AM_CONDITIONAL(ENABLE_SIDPLAY, test x$enable_sidplay = xyes) AM_CONDITIONAL(ENABLE_SIDPLAY, test x$enable_sidplay = xyes)

View File

@ -23,6 +23,7 @@
#include "tag/TagHandler.hxx" #include "tag/TagHandler.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "util/Macros.hxx"
#include "util/FormatString.hxx" #include "util/FormatString.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
@ -32,10 +33,21 @@
#include <string.h> #include <string.h>
#ifdef HAVE_SIDPLAYFP
#include <sidplayfp/sidplayfp.h>
#include <sidplayfp/SidInfo.h>
#include <sidplayfp/SidConfig.h>
#include <sidplayfp/SidTune.h>
#include <sidplayfp/SidTuneInfo.h>
#include <sidplayfp/builders/resid.h>
#include <sidplayfp/builders/residfp.h>
#include <sidplayfp/SidDatabase.h>
#else
#include <sidplay/sidplay2.h> #include <sidplay/sidplay2.h>
#include <sidplay/builders/resid.h> #include <sidplay/builders/resid.h>
#include <sidplay/utils/SidTuneMod.h> #include <sidplay/utils/SidTuneMod.h>
#include <sidplay/utils/SidDatabase.h> #include <sidplay/utils/SidDatabase.h>
#endif
#define SUBTUNE_PREFIX "tune_" #define SUBTUNE_PREFIX "tune_"
@ -52,7 +64,12 @@ static SidDatabase *
sidplay_load_songlength_db(const Path path) sidplay_load_songlength_db(const Path path)
{ {
SidDatabase *db = new SidDatabase(); 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, FormatError(sidplay_domain,
"unable to read songlengths file %s: %s", "unable to read songlengths file %s: %s",
path.c_str(), db->error()); path.c_str(), db->error());
@ -128,7 +145,23 @@ ParseContainerPath(Path path_fs)
return { path_fs.GetDirectoryName(), track }; 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 static SignedSongTime
get_song_length(SidTuneMod &tune) get_song_length(SidTuneMod &tune)
{ {
@ -144,6 +177,8 @@ get_song_length(SidTuneMod &tune)
return SignedSongTime::FromS(length); return SignedSongTime::FromS(length);
} }
#endif
static void static void
sidplay_file_decode(Decoder &decoder, Path path_fs) sidplay_file_decode(Decoder &decoder, Path path_fs)
{ {
@ -152,10 +187,19 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
/* load the tune */ /* load the tune */
const auto container = ParseContainerPath(path_fs); const auto container = ParseContainerPath(path_fs);
#ifdef HAVE_SIDPLAYFP
SidTune tune(container.path.c_str());
#else
SidTuneMod tune(container.path.c_str()); SidTuneMod tune(container.path.c_str());
#endif
if (!tune.getStatus()) { 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", FormatWarning(sidplay_domain, "failed to load file: %s",
tune.getInfo().statusString); error);
return; return;
} }
@ -168,9 +212,17 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
/* initialize the player */ /* initialize the player */
#ifdef HAVE_SIDPLAYFP
sidplayfp player;
#else
sidplay2 player; sidplay2 player;
int iret = player.load(&tune); #endif
if (iret != 0) { #ifdef HAVE_SIDPLAYFP
bool error = !player.load(&tune);
#else
bool error = player.load(&tune) < 0;
#endif
if (error) {
FormatWarning(sidplay_domain, FormatWarning(sidplay_domain,
"sidplay2.load() failed: %s", player.error()); "sidplay2.load() failed: %s", player.error());
return; return;
@ -178,6 +230,23 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
/* initialize the builder */ /* 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"); ReSIDBuilder builder("ReSID");
builder.create(player.info().maxsids); builder.create(player.info().maxsids);
if (!builder) { if (!builder) {
@ -185,42 +254,80 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
builder.error()); builder.error());
return; return;
} }
#endif
builder.filter(filter_setting); builder.filter(filter_setting);
#ifdef HAVE_SIDPLAYFP
if (!builder.getStatus()) {
FormatWarning(sidplay_domain,
"ReSIDfpBuilder.filter() failed: %s",
builder.error());
return;
}
#else
if (!builder) { if (!builder) {
FormatWarning(sidplay_domain, "ReSIDBuilder.filter() failed: %s", FormatWarning(sidplay_domain, "ReSIDBuilder.filter() failed: %s",
builder.error()); builder.error());
return; return;
} }
#endif
/* configure the player */ /* configure the player */
sid2_config_t config = player.config(); auto config = player.config();
#ifndef HAVE_SIDPLAYFP
config.clockDefault = SID2_CLOCK_PAL; config.clockDefault = SID2_CLOCK_PAL;
config.clockForced = true; config.clockForced = true;
config.clockSpeed = SID2_CLOCK_CORRECT; config.clockSpeed = SID2_CLOCK_CORRECT;
#endif
config.frequency = 48000; config.frequency = 48000;
#ifndef HAVE_SIDPLAYFP
config.optimisation = SID2_DEFAULT_OPTIMISATION; config.optimisation = SID2_DEFAULT_OPTIMISATION;
config.precision = 16; config.precision = 16;
config.sidDefault = SID2_MOS6581; config.sidDefault = SID2_MOS6581;
#endif
config.sidEmulation = &builder; config.sidEmulation = &builder;
#ifdef HAVE_SIDPLAYFP
config.samplingMethod = SidConfig::INTERPOLATE;
config.fastSampling = false;
#else
config.sidModel = SID2_MODEL_CORRECT; config.sidModel = SID2_MODEL_CORRECT;
config.sidSamples = true; config.sidSamples = true;
config.sampleFormat = IsLittleEndian() config.sampleFormat = IsLittleEndian()
? SID2_LITTLE_SIGNED ? SID2_LITTLE_SIGNED
: SID2_BIG_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; config.playback = sid2_stereo;
#endif
channels = 2; channels = 2;
} else { } else {
#ifdef HAVE_SIDPLAYFP
config.playback = SidConfig::MONO;
#else
config.playback = sid2_mono; config.playback = sid2_mono;
#endif
channels = 1; channels = 1;
} }
iret = player.config(config); #ifdef HAVE_SIDPLAYFP
if (iret != 0) { error = !player.config(config);
#else
error = player.config(config) < 0;
#endif
if (error) {
FormatWarning(sidplay_domain, FormatWarning(sidplay_domain,
"sidplay2.config() failed: %s", player.error()); "sidplay2.config() failed: %s", player.error());
return; return;
@ -235,17 +342,21 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
/* .. and play */ /* .. and play */
#ifdef HAVE_SIDPLAYFP
constexpr unsigned timebase = 1;
#else
const unsigned timebase = player.timebase(); const unsigned timebase = player.timebase();
#endif
const unsigned end = duration.IsNegative() const unsigned end = duration.IsNegative()
? 0u ? 0u
: duration.ToScale<uint64_t>(timebase); : duration.ToScale<uint64_t>(timebase);
DecoderCommand cmd; DecoderCommand cmd;
do { do {
char buffer[4096]; short buffer[4096];
size_t nbytes; size_t nbytes;
nbytes = player.play(buffer, sizeof(buffer)); nbytes = player.play(buffer, ARRAY_SIZE(buffer));
if (nbytes == 0) if (nbytes == 0)
break; break;
@ -266,7 +377,7 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
/* ignore data until target time is reached */ /* ignore data until target time is reached */
while(data_time<target_time) { while(data_time<target_time) {
nbytes=player.play(buffer, sizeof(buffer)); nbytes=player.play(buffer, ARRAY_SIZE(buffer));
if(nbytes==0) if(nbytes==0)
break; break;
data_time = player.time(); data_time = player.time();
@ -285,10 +396,15 @@ gcc_pure
static const char * static const char *
GetInfoString(const SidTuneInfo &info, unsigned i) GetInfoString(const SidTuneInfo &info, unsigned i)
{ {
#ifdef HAVE_SIDPLAYFP
return info.numberOfInfoStrings() > i
? info.infoString(i)
: nullptr;
#else
return info.numberOfInfoStrings > i return info.numberOfInfoStrings > i
? info.infoString[i] ? info.infoString[i]
: nullptr; : nullptr;
#endif
} }
static bool static bool
@ -298,24 +414,34 @@ sidplay_scan_file(Path path_fs,
const auto container = ParseContainerPath(path_fs); const auto container = ParseContainerPath(path_fs);
const unsigned song_num = container.track; const unsigned song_num = container.track;
#ifdef HAVE_SIDPLAYFP
SidTune tune(container.path.c_str());
#else
SidTuneMod tune(container.path.c_str()); SidTuneMod tune(container.path.c_str());
#endif
if (!tune.getStatus()) if (!tune.getStatus())
return false; return false;
tune.selectSong(song_num); 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 SidTuneInfo &info = tune.getInfo();
const unsigned n_tracks = info.songs;
#endif
/* title */ /* title */
const char *title = GetInfoString(info, 0); const char *title = GetInfoString(info, 0);
if (title == nullptr) if (title == nullptr)
title = ""; title = "";
if(info.songs>1) { if (n_tracks > 1) {
char tag_title[1024]; char tag_title[1024];
snprintf(tag_title, sizeof(tag_title), snprintf(tag_title, sizeof(tag_title),
"%s (%d/%d)", "%s (%d/%u)",
title, song_num, info.songs); title, song_num, n_tracks);
tag_handler_invoke_tag(handler, handler_ctx, tag_handler_invoke_tag(handler, handler_ctx,
TAG_TITLE, tag_title); TAG_TITLE, tag_title);
} else } else
@ -351,19 +477,25 @@ static char *
sidplay_container_scan(Path path_fs, const unsigned int tnum) sidplay_container_scan(Path path_fs, const unsigned int tnum)
{ {
SidTune tune(path_fs.c_str(), nullptr, true); SidTune tune(path_fs.c_str(), nullptr, true);
if (!tune) if (!tune.getStatus())
return nullptr; 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 /* Don't treat sids containing a single tune
as containers */ as containers */
if(!all_files_are_containers && info.songs<2) if(!all_files_are_containers && n_tracks < 2)
return nullptr; return nullptr;
/* Construct container/tune path names, eg. /* Construct container/tune path names, eg.
Delta.sid/tune_001.sid */ Delta.sid/tune_001.sid */
if(tnum<=info.songs) { if (tnum <= n_tracks) {
return FormatNew(SUBTUNE_PREFIX "%03u.sid", tnum); return FormatNew(SUBTUNE_PREFIX "%03u.sid", tnum);
} else } else
return nullptr; return nullptr;