diff -Naur audacious-plugins-3.10.1-orig/src/openmpt/Makefile audacious-plugins-3.10.1/src/openmpt/Makefile
--- audacious-plugins-3.10.1-orig/src/openmpt/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-3.10.1/src/openmpt/Makefile 2019-12-26 11:31:08.234961926 +0100
@@ -0,0 +1,15 @@
+PLUGIN = openmpt${PLUGIN_SUFFIX}
+
+SRCS = mpt.cc \
+ mptwrap.cc
+
+include ../../buildsys.mk
+include ../../extra.mk
+
+plugindir := ${plugindir}/${INPUT_PLUGIN_DIR}
+
+LD = ${CXX}
+CFLAGS += ${PLUGIN_CFLAGS}
+CXXFLAGS += ${PLUGIN_CFLAGS}
+CPPFLAGS += ${PLUGIN_CPPFLAGS} `pkg-config --cflags libopenmpt` -I../..
+LIBS += `pkg-config --libs libopenmpt`
diff -Naur audacious-plugins-3.10.1-orig/src/openmpt/mpt.cc audacious-plugins-3.10.1/src/openmpt/mpt.cc
--- audacious-plugins-3.10.1-orig/src/openmpt/mpt.cc 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-3.10.1/src/openmpt/mpt.cc 2019-10-29 03:24:11.000000000 +0100
@@ -0,0 +1,167 @@
+/*-
+ * Copyright (c) 2015-2019 Chris Spiegel
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <libaudcore/i18n.h>
+#include <libaudcore/plugin.h>
+#include <libaudcore/preferences.h>
+#include <libaudcore/runtime.h>
+
+#include "mptwrap.h"
+
+static bool force_apply = false;
+
+static constexpr const char *CFG_SECTION = "openmpt";
+static constexpr const char *SETTING_STEREO_SEPARATION = "stereo_separation";
+static constexpr const char *SETTING_INTERPOLATOR = "interpolator";
+
+class MPTPlugin : public InputPlugin
+{
+public:
+ static const char about[];
+ static const char *const exts[];
+ static const PreferencesWidget widgets[];
+ static const PluginPreferences prefs;
+
+ static constexpr PluginInfo info =
+ {
+ N_("OpenMPT (Module Player)"),
+ PACKAGE,
+ about,
+ &prefs,
+ };
+
+ static constexpr auto iinfo = InputInfo(0)
+ /* For continuity, be at a lower priority than modplug for the time being */
+ .with_priority(1)
+ .with_exts(exts);
+
+ constexpr MPTPlugin() : InputPlugin(info, iinfo) { }
+
+ bool init()
+ {
+ static constexpr const char * defaults[] =
+ {
+ SETTING_STEREO_SEPARATION, aud::numeric_string<MPTWrap::default_stereo_separation>::str,
+ SETTING_INTERPOLATOR, aud::numeric_string<MPTWrap::default_interpolator>::str,
+ nullptr,
+ };
+
+ aud_config_set_defaults(CFG_SECTION, defaults);
+
+ return true;
+ }
+
+ bool is_our_file(const char *filename, VFSFile &file)
+ {
+ MPTWrap mpt;
+ return mpt.open(file);
+ }
+
+ bool read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *)
+ {
+ MPTWrap mpt;
+ if (!mpt.open(file))
+ return false;
+
+ tuple.set_filename(filename);
+ tuple.set_format(mpt.format(), mpt.channels(), mpt.rate(), 0);
+
+ tuple.set_int(Tuple::Length, mpt.duration());
+ tuple.set_str(Tuple::Title, mpt.title());
+
+ return true;
+ }
+
+ bool play(const char *filename, VFSFile &file)
+ {
+ MPTWrap mpt;
+ if (!mpt.open(file))
+ return false;
+
+ force_apply = true;
+
+ open_audio(FMT_FLOAT, mpt.rate(), mpt.channels());
+
+ while (!check_stop())
+ {
+ float buffer[16384];
+ int seek_value = check_seek();
+
+ if (seek_value >= 0)
+ mpt.seek(seek_value);
+
+ if (force_apply)
+ {
+ mpt.set_interpolator(aud_get_int(CFG_SECTION, SETTING_INTERPOLATOR));
+ mpt.set_stereo_separation(aud_get_int(CFG_SECTION, SETTING_STEREO_SEPARATION));
+ force_apply = false;
+ }
+
+ auto n = mpt.read(buffer, aud::n_elems(buffer));
+ if (n == 0)
+ break;
+
+ write_audio(buffer, n * sizeof buffer[0]);
+ }
+
+ return true;
+ }
+};
+
+const char MPTPlugin::about[] = N_("Module player based on libopenmpt\n\nWritten by: Chris Spiegel <cspiegel@gmail.com>");
+
+const char *const MPTPlugin::exts[] =
+{
+ "669", "amf", "ams", "dbm", "digi", "dmf", "dsm", "far", "gdm", "ice", "imf",
+ "it", "j2b", "m15", "mdl", "med", "mmcmp", "mms", "mo3", "mod", "mptm", "mt2",
+ "mtm", "nst", "okt", "plm", "ppm", "psm", "pt36", "ptm", "s3m", "sfx", "sfx2",
+ "st26", "stk", "stm", "ult", "umx", "wow", "xm", "xpk",
+ nullptr
+};
+
+static void values_changed()
+{
+ force_apply = true;
+}
+
+const PreferencesWidget MPTPlugin::widgets[] =
+{
+ WidgetSpin(
+ N_("Stereo separation:"),
+ WidgetInt(CFG_SECTION, SETTING_STEREO_SEPARATION, values_changed),
+ { 0.0, 100.0, 1.0, N_("%") }
+ ),
+
+ WidgetCombo(
+ N_("Interpolation:"),
+ WidgetInt(CFG_SECTION, SETTING_INTERPOLATOR, values_changed),
+ { MPTWrap::interpolators }
+ )
+};
+
+const PluginPreferences MPTPlugin::prefs = {{ widgets }};
+
+EXPORT MPTPlugin aud_plugin_instance;
diff -Naur audacious-plugins-3.10.1-orig/src/openmpt/mptwrap.cc audacious-plugins-3.10.1/src/openmpt/mptwrap.cc
--- audacious-plugins-3.10.1-orig/src/openmpt/mptwrap.cc 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-3.10.1/src/openmpt/mptwrap.cc 2019-10-29 03:24:11.000000000 +0100
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 2015-2019 Chris Spiegel
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <algorithm>
+#include <iterator>
+
+#define WANT_VFS_STDIO_COMPAT
+#include <libopenmpt/libopenmpt_version.h>
+#include "mptwrap.h"
+
+constexpr ComboItem MPTWrap::interpolators[];
+constexpr openmpt_stream_callbacks MPTWrap::callbacks;
+
+static String to_aud_str(const char * str)
+{
+ String aud_str(str);
+ openmpt_free_string(str);
+ return aud_str;
+}
+
+bool MPTWrap::open(VFSFile &file)
+{
+#if OPENMPT_API_VERSION_MAJOR <= 0 && OPENMPT_API_VERSION_MINOR < 3
+ auto m = openmpt_module_create(callbacks, &file, openmpt_log_func_silent,
+ nullptr, nullptr);
+#else
+ auto m = openmpt_module_create2(callbacks, &file, openmpt_log_func_silent,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+#endif
+
+ if (m == nullptr)
+ return false;
+
+ mod.capture(m);
+
+ openmpt_module_select_subsong(mod.get(), -1);
+
+ m_duration = openmpt_module_get_duration_seconds(mod.get()) * 1000;
+ m_title = to_aud_str(openmpt_module_get_metadata(mod.get(), "title"));
+ m_format = to_aud_str(openmpt_module_get_metadata(mod.get(), "type_long"));
+
+ return true;
+}
+
+size_t MPTWrap::stream_read(void *instance, void *buf, size_t n)
+{
+ return VFS(instance)->fread(buf, 1, n);
+}
+
+int MPTWrap::stream_seek(void *instance, int64_t offset, int whence)
+{
+ VFSSeekType w = to_vfs_seek_type(whence);
+ return VFS(instance)->fseek(offset, w) >= 0 ? 0 : -1;
+}
+
+int64_t MPTWrap::stream_tell(void *instance)
+{
+ return VFS(instance)->ftell();
+}
+
+bool MPTWrap::is_valid_interpolator(int interpolator_value)
+{
+ return std::any_of(std::begin(interpolators), std::end(interpolators),
+ [interpolator_value](const ComboItem &ci) { return ci.num == interpolator_value; });
+}
+
+void MPTWrap::set_interpolator(int interpolator_value)
+{
+ if (is_valid_interpolator(interpolator_value))
+ openmpt_module_set_render_param(mod.get(),
+ OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH, interpolator_value);
+}
+
+bool MPTWrap::is_valid_stereo_separation(int separation)
+{
+ return separation >= 0 && separation <= 100;
+}
+
+void MPTWrap::set_stereo_separation(int separation)
+{
+ if (is_valid_stereo_separation(separation))
+ openmpt_module_set_render_param(mod.get(),
+ OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT, separation);
+}
+
+int64_t MPTWrap::read(float *buf, int64_t bufcnt)
+{
+ auto n = openmpt_module_read_interleaved_float_stereo(mod.get(), rate(),
+ bufcnt / channels(), buf);
+
+ return n * channels();
+}
+
+void MPTWrap::seek(int pos)
+{
+ openmpt_module_set_position_seconds(mod.get(), pos / 1000.0);
+}
diff -Naur audacious-plugins-3.10.1-orig/src/openmpt/mptwrap.h audacious-plugins-3.10.1/src/openmpt/mptwrap.h
--- audacious-plugins-3.10.1-orig/src/openmpt/mptwrap.h 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-3.10.1/src/openmpt/mptwrap.h 2019-10-29 03:24:11.000000000 +0100
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2015-2019 Chris Spiegel
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef AUDACIOUS_MPT_MPTWRAP_H
+#define AUDACIOUS_MPT_MPTWRAP_H
+
+#include <libaudcore/i18n.h>
+#include <libaudcore/preferences.h>
+#include <libaudcore/vfs.h>
+
+#include <libopenmpt/libopenmpt.h>
+#include <libopenmpt/libopenmpt_stream_callbacks_file.h>
+
+class MPTWrap
+{
+public:
+ static constexpr int interp_none = 1;
+ static constexpr int interp_linear = 2;
+ static constexpr int interp_cubic = 4;
+ static constexpr int interp_windowed = 8;
+
+ static constexpr int default_interpolator = interp_windowed;
+ static constexpr int default_stereo_separation = 70;
+
+ static constexpr ComboItem interpolators[] =
+ {
+ {N_("None"), interp_none},
+ {N_("Linear"), interp_linear},
+ {N_("Cubic"), interp_cubic},
+ {N_("Windowed sinc"), interp_windowed}
+ };
+
+ static bool is_valid_interpolator(int);
+ void set_interpolator(int);
+
+ static bool is_valid_stereo_separation(int);
+ void set_stereo_separation(int);
+
+ bool open(VFSFile &);
+ int64_t read(float *, int64_t);
+ void seek(int pos);
+
+ static constexpr int rate() { return 48000; }
+ static constexpr int channels() { return 2; }
+
+ int duration() const { return m_duration; }
+ const String & title() const { return m_title; }
+ const String & format() const { return m_format; }
+
+private:
+ static size_t stream_read(void *, void *, size_t);
+ static int stream_seek(void *, int64_t, int);
+ static int64_t stream_tell(void *);
+ static VFSFile *VFS(void *instance) { return reinterpret_cast<VFSFile *>(instance); }
+
+ static constexpr openmpt_stream_callbacks callbacks = { stream_read, stream_seek, stream_tell };
+
+ SmartPtr<openmpt_module, openmpt_module_destroy> mod;
+
+ int m_duration = 0;
+ String m_title;
+ String m_format;
+};
+
+#endif