From 541c31c879beb06899fa5a7eaf55ebcb68a96785 Mon Sep 17 00:00:00 2001 From: GrimReaperFloof Date: Mon, 10 May 2021 21:36:05 +0200 Subject: [PATCH 1/7] Add openmpt decoder plugin --- doc/plugins.rst | 26 +++ meson_options.txt | 1 + python/build/libs.py | 9 + src/decoder/DecoderList.cxx | 4 + src/decoder/plugins/OpenmptDecoderPlugin.cxx | 208 +++++++++++++++++++ src/decoder/plugins/OpenmptDecoderPlugin.hxx | 25 +++ src/decoder/plugins/meson.build | 7 + 7 files changed, 280 insertions(+) create mode 100644 src/decoder/plugins/OpenmptDecoderPlugin.cxx create mode 100644 src/decoder/plugins/OpenmptDecoderPlugin.hxx diff --git a/doc/plugins.rst b/doc/plugins.rst index 021b5f43f..69a1f8361 100644 --- a/doc/plugins.rst +++ b/doc/plugins.rst @@ -494,6 +494,32 @@ Module player based on MODPlug. * - **loop_count** - Number of times to loop the module if it uses backward loops. Default is 0 which prevents looping. -1 loops forever. +openmpt +------- + +Module player based on `libopenmpt `_. + +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Setting + - Description + * - **stereo_separation** + - Sets the stereo separation. The supported value range is [0,200]. Defaults to 100. + * - **interpolation_filter 0|1|2|4|8** + - Sets the interpolation filter. 0: internal default. 1: no interpolation (zero order hold). 2: linear interpolation. 4: cubic interpolation. 8: windowed sinc with 8 taps. Defaults to 0. + * - **override_mptm_interp_filter yes|no** + - If `interpolation_filter` has been changed, setting this to yes will force all MPTM modules to use that interpolation filter. If set to no, MPTM modules will play with their own interpolation filter regardless of the value of `interpolation_filter`. Defaults to no. + * - **volume_ramping** + - Sets the amount of volume ramping done by the libopenmpt mixer. The default value is -1, which indicates a recommended default value. The meaningful value range is [-1..10]. A value of 0 completely disables volume ramping. This might cause clicks in sound output. Higher values imply slower/softer volume ramps. + * - **sync_samples yes|no** + - Syncs sample playback when seeking. Defaults to yes. + * - **emulate_amiga yes|no** + - Enables the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. Defaults to yes. + * - **emulate_amiga_type** + - Configures the filter type to use for the Amiga resampler. Supported values are: "auto": Filter type is chosen by the library and might change. This is the default. "a500": Amiga A500 filter. "a1200": Amiga A1200 filter. "unfiltered": BLEP synthesis without model-specific filters. The LED filter is ignored by this setting. This filter mode is considered to be experimental and might change in the future. Defaults to "auto". + mpcdec ------ diff --git a/meson_options.txt b/meson_options.txt index aaf978f92..3f0b6f71f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -138,6 +138,7 @@ option('gme', type: 'feature', description: 'Game Music Emulator decoder plugin' option('mad', type: 'feature', description: 'MP3 decoder using libmad') option('mikmod', type: 'feature', description: 'MikMod decoder plugin') option('modplug', type: 'feature', description: 'Modplug decoder plugin') +option('openmpt', type: 'feature', description: 'OpenMPT decoder plugin') option('mpcdec', type: 'feature', description: 'Musepack decoder plugin') option('mpg123', type: 'feature', description: 'MP3 decoder using libmpg123') option('opus', type: 'feature', description: 'Opus decoder plugin') diff --git a/python/build/libs.py b/python/build/libs.py index d3e50ab09..419a52a66 100644 --- a/python/build/libs.py +++ b/python/build/libs.py @@ -123,6 +123,15 @@ libmodplug = AutotoolsProject( ], ) +libopenmpt = AutotoolsProject( + 'https://lib.openmpt.org/files/libopenmpt/src/libopenmpt-0.5.8+release.autotools.tar.gz', + '61de7cc0c011b10472ca16adcc123689', + 'lib/libopenmpt.a', + [ + '--disable-shared', '--enable-static' + ], +) + wildmidi = CmakeProject( 'https://codeload.github.com/Mindwerks/wildmidi/tar.gz/wildmidi-0.4.3', '498e5a96455bb4b91b37188ad6dcb070824e92c44f5ed452b90adbaec8eef3c5', diff --git a/src/decoder/DecoderList.cxx b/src/decoder/DecoderList.cxx index e57077920..1c3cdc834 100644 --- a/src/decoder/DecoderList.cxx +++ b/src/decoder/DecoderList.cxx @@ -44,6 +44,7 @@ #include "plugins/WildmidiDecoderPlugin.hxx" #include "plugins/MikmodDecoderPlugin.hxx" #include "plugins/ModplugDecoderPlugin.hxx" +#include "plugins/OpenmptDecoderPlugin.hxx" #include "plugins/MpcdecDecoderPlugin.hxx" #include "plugins/FluidsynthDecoderPlugin.hxx" #include "plugins/SidplayDecoderPlugin.hxx" @@ -90,6 +91,9 @@ constexpr const struct DecoderPlugin *decoder_plugins[] = { #ifdef ENABLE_WAVPACK &wavpack_decoder_plugin, #endif +#ifdef ENABLE_OPENMPT + &openmpt_decoder_plugin, +#endif #ifdef ENABLE_MODPLUG &modplug_decoder_plugin, #endif diff --git a/src/decoder/plugins/OpenmptDecoderPlugin.cxx b/src/decoder/plugins/OpenmptDecoderPlugin.cxx new file mode 100644 index 000000000..fd2a96b5b --- /dev/null +++ b/src/decoder/plugins/OpenmptDecoderPlugin.cxx @@ -0,0 +1,208 @@ +/* + * Copyright 2003-2021 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 "OpenmptDecoderPlugin.hxx" +#include "../DecoderAPI.hxx" +#include "input/InputStream.hxx" +#include "tag/Handler.hxx" +#include "tag/Type.h" +#include "util/WritableBuffer.hxx" +#include "util/Domain.hxx" +#include "util/RuntimeError.hxx" +#include "util/StringView.hxx" +#include "Log.hxx" + +#include + +#include + +static constexpr Domain openmpt_domain("openmpt"); + +static constexpr size_t OPENMPT_FRAME_SIZE = 4096; +static constexpr size_t OPENMPT_PREALLOC_BLOCK = 256 * 1024; +static constexpr int32_t OPENMPT_SAMPLE_RATE = 48000; + +static int openmpt_stereo_separation; +static int openmpt_interpolation_filter; +static bool openmpt_override_mptm_interp_filter; +static int openmpt_volume_ramping; +static bool openmpt_sync_samples; +static bool openmpt_emulate_amiga; +static std::string_view openmpt_emulate_amiga_type; + +static bool +openmpt_decoder_init(const ConfigBlock &block) +{ + openmpt_stereo_separation = block.GetBlockValue("stereo_separation", 100); + openmpt_interpolation_filter = block.GetBlockValue("interpolation_filter", 0); + openmpt_override_mptm_interp_filter = block.GetBlockValue("override_mptm_interp_filter", false); + openmpt_volume_ramping = block.GetBlockValue("volume_ramping", -1); + openmpt_sync_samples = block.GetBlockValue("sync_samples", true); + openmpt_emulate_amiga = block.GetBlockValue("emulate_amiga", true); + openmpt_emulate_amiga_type = block.GetBlockValue("emulate_amiga_type", "auto"); + + return true; +} + +static WritableBuffer +mod_loadfile(DecoderClient *client, InputStream &is) +{ + //known/unknown size, preallocate array, lets read in chunks + + const bool is_stream = !is.KnownSize(); + + WritableBuffer buffer; + if (is_stream) + buffer.size = OPENMPT_PREALLOC_BLOCK; + else { + const auto size = is.GetSize(); + + if (size == 0) { + LogWarning(openmpt_domain, "file is empty"); + return nullptr; + } + + buffer.size = size; + } + + buffer.data = new uint8_t[buffer.size]; + + uint8_t *const end = buffer.end(); + uint8_t *p = buffer.begin(); + + while (true) { + size_t ret = decoder_read(client, is, p, end - p); + if (ret == 0) { + if (is.LockIsEOF()) + /* end of file */ + break; + + /* I/O error - skip this song */ + delete[] buffer.data; + buffer.data = nullptr; + return buffer; + } + + p += ret; + if (p == end) { + if (!is_stream) + break; + + LogWarning(openmpt_domain, "stream too large"); + delete[] buffer.data; + buffer.data = nullptr; + return buffer; + } + } + + buffer.size = p - buffer.data; + return buffer; +} + +static void +mod_decode(DecoderClient &client, InputStream &is) +{ + int ret; + char audio_buffer[OPENMPT_FRAME_SIZE]; + + const auto buffer = mod_loadfile(&client, is); + if (buffer.IsNull()) { + LogWarning(openmpt_domain, "could not load stream"); + return; + } + + openmpt::module mod(buffer.data, buffer.size); + delete[] buffer.data; + + /* alter settings */ + mod.set_render_param(mod.RENDER_STEREOSEPARATION_PERCENT, openmpt_stereo_separation); + mod.set_render_param(mod.RENDER_INTERPOLATIONFILTER_LENGTH, openmpt_interpolation_filter); + if (!openmpt_override_mptm_interp_filter && mod.get_metadata("type") == "mptm") { + /* The MPTM format has a setting for which interpolation filter should be used. + * If we want to play the module back the way the composer intended it, + * we have to set the interpolation filter setting in libopenmpt back to 0: internal default. */ + mod.set_render_param(mod.RENDER_INTERPOLATIONFILTER_LENGTH, 0); + } + mod.set_render_param(mod.RENDER_VOLUMERAMPING_STRENGTH, openmpt_volume_ramping); + mod.ctl_set_boolean("seek.sync_samples", openmpt_sync_samples); + mod.ctl_set_boolean("render.resampler.emulate_amiga", openmpt_emulate_amiga); + mod.ctl_set_text("render.resampler.emulate_amiga_type", openmpt_emulate_amiga_type); + + static constexpr AudioFormat audio_format(OPENMPT_SAMPLE_RATE, SampleFormat::FLOAT, 2); + assert(audio_format.IsValid()); + + client.Ready(audio_format, is.IsSeekable(), + SongTime::FromS(mod.get_duration_seconds())); + + DecoderCommand cmd; + do { + ret = mod.read_interleaved_stereo(OPENMPT_SAMPLE_RATE, OPENMPT_FRAME_SIZE / 2 / sizeof(float), (float*)audio_buffer); + if (ret <= 0) + break; + + cmd = client.SubmitData(nullptr, + audio_buffer, ret * 2 * sizeof(float), + 0); + + if (cmd == DecoderCommand::SEEK) { + mod.set_position_seconds(client.GetSeekTime().ToS()); + client.CommandFinished(); + } + + } while (cmd != DecoderCommand::STOP); +} + +static bool +openmpt_scan_stream(InputStream &is, TagHandler &handler) noexcept +{ + const auto buffer = mod_loadfile(nullptr, is); + if (buffer.IsNull()) { + LogWarning(openmpt_domain, "could not load stream"); + return false; + } + + openmpt::module mod(buffer.data, buffer.size); + delete[] buffer.data; + + handler.OnDuration(SongTime::FromS(mod.get_duration_seconds())); + + /* Tagging */ + handler.OnTag(TAG_TITLE, mod.get_metadata("title").c_str()); + handler.OnTag(TAG_ARTIST, mod.get_metadata("artist").c_str()); + handler.OnTag(TAG_COMMENT, mod.get_metadata("message").c_str()); + handler.OnTag(TAG_DATE, mod.get_metadata("date").c_str()); + handler.OnTag(TAG_PERFORMER, mod.get_metadata("tracker").c_str()); + + return true; +} + +static const char *const mod_suffixes[] = { + "mptm", "mod", "s3m", "xm", "it", "669", "amf", "ams", + "c67", "dbm", "digi", "dmf", "dsm", "dtm", "far", "imf", + "ice", "j2b", "m15", "mdl", "med", "mms", "mt2", "mtm", + "nst", "okt", "plm", "psm", "pt36", "ptm", "sfx", "sfx2", + "st26", "stk", "stm", "stp", "ult", "wow", "gdm", "mo3", + "oxm", "umx", "xpk", "ppm", "mmcmp", + nullptr +}; + +constexpr DecoderPlugin openmpt_decoder_plugin = + DecoderPlugin("openmpt", mod_decode, openmpt_scan_stream) + .WithInit(openmpt_decoder_init) + .WithSuffixes(mod_suffixes); diff --git a/src/decoder/plugins/OpenmptDecoderPlugin.hxx b/src/decoder/plugins/OpenmptDecoderPlugin.hxx new file mode 100644 index 000000000..29377693c --- /dev/null +++ b/src/decoder/plugins/OpenmptDecoderPlugin.hxx @@ -0,0 +1,25 @@ +/* + * Copyright 2003-2021 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. + */ + +#ifndef MPD_DECODER_OPENMPT_HXX +#define MPD_DECODER_OPENMPT_HXX + +extern const struct DecoderPlugin openmpt_decoder_plugin; + +#endif diff --git a/src/decoder/plugins/meson.build b/src/decoder/plugins/meson.build index 3a5233074..f782b7a78 100644 --- a/src/decoder/plugins/meson.build +++ b/src/decoder/plugins/meson.build @@ -108,6 +108,12 @@ if libmodplug_dep.found() ] endif +libopenmpt_dep = dependency('libopenmpt', required: get_option('openmpt')) +decoder_features.set('ENABLE_OPENMPT', libopenmpt_dep.found()) +if libopenmpt_dep.found() + decoder_plugins_sources += 'OpenmptDecoderPlugin.cxx' +endif + libmpcdec_dep = c_compiler.find_library('mpcdec', required: get_option('mpcdec')) decoder_features.set('ENABLE_MPCDEC', libmpcdec_dep.found()) if libmpcdec_dep.found() @@ -188,6 +194,7 @@ decoder_plugins = static_library( libmad_dep, libmikmod_dep, libmodplug_dep, + libopenmpt_dep, libmpcdec_dep, libmpg123_dep, libopus_dep, From fec6aac0f1a18e2dc6dfa56bf71eff647c138d80 Mon Sep 17 00:00:00 2001 From: GrimReaperFloof Date: Tue, 11 May 2021 20:05:26 +0200 Subject: [PATCH 2/7] Code deduplication: move mod_loadfile() into ModCommon.cxx --- src/decoder/plugins/OpenmptDecoderPlugin.cxx | 61 +------------------- src/decoder/plugins/meson.build | 5 +- 2 files changed, 7 insertions(+), 59 deletions(-) diff --git a/src/decoder/plugins/OpenmptDecoderPlugin.cxx b/src/decoder/plugins/OpenmptDecoderPlugin.cxx index fd2a96b5b..6555da94a 100644 --- a/src/decoder/plugins/OpenmptDecoderPlugin.cxx +++ b/src/decoder/plugins/OpenmptDecoderPlugin.cxx @@ -18,6 +18,7 @@ */ #include "OpenmptDecoderPlugin.hxx" +#include "ModCommon.hxx" #include "../DecoderAPI.hxx" #include "input/InputStream.hxx" #include "tag/Handler.hxx" @@ -35,7 +36,6 @@ static constexpr Domain openmpt_domain("openmpt"); static constexpr size_t OPENMPT_FRAME_SIZE = 4096; -static constexpr size_t OPENMPT_PREALLOC_BLOCK = 256 * 1024; static constexpr int32_t OPENMPT_SAMPLE_RATE = 48000; static int openmpt_stereo_separation; @@ -60,68 +60,13 @@ openmpt_decoder_init(const ConfigBlock &block) return true; } -static WritableBuffer -mod_loadfile(DecoderClient *client, InputStream &is) -{ - //known/unknown size, preallocate array, lets read in chunks - - const bool is_stream = !is.KnownSize(); - - WritableBuffer buffer; - if (is_stream) - buffer.size = OPENMPT_PREALLOC_BLOCK; - else { - const auto size = is.GetSize(); - - if (size == 0) { - LogWarning(openmpt_domain, "file is empty"); - return nullptr; - } - - buffer.size = size; - } - - buffer.data = new uint8_t[buffer.size]; - - uint8_t *const end = buffer.end(); - uint8_t *p = buffer.begin(); - - while (true) { - size_t ret = decoder_read(client, is, p, end - p); - if (ret == 0) { - if (is.LockIsEOF()) - /* end of file */ - break; - - /* I/O error - skip this song */ - delete[] buffer.data; - buffer.data = nullptr; - return buffer; - } - - p += ret; - if (p == end) { - if (!is_stream) - break; - - LogWarning(openmpt_domain, "stream too large"); - delete[] buffer.data; - buffer.data = nullptr; - return buffer; - } - } - - buffer.size = p - buffer.data; - return buffer; -} - static void mod_decode(DecoderClient &client, InputStream &is) { int ret; char audio_buffer[OPENMPT_FRAME_SIZE]; - const auto buffer = mod_loadfile(&client, is); + const auto buffer = mod_loadfile(&openmpt_domain, &client, is); if (buffer.IsNull()) { LogWarning(openmpt_domain, "could not load stream"); return; @@ -171,7 +116,7 @@ mod_decode(DecoderClient &client, InputStream &is) static bool openmpt_scan_stream(InputStream &is, TagHandler &handler) noexcept { - const auto buffer = mod_loadfile(nullptr, is); + const auto buffer = mod_loadfile(&openmpt_domain, nullptr, is); if (buffer.IsNull()) { LogWarning(openmpt_domain, "could not load stream"); return false; diff --git a/src/decoder/plugins/meson.build b/src/decoder/plugins/meson.build index f782b7a78..5361f091f 100644 --- a/src/decoder/plugins/meson.build +++ b/src/decoder/plugins/meson.build @@ -111,7 +111,10 @@ endif libopenmpt_dep = dependency('libopenmpt', required: get_option('openmpt')) decoder_features.set('ENABLE_OPENMPT', libopenmpt_dep.found()) if libopenmpt_dep.found() - decoder_plugins_sources += 'OpenmptDecoderPlugin.cxx' + decoder_plugins_sources += [ + 'OpenmptDecoderPlugin.cxx', + 'ModCommon.cxx' + ] endif libmpcdec_dep = c_compiler.find_library('mpcdec', required: get_option('mpcdec')) From 9e407f5989d7792e70dc42522f0b7c64500e2c5b Mon Sep 17 00:00:00 2001 From: GrimReaperFloof Date: Wed, 12 May 2021 20:24:17 +0200 Subject: [PATCH 3/7] Change WritableBuffer to AllocatedArray --- src/decoder/plugins/OpenmptDecoderPlugin.cxx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/decoder/plugins/OpenmptDecoderPlugin.cxx b/src/decoder/plugins/OpenmptDecoderPlugin.cxx index 6555da94a..93693eaac 100644 --- a/src/decoder/plugins/OpenmptDecoderPlugin.cxx +++ b/src/decoder/plugins/OpenmptDecoderPlugin.cxx @@ -23,7 +23,6 @@ #include "input/InputStream.hxx" #include "tag/Handler.hxx" #include "tag/Type.h" -#include "util/WritableBuffer.hxx" #include "util/Domain.hxx" #include "util/RuntimeError.hxx" #include "util/StringView.hxx" @@ -72,8 +71,7 @@ mod_decode(DecoderClient &client, InputStream &is) return; } - openmpt::module mod(buffer.data, buffer.size); - delete[] buffer.data; + openmpt::module mod(buffer.data(), buffer.size()); /* alter settings */ mod.set_render_param(mod.RENDER_STEREOSEPARATION_PERCENT, openmpt_stereo_separation); @@ -122,8 +120,7 @@ openmpt_scan_stream(InputStream &is, TagHandler &handler) noexcept return false; } - openmpt::module mod(buffer.data, buffer.size); - delete[] buffer.data; + openmpt::module mod(buffer.data(), buffer.size()); handler.OnDuration(SongTime::FromS(mod.get_duration_seconds())); From dc5b9d989b1dfabb02c933560c100dee8de4fbab Mon Sep 17 00:00:00 2001 From: GrimReaperFloof Date: Mon, 24 May 2021 16:52:30 +0200 Subject: [PATCH 4/7] Backwards compatibility with older libopenmpt versions than 0.5 --- src/decoder/plugins/OpenmptDecoderPlugin.cxx | 10 ++++++++++ src/decoder/plugins/meson.build | 1 + 2 files changed, 11 insertions(+) diff --git a/src/decoder/plugins/OpenmptDecoderPlugin.cxx b/src/decoder/plugins/OpenmptDecoderPlugin.cxx index 93693eaac..327fd532a 100644 --- a/src/decoder/plugins/OpenmptDecoderPlugin.cxx +++ b/src/decoder/plugins/OpenmptDecoderPlugin.cxx @@ -18,6 +18,7 @@ */ #include "OpenmptDecoderPlugin.hxx" +#include "decoder/Features.h" #include "ModCommon.hxx" #include "../DecoderAPI.hxx" #include "input/InputStream.hxx" @@ -43,7 +44,9 @@ static bool openmpt_override_mptm_interp_filter; static int openmpt_volume_ramping; static bool openmpt_sync_samples; static bool openmpt_emulate_amiga; +#ifdef HAVE_LIBOPENMPT_VERSION_0_5 static std::string_view openmpt_emulate_amiga_type; +#endif static bool openmpt_decoder_init(const ConfigBlock &block) @@ -54,7 +57,9 @@ openmpt_decoder_init(const ConfigBlock &block) openmpt_volume_ramping = block.GetBlockValue("volume_ramping", -1); openmpt_sync_samples = block.GetBlockValue("sync_samples", true); openmpt_emulate_amiga = block.GetBlockValue("emulate_amiga", true); +#ifdef HAVE_LIBOPENMPT_VERSION_0_5 openmpt_emulate_amiga_type = block.GetBlockValue("emulate_amiga_type", "auto"); +#endif return true; } @@ -83,9 +88,14 @@ mod_decode(DecoderClient &client, InputStream &is) mod.set_render_param(mod.RENDER_INTERPOLATIONFILTER_LENGTH, 0); } mod.set_render_param(mod.RENDER_VOLUMERAMPING_STRENGTH, openmpt_volume_ramping); +#ifdef HAVE_LIBOPENMPT_VERSION_0_5 mod.ctl_set_boolean("seek.sync_samples", openmpt_sync_samples); mod.ctl_set_boolean("render.resampler.emulate_amiga", openmpt_emulate_amiga); mod.ctl_set_text("render.resampler.emulate_amiga_type", openmpt_emulate_amiga_type); +#else + mod.ctl_set("seek.sync_samples", std::to_string(openmpt_sync_samples)); + mod.ctl_set("render.resampler.emulate_amiga", std::to_string(openmpt_emulate_amiga)); +#endif static constexpr AudioFormat audio_format(OPENMPT_SAMPLE_RATE, SampleFormat::FLOAT, 2); assert(audio_format.IsValid()); diff --git a/src/decoder/plugins/meson.build b/src/decoder/plugins/meson.build index 5361f091f..6dfb5de7a 100644 --- a/src/decoder/plugins/meson.build +++ b/src/decoder/plugins/meson.build @@ -110,6 +110,7 @@ endif libopenmpt_dep = dependency('libopenmpt', required: get_option('openmpt')) decoder_features.set('ENABLE_OPENMPT', libopenmpt_dep.found()) +decoder_features.set('HAVE_LIBOPENMPT_VERSION_0_5', libopenmpt_dep.version().version_compare('>= 0.5')) if libopenmpt_dep.found() decoder_plugins_sources += [ 'OpenmptDecoderPlugin.cxx', From 6f64fa070d53ae0461ed1adadcc0feb9cac3700d Mon Sep 17 00:00:00 2001 From: GrimReaperFloof Date: Wed, 26 May 2021 23:16:05 +0200 Subject: [PATCH 5/7] Add repeat count setting to openmpt decoder --- doc/plugins.rst | 2 ++ src/decoder/plugins/OpenmptDecoderPlugin.cxx | 3 +++ 2 files changed, 5 insertions(+) diff --git a/doc/plugins.rst b/doc/plugins.rst index 69a1f8361..24acdf619 100644 --- a/doc/plugins.rst +++ b/doc/plugins.rst @@ -505,6 +505,8 @@ Module player based on `libopenmpt `_. * - Setting - Description + * - **repeat_count** + - Set how many times the module repeats. -1: repeat forever. 0: play once, repeat zero times (the default). n>0: play once and repeat n times after that. * - **stereo_separation** - Sets the stereo separation. The supported value range is [0,200]. Defaults to 100. * - **interpolation_filter 0|1|2|4|8** diff --git a/src/decoder/plugins/OpenmptDecoderPlugin.cxx b/src/decoder/plugins/OpenmptDecoderPlugin.cxx index 327fd532a..b6722a62f 100644 --- a/src/decoder/plugins/OpenmptDecoderPlugin.cxx +++ b/src/decoder/plugins/OpenmptDecoderPlugin.cxx @@ -38,6 +38,7 @@ static constexpr Domain openmpt_domain("openmpt"); static constexpr size_t OPENMPT_FRAME_SIZE = 4096; static constexpr int32_t OPENMPT_SAMPLE_RATE = 48000; +static int openmpt_repeat_count; static int openmpt_stereo_separation; static int openmpt_interpolation_filter; static bool openmpt_override_mptm_interp_filter; @@ -51,6 +52,7 @@ static std::string_view openmpt_emulate_amiga_type; static bool openmpt_decoder_init(const ConfigBlock &block) { + openmpt_repeat_count = block.GetBlockValue("repeat_count", 0); openmpt_stereo_separation = block.GetBlockValue("stereo_separation", 100); openmpt_interpolation_filter = block.GetBlockValue("interpolation_filter", 0); openmpt_override_mptm_interp_filter = block.GetBlockValue("override_mptm_interp_filter", false); @@ -79,6 +81,7 @@ mod_decode(DecoderClient &client, InputStream &is) openmpt::module mod(buffer.data(), buffer.size()); /* alter settings */ + mod.set_repeat_count(openmpt_repeat_count); mod.set_render_param(mod.RENDER_STEREOSEPARATION_PERCENT, openmpt_stereo_separation); mod.set_render_param(mod.RENDER_INTERPOLATIONFILTER_LENGTH, openmpt_interpolation_filter); if (!openmpt_override_mptm_interp_filter && mod.get_metadata("type") == "mptm") { From 43a9dc70826e68853c61081a08b858629ae72a34 Mon Sep 17 00:00:00 2001 From: GrimReaperFloof Date: Wed, 26 May 2021 23:33:56 +0200 Subject: [PATCH 6/7] Add note about emulate_amiga_type requiring libopenmpt 0.5 --- doc/plugins.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/plugins.rst b/doc/plugins.rst index 24acdf619..739e506c1 100644 --- a/doc/plugins.rst +++ b/doc/plugins.rst @@ -520,7 +520,7 @@ Module player based on `libopenmpt `_. * - **emulate_amiga yes|no** - Enables the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. Defaults to yes. * - **emulate_amiga_type** - - Configures the filter type to use for the Amiga resampler. Supported values are: "auto": Filter type is chosen by the library and might change. This is the default. "a500": Amiga A500 filter. "a1200": Amiga A1200 filter. "unfiltered": BLEP synthesis without model-specific filters. The LED filter is ignored by this setting. This filter mode is considered to be experimental and might change in the future. Defaults to "auto". + - Configures the filter type to use for the Amiga resampler. Supported values are: "auto": Filter type is chosen by the library and might change. This is the default. "a500": Amiga A500 filter. "a1200": Amiga A1200 filter. "unfiltered": BLEP synthesis without model-specific filters. The LED filter is ignored by this setting. This filter mode is considered to be experimental and might change in the future. Defaults to "auto". Requires libopenmpt 0.5 or higher. mpcdec ------ From 724754f16c92d7ca2031acd6d7d29c2a9b4a3bac Mon Sep 17 00:00:00 2001 From: GrimReaperFloof Date: Thu, 27 May 2021 20:47:45 +0200 Subject: [PATCH 7/7] Fix std::to_string warning for booleans in openmpt decoder --- src/decoder/plugins/OpenmptDecoderPlugin.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/decoder/plugins/OpenmptDecoderPlugin.cxx b/src/decoder/plugins/OpenmptDecoderPlugin.cxx index b6722a62f..bedb8341d 100644 --- a/src/decoder/plugins/OpenmptDecoderPlugin.cxx +++ b/src/decoder/plugins/OpenmptDecoderPlugin.cxx @@ -96,8 +96,8 @@ mod_decode(DecoderClient &client, InputStream &is) mod.ctl_set_boolean("render.resampler.emulate_amiga", openmpt_emulate_amiga); mod.ctl_set_text("render.resampler.emulate_amiga_type", openmpt_emulate_amiga_type); #else - mod.ctl_set("seek.sync_samples", std::to_string(openmpt_sync_samples)); - mod.ctl_set("render.resampler.emulate_amiga", std::to_string(openmpt_emulate_amiga)); + mod.ctl_set("seek.sync_samples", std::to_string((unsigned)openmpt_sync_samples)); + mod.ctl_set("render.resampler.emulate_amiga", std::to_string((unsigned)openmpt_emulate_amiga)); #endif static constexpr AudioFormat audio_format(OPENMPT_SAMPLE_RATE, SampleFormat::FLOAT, 2);