From 8e31366431858782de117dfb6146fd5ebf788ce0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 8 Apr 2013 23:32:53 +0200 Subject: decoder/gme: convert to C++ --- Makefile.am | 3 +- src/DecoderList.cxx | 2 +- src/decoder/GmeDecoderPlugin.cxx | 292 +++++++++++++++++++++++++++++++++++++++ src/decoder/GmeDecoderPlugin.hxx | 25 ++++ src/decoder/gme_decoder_plugin.c | 257 ---------------------------------- 5 files changed, 320 insertions(+), 259 deletions(-) create mode 100644 src/decoder/GmeDecoderPlugin.cxx create mode 100644 src/decoder/GmeDecoderPlugin.hxx delete mode 100644 src/decoder/gme_decoder_plugin.c diff --git a/Makefile.am b/Makefile.am index 0a88e587a..0b5d46c45 100644 --- a/Makefile.am +++ b/Makefile.am @@ -610,7 +610,8 @@ libdecoder_plugins_a_SOURCES += src/decoder/sndfile_decoder_plugin.c endif if HAVE_GME -libdecoder_plugins_a_SOURCES += src/decoder/gme_decoder_plugin.c +libdecoder_plugins_a_SOURCES += \ + src/decoder/GmeDecoderPlugin.cxx src/decoder/GmeDecoderPlugin.hxx endif # encoder plugins diff --git a/src/DecoderList.cxx b/src/DecoderList.cxx index da9c3fcc6..0bf65bcdb 100644 --- a/src/DecoderList.cxx +++ b/src/DecoderList.cxx @@ -31,6 +31,7 @@ #include "decoder/AdPlugDecoderPlugin.h" #include "decoder/WavpackDecoderPlugin.hxx" #include "decoder/FfmpegDecoderPlugin.hxx" +#include "decoder/GmeDecoderPlugin.hxx" #include @@ -47,7 +48,6 @@ extern const struct decoder_plugin mikmod_decoder_plugin; extern const struct decoder_plugin sidplay_decoder_plugin; extern const struct decoder_plugin wildmidi_decoder_plugin; extern const struct decoder_plugin fluidsynth_decoder_plugin; -extern const struct decoder_plugin gme_decoder_plugin; const struct decoder_plugin *const decoder_plugins[] = { #ifdef HAVE_MAD diff --git a/src/decoder/GmeDecoderPlugin.cxx b/src/decoder/GmeDecoderPlugin.cxx new file mode 100644 index 000000000..6e59d4c13 --- /dev/null +++ b/src/decoder/GmeDecoderPlugin.cxx @@ -0,0 +1,292 @@ +/* + * 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 "GmeDecoderPlugin.hxx" +#include "decoder_api.h" +#include "audio_check.h" +#include "tag_handler.h" + +extern "C" { +#include "uri.h" +} + +#include +#include +#include +#include + +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "gme" + +#define SUBTUNE_PREFIX "tune_" + +static constexpr unsigned GME_SAMPLE_RATE = 44100; +static constexpr unsigned GME_CHANNELS = 2; +static constexpr unsigned GME_BUFFER_FRAMES = 2048; +static constexpr unsigned GME_BUFFER_SAMPLES = + GME_BUFFER_FRAMES * GME_CHANNELS; + +/** + * returns the file path stripped of any /tune_xxx.* subtune + * suffix + */ +static char * +get_container_name(const char *path_fs) +{ + const char *subtune_suffix = uri_get_suffix(path_fs); + char *path_container = g_strdup(path_fs); + char *pat = g_strconcat("*/" SUBTUNE_PREFIX "???.", + subtune_suffix, nullptr); + GPatternSpec *path_with_subtune = g_pattern_spec_new(pat); + g_free(pat); + if (!g_pattern_match(path_with_subtune, + strlen(path_container), path_container, nullptr)) { + g_pattern_spec_free(path_with_subtune); + return path_container; + } + + char *ptr = g_strrstr(path_container, "/" SUBTUNE_PREFIX); + if (ptr != nullptr) + *ptr='\0'; + + g_pattern_spec_free(path_with_subtune); + return path_container; +} + +/** + * returns tune number from file.nsf/tune_xxx.* style path or 0 if no subtune + * is appended. + */ +static int +get_song_num(const char *path_fs) +{ + const char *subtune_suffix = uri_get_suffix(path_fs); + char *pat = g_strconcat("*/" SUBTUNE_PREFIX "???.", + subtune_suffix, nullptr); + GPatternSpec *path_with_subtune = g_pattern_spec_new(pat); + g_free(pat); + + if (g_pattern_match(path_with_subtune, + strlen(path_fs), path_fs, nullptr)) { + char *sub = g_strrstr(path_fs, "/" SUBTUNE_PREFIX); + g_pattern_spec_free(path_with_subtune); + if (!sub) + return 0; + + sub += strlen("/" SUBTUNE_PREFIX); + int song_num = strtol(sub, nullptr, 10); + + return song_num - 1; + } else { + g_pattern_spec_free(path_with_subtune); + return 0; + } +} + +static char * +gme_container_scan(const char *path_fs, const unsigned int tnum) +{ + Music_Emu *emu; + const char *gme_err = gme_open_file(path_fs, &emu, GME_SAMPLE_RATE); + if (gme_err != nullptr) { + g_warning("%s", gme_err); + return nullptr; + } + + const unsigned num_songs = gme_track_count(emu); + /* if it only contains a single tune, don't treat as container */ + if (num_songs < 2) + return nullptr; + + const char *subtune_suffix = uri_get_suffix(path_fs); + if (tnum <= num_songs){ + char *subtune = g_strdup_printf( + SUBTUNE_PREFIX "%03u.%s", tnum, subtune_suffix); + return subtune; + } else + return nullptr; +} + +static void +gme_file_decode(struct decoder *decoder, const char *path_fs) +{ + char *path_container = get_container_name(path_fs); + + Music_Emu *emu; + const char *gme_err = + gme_open_file(path_container, &emu, GME_SAMPLE_RATE); + g_free(path_container); + if (gme_err != nullptr) { + g_warning("%s", gme_err); + return; + } + + gme_info_t *ti; + const int song_num = get_song_num(path_fs); + gme_err = gme_track_info(emu, &ti, song_num); + if (gme_err != nullptr) { + g_warning("%s", gme_err); + gme_delete(emu); + return; + } + + const float song_len = ti->length > 0 + ? ti->length / 1000.0 + : -1.0; + + /* initialize the MPD decoder */ + + GError *error = nullptr; + struct audio_format audio_format; + if (!audio_format_init_checked(&audio_format, GME_SAMPLE_RATE, + SAMPLE_FORMAT_S16, GME_CHANNELS, + &error)) { + g_warning("%s", error->message); + g_error_free(error); + gme_free_info(ti); + gme_delete(emu); + return; + } + + decoder_initialized(decoder, &audio_format, true, song_len); + + gme_err = gme_start_track(emu, song_num); + if (gme_err != nullptr) + g_warning("%s", gme_err); + + if (ti->length > 0) + gme_set_fade(emu, ti->length); + + /* play */ + enum decoder_command cmd; + do { + short buf[GME_BUFFER_SAMPLES]; + gme_err = gme_play(emu, GME_BUFFER_SAMPLES, buf); + if (gme_err != nullptr) { + g_warning("%s", gme_err); + return; + } + + cmd = decoder_data(decoder, nullptr, buf, sizeof(buf), 0); + if (cmd == DECODE_COMMAND_SEEK) { + float where = decoder_seek_where(decoder); + gme_err = gme_seek(emu, (int)where * 1000); + if (gme_err != nullptr) + g_warning("%s", gme_err); + decoder_command_finished(decoder); + } + + if (gme_track_ended(emu)) + break; + } while (cmd != DECODE_COMMAND_STOP); + + gme_free_info(ti); + gme_delete(emu); +} + +static bool +gme_scan_file(const char *path_fs, + const struct tag_handler *handler, void *handler_ctx) +{ + char *path_container = get_container_name(path_fs); + + Music_Emu *emu; + const char *gme_err = + gme_open_file(path_container, &emu, GME_SAMPLE_RATE); + g_free(path_container); + if (gme_err != nullptr) { + g_warning("%s", gme_err); + return false; + } + + const int song_num = get_song_num(path_fs); + + gme_info_t *ti; + gme_err = gme_track_info(emu, &ti, song_num); + if (gme_err != nullptr) { + g_warning("%s", gme_err); + gme_delete(emu); + return false; + } + + assert(ti != nullptr); + + if (ti->length > 0) + tag_handler_invoke_duration(handler, handler_ctx, + ti->length / 100); + + if (ti->song != nullptr) { + if (gme_track_count(emu) > 1) { + /* start numbering subtunes from 1 */ + char *tag_title = + g_strdup_printf("%s (%d/%d)", + ti->song, song_num + 1, + gme_track_count(emu)); + tag_handler_invoke_tag(handler, handler_ctx, + TAG_TITLE, tag_title); + g_free(tag_title); + } else + tag_handler_invoke_tag(handler, handler_ctx, + TAG_TITLE, ti->song); + } + + if (ti->author != nullptr) + tag_handler_invoke_tag(handler, handler_ctx, + TAG_ARTIST, ti->author); + + if (ti->game != nullptr) + tag_handler_invoke_tag(handler, handler_ctx, + TAG_ALBUM, ti->game); + + if (ti->comment != nullptr) + tag_handler_invoke_tag(handler, handler_ctx, + TAG_COMMENT, ti->comment); + + if (ti->copyright != nullptr) + tag_handler_invoke_tag(handler, handler_ctx, + TAG_DATE, ti->copyright); + + gme_free_info(ti); + gme_delete(emu); + + return true; +} + +static const char *const gme_suffixes[] = { + "ay", "gbs", "gym", "hes", "kss", "nsf", + "nsfe", "sap", "spc", "vgm", "vgz", + nullptr +}; + +extern const struct decoder_plugin gme_decoder_plugin; +const struct decoder_plugin gme_decoder_plugin = { + "gme", + nullptr, + nullptr, + nullptr, + gme_file_decode, + gme_scan_file, + nullptr, + gme_container_scan, + gme_suffixes, + nullptr, +}; diff --git a/src/decoder/GmeDecoderPlugin.hxx b/src/decoder/GmeDecoderPlugin.hxx new file mode 100644 index 000000000..fba735d92 --- /dev/null +++ b/src/decoder/GmeDecoderPlugin.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_GME_HXX +#define MPD_DECODER_GME_HXX + +extern const struct decoder_plugin gme_decoder_plugin; + +#endif diff --git a/src/decoder/gme_decoder_plugin.c b/src/decoder/gme_decoder_plugin.c deleted file mode 100644 index 237a1deb1..000000000 --- a/src/decoder/gme_decoder_plugin.c +++ /dev/null @@ -1,257 +0,0 @@ -#include "config.h" -#include "../decoder_api.h" -#include "audio_check.h" -#include "uri.h" -#include "tag_handler.h" - -#include -#include -#include -#include -#include - -#include - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "gme" - -#define SUBTUNE_PREFIX "tune_" - -enum { - GME_SAMPLE_RATE = 44100, - GME_CHANNELS = 2, - GME_BUFFER_FRAMES = 2048, - GME_BUFFER_SAMPLES = GME_BUFFER_FRAMES * GME_CHANNELS, -}; - -/** - * returns the file path stripped of any /tune_xxx.* subtune - * suffix - */ -static char * -get_container_name(const char *path_fs) -{ - const char *subtune_suffix = uri_get_suffix(path_fs); - char *path_container = g_strdup(path_fs); - char *pat = g_strconcat("*/" SUBTUNE_PREFIX "???.", subtune_suffix, NULL); - GPatternSpec *path_with_subtune = g_pattern_spec_new(pat); - g_free(pat); - if (!g_pattern_match(path_with_subtune, - strlen(path_container), path_container, NULL)) { - g_pattern_spec_free(path_with_subtune); - return path_container; - } - - char *ptr = g_strrstr(path_container, "/" SUBTUNE_PREFIX); - if (ptr != NULL) - *ptr='\0'; - - g_pattern_spec_free(path_with_subtune); - return path_container; -} - -/** - * returns tune number from file.nsf/tune_xxx.* style path or 0 if no subtune - * is appended. - */ -static int -get_song_num(const char *path_fs) -{ - const char *subtune_suffix = uri_get_suffix(path_fs); - char *pat = g_strconcat("*/" SUBTUNE_PREFIX "???.", subtune_suffix, NULL); - GPatternSpec *path_with_subtune = g_pattern_spec_new(pat); - g_free(pat); - - if (g_pattern_match(path_with_subtune, - strlen(path_fs), path_fs, NULL)) { - char *sub = g_strrstr(path_fs, "/" SUBTUNE_PREFIX); - g_pattern_spec_free(path_with_subtune); - if(!sub) - return 0; - - sub += strlen("/" SUBTUNE_PREFIX); - int song_num = strtol(sub, NULL, 10); - - return song_num - 1; - } else { - g_pattern_spec_free(path_with_subtune); - return 0; - } -} - -static char * -gme_container_scan(const char *path_fs, const unsigned int tnum) -{ - Music_Emu *emu; - const char* gme_err; - unsigned int num_songs; - - gme_err = gme_open_file(path_fs, &emu, GME_SAMPLE_RATE); - if (gme_err != NULL) { - g_warning("%s", gme_err); - return NULL; - } - - num_songs = gme_track_count(emu); - /* if it only contains a single tune, don't treat as container */ - if (num_songs < 2) - return NULL; - - const char *subtune_suffix = uri_get_suffix(path_fs); - if (tnum <= num_songs){ - char *subtune = g_strdup_printf( - SUBTUNE_PREFIX "%03u.%s", tnum, subtune_suffix); - return subtune; - } else - return NULL; -} - -static void -gme_file_decode(struct decoder *decoder, const char *path_fs) -{ - float song_len; - Music_Emu *emu; - gme_info_t *ti; - struct audio_format audio_format; - enum decoder_command cmd; - short buf[GME_BUFFER_SAMPLES]; - const char* gme_err; - char *path_container = get_container_name(path_fs); - int song_num = get_song_num(path_fs); - - gme_err = gme_open_file(path_container, &emu, GME_SAMPLE_RATE); - g_free(path_container); - if (gme_err != NULL) { - g_warning("%s", gme_err); - return; - } - - if((gme_err = gme_track_info(emu, &ti, song_num)) != NULL){ - g_warning("%s", gme_err); - gme_delete(emu); - return; - } - - if(ti->length > 0) - song_len = ti->length / 1000.0; - else song_len = -1; - - /* initialize the MPD decoder */ - - GError *error = NULL; - if (!audio_format_init_checked(&audio_format, GME_SAMPLE_RATE, - SAMPLE_FORMAT_S16, GME_CHANNELS, - &error)) { - g_warning("%s", error->message); - g_error_free(error); - gme_free_info(ti); - gme_delete(emu); - return; - } - - decoder_initialized(decoder, &audio_format, true, song_len); - - if((gme_err = gme_start_track(emu, song_num)) != NULL) - g_warning("%s", gme_err); - - if(ti->length > 0) - gme_set_fade(emu, ti->length); - - /* play */ - do { - gme_err = gme_play(emu, GME_BUFFER_SAMPLES, buf); - if (gme_err != NULL) { - g_warning("%s", gme_err); - return; - } - cmd = decoder_data(decoder, NULL, buf, sizeof(buf), 0); - - if(cmd == DECODE_COMMAND_SEEK) { - float where = decoder_seek_where(decoder); - if((gme_err = gme_seek(emu, (int)where*1000)) != NULL) - g_warning("%s", gme_err); - decoder_command_finished(decoder); - } - - if(gme_track_ended(emu)) - break; - } while(cmd != DECODE_COMMAND_STOP); - - gme_free_info(ti); - gme_delete(emu); -} - -static bool -gme_scan_file(const char *path_fs, - const struct tag_handler *handler, void *handler_ctx) -{ - Music_Emu *emu; - gme_info_t *ti; - const char* gme_err; - char *path_container=get_container_name(path_fs); - int song_num; - song_num=get_song_num(path_fs); - - gme_err = gme_open_file(path_container, &emu, GME_SAMPLE_RATE); - g_free(path_container); - if (gme_err != NULL) { - g_warning("%s", gme_err); - return false; - } - if((gme_err = gme_track_info(emu, &ti, song_num)) != NULL){ - g_warning("%s", gme_err); - gme_delete(emu); - return false; - } - - assert(ti != NULL); - - if(ti->length > 0) - tag_handler_invoke_duration(handler, handler_ctx, - ti->length / 100); - - if(ti->song != NULL){ - if(gme_track_count(emu) > 1){ - /* start numbering subtunes from 1 */ - char *tag_title=g_strdup_printf("%s (%d/%d)", - ti->song, song_num+1, gme_track_count(emu)); - tag_handler_invoke_tag(handler, handler_ctx, - TAG_TITLE, tag_title); - g_free(tag_title); - }else - tag_handler_invoke_tag(handler, handler_ctx, - TAG_TITLE, ti->song); - } - if(ti->author != NULL) - tag_handler_invoke_tag(handler, handler_ctx, - TAG_ARTIST, ti->author); - if(ti->game != NULL) - tag_handler_invoke_tag(handler, handler_ctx, - TAG_ALBUM, ti->game); - if(ti->comment != NULL) - tag_handler_invoke_tag(handler, handler_ctx, - TAG_COMMENT, ti->comment); - if(ti->copyright != NULL) - tag_handler_invoke_tag(handler, handler_ctx, - TAG_DATE, ti->copyright); - - gme_free_info(ti); - gme_delete(emu); - - return true; -} - -static const char *const gme_suffixes[] = { - "ay", "gbs", "gym", "hes", "kss", "nsf", - "nsfe", "sap", "spc", "vgm", "vgz", - NULL -}; - -extern const struct decoder_plugin gme_decoder_plugin; -const struct decoder_plugin gme_decoder_plugin = { - .name = "gme", - .file_decode = gme_file_decode, - .scan_file = gme_scan_file, - .suffixes = gme_suffixes, - .container_scan = gme_container_scan, -}; -- cgit v1.2.3