From 2eed9d64ce89071e0f1221931c789efabc48f0ae Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 28 Jul 2013 12:56:35 +0200 Subject: decoder/modplug: convert to C++ --- src/DecoderList.cxx | 2 +- src/decoder/ModplugDecoderPlugin.cxx | 201 +++++++++++++++++++++++++++++++++++ src/decoder/ModplugDecoderPlugin.hxx | 25 +++++ src/decoder/modplug_decoder_plugin.c | 197 ---------------------------------- 4 files changed, 227 insertions(+), 198 deletions(-) create mode 100644 src/decoder/ModplugDecoderPlugin.cxx create mode 100644 src/decoder/ModplugDecoderPlugin.hxx delete mode 100644 src/decoder/modplug_decoder_plugin.c (limited to 'src') diff --git a/src/DecoderList.cxx b/src/DecoderList.cxx index 67fbed5f6..562e25a18 100644 --- a/src/DecoderList.cxx +++ b/src/DecoderList.cxx @@ -39,13 +39,13 @@ #include "decoder/Mpg123DecoderPlugin.hxx" #include "decoder/WildmidiDecoderPlugin.hxx" #include "decoder/MikmodDecoderPlugin.hxx" +#include "decoder/ModplugDecoderPlugin.hxx" #include #include extern const struct decoder_plugin mpcdec_decoder_plugin; -extern const struct decoder_plugin modplug_decoder_plugin; extern const struct decoder_plugin sidplay_decoder_plugin; extern const struct decoder_plugin fluidsynth_decoder_plugin; diff --git a/src/decoder/ModplugDecoderPlugin.cxx b/src/decoder/ModplugDecoderPlugin.cxx new file mode 100644 index 000000000..3c6dc0ca1 --- /dev/null +++ b/src/decoder/ModplugDecoderPlugin.cxx @@ -0,0 +1,201 @@ +/* + * 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 "ModplugDecoderPlugin.hxx" +#include "decoder_api.h" +#include "tag_handler.h" + +#include +#include +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "modplug" + +static constexpr size_t MODPLUG_FRAME_SIZE = 4096; +static constexpr size_t MODPLUG_PREALLOC_BLOCK = 256 * 1024; +static constexpr size_t MODPLUG_READ_BLOCK = 128 * 1024; +static constexpr goffset MODPLUG_FILE_LIMIT = 100 * 1024 * 1024; + +static GByteArray * +mod_loadfile(struct decoder *decoder, struct input_stream *is) +{ + const goffset size = input_stream_get_size(is); + + if (size == 0) { + g_warning("file is empty"); + return nullptr; + } + + if (size > MODPLUG_FILE_LIMIT) { + g_warning("file too large"); + return nullptr; + } + + //known/unknown size, preallocate array, lets read in chunks + GByteArray *bdatas; + if (size > 0) { + bdatas = g_byte_array_sized_new(size); + } else { + bdatas = g_byte_array_sized_new(MODPLUG_PREALLOC_BLOCK); + } + + unsigned char *data = (unsigned char *)g_malloc(MODPLUG_READ_BLOCK); + + while (true) { + size_t ret = decoder_read(decoder, is, data, + MODPLUG_READ_BLOCK); + if (ret == 0) { + if (input_stream_lock_eof(is)) + /* end of file */ + break; + + /* I/O error - skip this song */ + g_free(data); + g_byte_array_free(bdatas, true); + return nullptr; + } + + if (goffset(bdatas->len + ret) > MODPLUG_FILE_LIMIT) { + g_warning("stream too large\n"); + g_free(data); + g_byte_array_free(bdatas, TRUE); + return nullptr; + } + + g_byte_array_append(bdatas, data, ret); + } + + g_free(data); + + return bdatas; +} + +static void +mod_decode(struct decoder *decoder, struct input_stream *is) +{ + ModPlugFile *f; + ModPlug_Settings settings; + GByteArray *bdatas; + struct audio_format audio_format; + int ret; + char audio_buffer[MODPLUG_FRAME_SIZE]; + enum decoder_command cmd = DECODE_COMMAND_NONE; + + bdatas = mod_loadfile(decoder, is); + + if (!bdatas) { + g_warning("could not load stream\n"); + return; + } + + ModPlug_GetSettings(&settings); + /* alter setting */ + settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; /* RESAMP */ + settings.mChannels = 2; + settings.mBits = 16; + settings.mFrequency = 44100; + /* insert more setting changes here */ + ModPlug_SetSettings(&settings); + + f = ModPlug_Load(bdatas->data, bdatas->len); + g_byte_array_free(bdatas, TRUE); + if (!f) { + g_warning("could not decode stream\n"); + return; + } + + audio_format_init(&audio_format, 44100, SAMPLE_FORMAT_S16, 2); + assert(audio_format_valid(&audio_format)); + + decoder_initialized(decoder, &audio_format, + input_stream_is_seekable(is), + ModPlug_GetLength(f) / 1000.0); + + do { + ret = ModPlug_Read(f, audio_buffer, MODPLUG_FRAME_SIZE); + if (ret <= 0) + break; + + cmd = decoder_data(decoder, nullptr, + audio_buffer, ret, + 0); + + if (cmd == DECODE_COMMAND_SEEK) { + float where = decoder_seek_where(decoder); + + ModPlug_Seek(f, (int)(where * 1000.0)); + + decoder_command_finished(decoder); + } + + } while (cmd != DECODE_COMMAND_STOP); + + ModPlug_Unload(f); +} + +static bool +modplug_scan_stream(struct input_stream *is, + const struct tag_handler *handler, void *handler_ctx) +{ + ModPlugFile *f; + GByteArray *bdatas; + + bdatas = mod_loadfile(nullptr, is); + if (!bdatas) + return false; + + f = ModPlug_Load(bdatas->data, bdatas->len); + g_byte_array_free(bdatas, TRUE); + if (f == nullptr) + return false; + + tag_handler_invoke_duration(handler, handler_ctx, + ModPlug_GetLength(f) / 1000); + + const char *title = ModPlug_GetName(f); + if (title != nullptr) + tag_handler_invoke_tag(handler, handler_ctx, + TAG_TITLE, title); + + ModPlug_Unload(f); + + return true; +} + +static const char *const mod_suffixes[] = { + "669", "amf", "ams", "dbm", "dfm", "dsm", "far", "it", + "med", "mdl", "mod", "mtm", "mt2", "okt", "s3m", "stm", + "ult", "umx", "xm", + nullptr +}; + +const struct decoder_plugin modplug_decoder_plugin = { + "modplug", + nullptr, + nullptr, + mod_decode, + nullptr, + nullptr, + modplug_scan_stream, + nullptr, + mod_suffixes, + nullptr, +}; diff --git a/src/decoder/ModplugDecoderPlugin.hxx b/src/decoder/ModplugDecoderPlugin.hxx new file mode 100644 index 000000000..fefb02b05 --- /dev/null +++ b/src/decoder/ModplugDecoderPlugin.hxx @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#ifndef MPD_DECODER_MODPLUG_HXX +#define MPD_DECODER_MODPLUG_HXX + +extern const struct decoder_plugin modplug_decoder_plugin; + +#endif diff --git a/src/decoder/modplug_decoder_plugin.c b/src/decoder/modplug_decoder_plugin.c deleted file mode 100644 index bc3d81767..000000000 --- a/src/decoder/modplug_decoder_plugin.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2003-2011 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 "decoder_api.h" -#include "tag_handler.h" - -#include -#include -#include - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "modplug" - -enum { - MODPLUG_FRAME_SIZE = 4096, - MODPLUG_PREALLOC_BLOCK = 256 * 1024, - MODPLUG_READ_BLOCK = 128 * 1024, - MODPLUG_FILE_LIMIT = 100 * 1024 * 1024, -}; - -static GByteArray *mod_loadfile(struct decoder *decoder, struct input_stream *is) -{ - unsigned char *data; - GByteArray *bdatas; - size_t ret; - - const goffset size = input_stream_get_size(is); - - if (size == 0) { - g_warning("file is empty"); - return NULL; - } - - if (size > MODPLUG_FILE_LIMIT) { - g_warning("file too large"); - return NULL; - } - - //known/unknown size, preallocate array, lets read in chunks - if (size > 0) { - bdatas = g_byte_array_sized_new(size); - } else { - bdatas = g_byte_array_sized_new(MODPLUG_PREALLOC_BLOCK); - } - - data = g_malloc(MODPLUG_READ_BLOCK); - - while (true) { - ret = decoder_read(decoder, is, data, MODPLUG_READ_BLOCK); - if (ret == 0) { - if (input_stream_lock_eof(is)) - /* end of file */ - break; - - /* I/O error - skip this song */ - g_free(data); - g_byte_array_free(bdatas, true); - return NULL; - } - - if (bdatas->len + ret > MODPLUG_FILE_LIMIT) { - g_warning("stream too large\n"); - g_free(data); - g_byte_array_free(bdatas, TRUE); - return NULL; - } - - g_byte_array_append(bdatas, data, ret); - } - - g_free(data); - - return bdatas; -} - -static void -mod_decode(struct decoder *decoder, struct input_stream *is) -{ - ModPlugFile *f; - ModPlug_Settings settings; - GByteArray *bdatas; - struct audio_format audio_format; - int ret; - char audio_buffer[MODPLUG_FRAME_SIZE]; - enum decoder_command cmd = DECODE_COMMAND_NONE; - - bdatas = mod_loadfile(decoder, is); - - if (!bdatas) { - g_warning("could not load stream\n"); - return; - } - - ModPlug_GetSettings(&settings); - /* alter setting */ - settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; /* RESAMP */ - settings.mChannels = 2; - settings.mBits = 16; - settings.mFrequency = 44100; - /* insert more setting changes here */ - ModPlug_SetSettings(&settings); - - f = ModPlug_Load(bdatas->data, bdatas->len); - g_byte_array_free(bdatas, TRUE); - if (!f) { - g_warning("could not decode stream\n"); - return; - } - - audio_format_init(&audio_format, 44100, SAMPLE_FORMAT_S16, 2); - assert(audio_format_valid(&audio_format)); - - decoder_initialized(decoder, &audio_format, - input_stream_is_seekable(is), - ModPlug_GetLength(f) / 1000.0); - - do { - ret = ModPlug_Read(f, audio_buffer, MODPLUG_FRAME_SIZE); - if (ret <= 0) - break; - - cmd = decoder_data(decoder, NULL, - audio_buffer, ret, - 0); - - if (cmd == DECODE_COMMAND_SEEK) { - float where = decoder_seek_where(decoder); - - ModPlug_Seek(f, (int)(where * 1000.0)); - - decoder_command_finished(decoder); - } - - } while (cmd != DECODE_COMMAND_STOP); - - ModPlug_Unload(f); -} - -static bool -modplug_scan_stream(struct input_stream *is, - const struct tag_handler *handler, void *handler_ctx) -{ - ModPlugFile *f; - GByteArray *bdatas; - - bdatas = mod_loadfile(NULL, is); - if (!bdatas) - return false; - - f = ModPlug_Load(bdatas->data, bdatas->len); - g_byte_array_free(bdatas, TRUE); - if (f == NULL) - return false; - - tag_handler_invoke_duration(handler, handler_ctx, - ModPlug_GetLength(f) / 1000); - - const char *title = ModPlug_GetName(f); - if (title != NULL) - tag_handler_invoke_tag(handler, handler_ctx, - TAG_TITLE, title); - - ModPlug_Unload(f); - - return true; -} - -static const char *const mod_suffixes[] = { - "669", "amf", "ams", "dbm", "dfm", "dsm", "far", "it", - "med", "mdl", "mod", "mtm", "mt2", "okt", "s3m", "stm", - "ult", "umx", "xm", - NULL -}; - -const struct decoder_plugin modplug_decoder_plugin = { - .name = "modplug", - .stream_decode = mod_decode, - .scan_stream = modplug_scan_stream, - .suffixes = mod_suffixes, -}; -- cgit v1.2.3