Blob Blame History Raw
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