aboutsummaryrefslogtreecommitdiffstats
path: root/src/decoder/MikmodDecoderPlugin.cxx
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2013-07-28 12:54:59 +0200
committerMax Kellermann <max@duempel.org>2013-07-28 13:03:04 +0200
commit1688b6dda9c510a5737ae3eb192b56166e497fc5 (patch)
tree1cfecc376dc36ce91eee8965cb9562545fdc59ac /src/decoder/MikmodDecoderPlugin.cxx
parent33aedc887acc4c52e140ba93df55f1825a2ebb10 (diff)
downloadmpd-1688b6dda9c510a5737ae3eb192b56166e497fc5.tar.gz
mpd-1688b6dda9c510a5737ae3eb192b56166e497fc5.tar.xz
mpd-1688b6dda9c510a5737ae3eb192b56166e497fc5.zip
decoder/mikmod: convert to C++
Diffstat (limited to 'src/decoder/MikmodDecoderPlugin.cxx')
-rw-r--r--src/decoder/MikmodDecoderPlugin.cxx240
1 files changed, 240 insertions, 0 deletions
diff --git a/src/decoder/MikmodDecoderPlugin.cxx b/src/decoder/MikmodDecoderPlugin.cxx
new file mode 100644
index 000000000..94dff0856
--- /dev/null
+++ b/src/decoder/MikmodDecoderPlugin.cxx
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2003-2013 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 "config.h"
+#include "MikmodDecoderPlugin.hxx"
+#include "decoder_api.h"
+#include "mpd_error.h"
+#include "tag_handler.h"
+
+#include <glib.h>
+#include <mikmod.h>
+#include <assert.h>
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "mikmod"
+
+/* this is largely copied from alsaplayer */
+
+static constexpr size_t MIKMOD_FRAME_SIZE = 4096;
+
+static BOOL
+mikmod_mpd_init(void)
+{
+ return VC_Init();
+}
+
+static void
+mikmod_mpd_exit(void)
+{
+ VC_Exit();
+}
+
+static void
+mikmod_mpd_update(void)
+{
+}
+
+static BOOL
+mikmod_mpd_is_present(void)
+{
+ return true;
+}
+
+static char drv_name[] = PACKAGE_NAME;
+static char drv_version[] = VERSION;
+
+#if (LIBMIKMOD_VERSION > 0x030106)
+static char drv_alias[] = PACKAGE;
+#endif
+
+static MDRIVER drv_mpd = {
+ nullptr,
+ drv_name,
+ drv_version,
+ 0,
+ 255,
+#if (LIBMIKMOD_VERSION > 0x030106)
+ drv_alias,
+#if (LIBMIKMOD_VERSION >= 0x030200)
+ nullptr, /* CmdLineHelp */
+#endif
+ nullptr, /* CommandLine */
+#endif
+ mikmod_mpd_is_present,
+ VC_SampleLoad,
+ VC_SampleUnload,
+ VC_SampleSpace,
+ VC_SampleLength,
+ mikmod_mpd_init,
+ mikmod_mpd_exit,
+ nullptr,
+ VC_SetNumVoices,
+ VC_PlayStart,
+ VC_PlayStop,
+ mikmod_mpd_update,
+ nullptr,
+ VC_VoiceSetVolume,
+ VC_VoiceGetVolume,
+ VC_VoiceSetFrequency,
+ VC_VoiceGetFrequency,
+ VC_VoiceSetPanning,
+ VC_VoiceGetPanning,
+ VC_VoicePlay,
+ VC_VoiceStop,
+ VC_VoiceStopped,
+ VC_VoiceGetPosition,
+ VC_VoiceRealVolume
+};
+
+static unsigned mikmod_sample_rate;
+
+static bool
+mikmod_decoder_init(const struct config_param *param)
+{
+ static char params[] = "";
+
+ mikmod_sample_rate = config_get_block_unsigned(param, "sample_rate",
+ 44100);
+ if (!audio_valid_sample_rate(mikmod_sample_rate))
+ MPD_ERROR("Invalid sample rate in line %d: %u",
+ param->line, mikmod_sample_rate);
+
+ md_device = 0;
+ md_reverb = 0;
+
+ MikMod_RegisterDriver(&drv_mpd);
+ MikMod_RegisterAllLoaders();
+
+ md_pansep = 64;
+ md_mixfreq = mikmod_sample_rate;
+ md_mode = (DMODE_SOFT_MUSIC | DMODE_INTERP | DMODE_STEREO |
+ DMODE_16BITS);
+
+ if (MikMod_Init(params)) {
+ g_warning("Could not init MikMod: %s\n",
+ MikMod_strerror(MikMod_errno));
+ return false;
+ }
+
+ return true;
+}
+
+static void
+mikmod_decoder_finish(void)
+{
+ MikMod_Exit();
+}
+
+static void
+mikmod_decoder_file_decode(struct decoder *decoder, const char *path_fs)
+{
+ char *path2;
+ MODULE *handle;
+ struct audio_format audio_format;
+ int ret;
+ SBYTE buffer[MIKMOD_FRAME_SIZE];
+ enum decoder_command cmd = DECODE_COMMAND_NONE;
+
+ path2 = g_strdup(path_fs);
+ handle = Player_Load(path2, 128, 0);
+ g_free(path2);
+
+ if (handle == nullptr) {
+ g_warning("failed to open mod: %s", path_fs);
+ return;
+ }
+
+ /* Prevent module from looping forever */
+ handle->loop = 0;
+
+ audio_format_init(&audio_format, mikmod_sample_rate, SAMPLE_FORMAT_S16, 2);
+ assert(audio_format_valid(&audio_format));
+
+ decoder_initialized(decoder, &audio_format, false, 0);
+
+ Player_Start(handle);
+ while (cmd == DECODE_COMMAND_NONE && Player_Active()) {
+ ret = VC_WriteBytes(buffer, sizeof(buffer));
+ cmd = decoder_data(decoder, nullptr, buffer, ret, 0);
+ }
+
+ Player_Stop();
+ Player_Free(handle);
+}
+
+static bool
+mikmod_decoder_scan_file(const char *path_fs,
+ const struct tag_handler *handler, void *handler_ctx)
+{
+ char *path2 = g_strdup(path_fs);
+ MODULE *handle = Player_Load(path2, 128, 0);
+
+ if (handle == nullptr) {
+ g_free(path2);
+ g_debug("Failed to open file: %s", path_fs);
+ return false;
+
+ }
+
+ Player_Free(handle);
+
+ char *title = Player_LoadTitle(path2);
+ g_free(path2);
+
+ if (title != nullptr) {
+ tag_handler_invoke_tag(handler, handler_ctx,
+ TAG_TITLE, title);
+ free(title);
+ }
+
+ return true;
+}
+
+static const char *const mikmod_decoder_suffixes[] = {
+ "amf",
+ "dsm",
+ "far",
+ "gdm",
+ "imf",
+ "it",
+ "med",
+ "mod",
+ "mtm",
+ "s3m",
+ "stm",
+ "stx",
+ "ult",
+ "uni",
+ "xm",
+ nullptr
+};
+
+const struct decoder_plugin mikmod_decoder_plugin = {
+ "mikmod",
+ mikmod_decoder_init,
+ mikmod_decoder_finish,
+ nullptr,
+ mikmod_decoder_file_decode,
+ mikmod_decoder_scan_file,
+ nullptr,
+ nullptr,
+ mikmod_decoder_suffixes,
+ nullptr,
+};