From 1fcf35ad3b10c241b8b5266c46a5fe99ce2c57d9 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 26 Jul 2013 12:09:17 +0200 Subject: tag_rva2: convert to C++ --- Makefile.am | 7 +- src/TagRva2.cxx | 150 +++++++++++++++++++++++++++++++++++++++ src/TagRva2.hxx | 39 ++++++++++ src/decoder/MadDecoderPlugin.cxx | 2 +- src/tag_rva2.c | 150 --------------------------------------- src/tag_rva2.h | 39 ---------- test/dump_rva2.c | 112 ----------------------------- test/dump_rva2.cxx | 114 +++++++++++++++++++++++++++++ 8 files changed, 307 insertions(+), 306 deletions(-) create mode 100644 src/TagRva2.cxx create mode 100644 src/TagRva2.hxx delete mode 100644 src/tag_rva2.c delete mode 100644 src/tag_rva2.h delete mode 100644 test/dump_rva2.c create mode 100644 test/dump_rva2.cxx diff --git a/Makefile.am b/Makefile.am index aad7352dd..563c5f6eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -93,7 +93,6 @@ mpd_headers = \ src/tag_table.h \ src/tag_ape.h \ src/tag_id3.h \ - src/tag_rva2.h \ src/Timer.hxx \ src/mpd_error.h @@ -441,7 +440,7 @@ libtag_a_SOURCES =\ if HAVE_ID3TAG libtag_a_SOURCES += \ src/tag_id3.c \ - src/tag_rva2.c \ + src/TagRva2.cxx src/TagRva2.hxx \ src/riff.c src/aiff.c endif @@ -1189,11 +1188,11 @@ if HAVE_ID3TAG test_dump_rva2_LDADD = \ $(ID3TAG_LIBS) \ $(GLIB_LIBS) -test_dump_rva2_SOURCES = test/dump_rva2.c \ +test_dump_rva2_SOURCES = test/dump_rva2.cxx \ src/riff.c src/aiff.c \ src/tag_handler.c \ src/tag_id3.c \ - src/tag_rva2.c + src/TagRva2.cxx endif test_run_filter_LDADD = \ diff --git a/src/TagRva2.cxx b/src/TagRva2.cxx new file mode 100644 index 000000000..f41119c35 --- /dev/null +++ b/src/TagRva2.cxx @@ -0,0 +1,150 @@ +/* + * 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 "TagRva2.hxx" +#include "replay_gain_info.h" + +#include +#include +#include +#include + +enum rva2_channel { + CHANNEL_OTHER = 0x00, + CHANNEL_MASTER_VOLUME = 0x01, + CHANNEL_FRONT_RIGHT = 0x02, + CHANNEL_FRONT_LEFT = 0x03, + CHANNEL_BACK_RIGHT = 0x04, + CHANNEL_BACK_LEFT = 0x05, + CHANNEL_FRONT_CENTRE = 0x06, + CHANNEL_BACK_CENTRE = 0x07, + CHANNEL_SUBWOOFER = 0x08 +}; + +struct rva2_data { + uint8_t type; + uint8_t volume_adjustment[2]; + uint8_t peak_bits; +}; + +static inline id3_length_t +rva2_peak_bytes(const struct rva2_data *data) +{ + return (data->peak_bits + 7) / 8; +} + +static inline int +rva2_fixed_volume_adjustment(const struct rva2_data *data) +{ + signed int voladj_fixed; + voladj_fixed = (data->volume_adjustment[0] << 8) | + data->volume_adjustment[1]; + voladj_fixed |= -(voladj_fixed & 0x8000); + return voladj_fixed; +} + +static inline float +rva2_float_volume_adjustment(const struct rva2_data *data) +{ + /* + * "The volume adjustment is encoded as a fixed point decibel + * value, 16 bit signed integer representing (adjustment*512), + * giving +/- 64 dB with a precision of 0.001953125 dB." + */ + + return (float)rva2_fixed_volume_adjustment(data) / (float)512; +} + +static inline bool +rva2_apply_data(struct replay_gain_info *replay_gain_info, + const struct rva2_data *data, const id3_latin1_t *id) +{ + if (data->type != CHANNEL_MASTER_VOLUME) + return false; + + float volume_adjustment = rva2_float_volume_adjustment(data); + + if (strcmp((const char *)id, "album") == 0) { + replay_gain_info->tuples[REPLAY_GAIN_ALBUM].gain = volume_adjustment; + } else if (strcmp((const char *)id, "track") == 0) { + replay_gain_info->tuples[REPLAY_GAIN_TRACK].gain = volume_adjustment; + } else { + replay_gain_info->tuples[REPLAY_GAIN_ALBUM].gain = volume_adjustment; + replay_gain_info->tuples[REPLAY_GAIN_TRACK].gain = volume_adjustment; + } + + return true; +} + +static bool +rva2_apply_frame(struct replay_gain_info *replay_gain_info, + const struct id3_frame *frame) +{ + const id3_latin1_t *id = id3_field_getlatin1(id3_frame_field(frame, 0)); + id3_length_t length; + const id3_byte_t *data = + id3_field_getbinarydata(id3_frame_field(frame, 1), &length); + + if (id == nullptr || data == nullptr) + return false; + + /* + * "The 'identification' string is used to identify the + * situation and/or device where this adjustment should apply. + * The following is then repeated for every channel + * + * Type of channel $xx + * Volume adjustment $xx xx + * Bits representing peak $xx + * Peak volume $xx (xx ...)" + */ + + while (length >= 4) { + const struct rva2_data *d = (const struct rva2_data *)data; + unsigned int peak_bytes = rva2_peak_bytes(d); + if (4 + peak_bytes > length) + break; + + if (rva2_apply_data(replay_gain_info, d, id)) + return true; + + data += 4 + peak_bytes; + length -= 4 + peak_bytes; + } + + return false; +} + +bool +tag_rva2_parse(struct id3_tag *tag, struct replay_gain_info *replay_gain_info) +{ + bool found = false; + + /* Loop through all RVA2 frames as some programs (e.g. mp3gain) store + track and album gain in separate tags */ + const struct id3_frame *frame; + for (unsigned i = 0; + (frame = id3_tag_findframe(tag, "RVA2", i)) != nullptr; + ++i) + if (rva2_apply_frame(replay_gain_info, frame)) + found = true; + + return found; +} diff --git a/src/TagRva2.hxx b/src/TagRva2.hxx new file mode 100644 index 000000000..057f03186 --- /dev/null +++ b/src/TagRva2.hxx @@ -0,0 +1,39 @@ +/* + * 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_TAG_RVA2_HXX +#define MPD_TAG_RVA2_HXX + +#include "check.h" + +#include + +struct id3_tag; +struct replay_gain_info; + +/** + * Parse the RVA2 tag, and fill the #replay_gain_info struct. This is + * used by decoder plugins with ID3 support. + * + * @return true on success + */ +bool +tag_rva2_parse(struct id3_tag *tag, struct replay_gain_info *replay_gain_info); + +#endif diff --git a/src/decoder/MadDecoderPlugin.cxx b/src/decoder/MadDecoderPlugin.cxx index 339fd5397..a8b607386 100644 --- a/src/decoder/MadDecoderPlugin.cxx +++ b/src/decoder/MadDecoderPlugin.cxx @@ -24,9 +24,9 @@ extern "C" { #include "tag_id3.h" -#include "tag_rva2.h" } +#include "TagRva2.hxx" #include "tag_handler.h" #include "audio_check.h" diff --git a/src/tag_rva2.c b/src/tag_rva2.c deleted file mode 100644 index 9250311b9..000000000 --- a/src/tag_rva2.c +++ /dev/null @@ -1,150 +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 "tag_rva2.h" -#include "replay_gain_info.h" - -#include -#include -#include -#include - -enum rva2_channel { - CHANNEL_OTHER = 0x00, - CHANNEL_MASTER_VOLUME = 0x01, - CHANNEL_FRONT_RIGHT = 0x02, - CHANNEL_FRONT_LEFT = 0x03, - CHANNEL_BACK_RIGHT = 0x04, - CHANNEL_BACK_LEFT = 0x05, - CHANNEL_FRONT_CENTRE = 0x06, - CHANNEL_BACK_CENTRE = 0x07, - CHANNEL_SUBWOOFER = 0x08 -}; - -struct rva2_data { - uint8_t type; - uint8_t volume_adjustment[2]; - uint8_t peak_bits; -}; - -static inline id3_length_t -rva2_peak_bytes(const struct rva2_data *data) -{ - return (data->peak_bits + 7) / 8; -} - -static inline int -rva2_fixed_volume_adjustment(const struct rva2_data *data) -{ - signed int voladj_fixed; - voladj_fixed = (data->volume_adjustment[0] << 8) | - data->volume_adjustment[1]; - voladj_fixed |= -(voladj_fixed & 0x8000); - return voladj_fixed; -} - -static inline float -rva2_float_volume_adjustment(const struct rva2_data *data) -{ - /* - * "The volume adjustment is encoded as a fixed point decibel - * value, 16 bit signed integer representing (adjustment*512), - * giving +/- 64 dB with a precision of 0.001953125 dB." - */ - - return (float)rva2_fixed_volume_adjustment(data) / (float)512; -} - -static inline bool -rva2_apply_data(struct replay_gain_info *replay_gain_info, - const struct rva2_data *data, const id3_latin1_t *id) -{ - if (data->type != CHANNEL_MASTER_VOLUME) - return false; - - float volume_adjustment = rva2_float_volume_adjustment(data); - - if (strcmp((const char *)id, "album") == 0) { - replay_gain_info->tuples[REPLAY_GAIN_ALBUM].gain = volume_adjustment; - } else if (strcmp((const char *)id, "track") == 0) { - replay_gain_info->tuples[REPLAY_GAIN_TRACK].gain = volume_adjustment; - } else { - replay_gain_info->tuples[REPLAY_GAIN_ALBUM].gain = volume_adjustment; - replay_gain_info->tuples[REPLAY_GAIN_TRACK].gain = volume_adjustment; - } - - return true; -} - -static bool -rva2_apply_frame(struct replay_gain_info *replay_gain_info, - const struct id3_frame *frame) -{ - const id3_latin1_t *id = id3_field_getlatin1(id3_frame_field(frame, 0)); - id3_length_t length; - const id3_byte_t *data = - id3_field_getbinarydata(id3_frame_field(frame, 1), &length); - - if (id == NULL || data == NULL) - return false; - - /* - * "The 'identification' string is used to identify the - * situation and/or device where this adjustment should apply. - * The following is then repeated for every channel - * - * Type of channel $xx - * Volume adjustment $xx xx - * Bits representing peak $xx - * Peak volume $xx (xx ...)" - */ - - while (length >= 4) { - const struct rva2_data *d = (const struct rva2_data *)data; - unsigned int peak_bytes = rva2_peak_bytes(d); - if (4 + peak_bytes > length) - break; - - if (rva2_apply_data(replay_gain_info, d, id)) - return true; - - data += 4 + peak_bytes; - length -= 4 + peak_bytes; - } - - return false; -} - -bool -tag_rva2_parse(struct id3_tag *tag, struct replay_gain_info *replay_gain_info) -{ - bool found = false; - - /* Loop through all RVA2 frames as some programs (e.g. mp3gain) store - track and album gain in separate tags */ - const struct id3_frame *frame; - for (unsigned i = 0; - (frame = id3_tag_findframe(tag, "RVA2", i)) != NULL; - ++i) - if (rva2_apply_frame(replay_gain_info, frame)) - found = true; - - return found; -} diff --git a/src/tag_rva2.h b/src/tag_rva2.h deleted file mode 100644 index 8aac2fe9f..000000000 --- a/src/tag_rva2.h +++ /dev/null @@ -1,39 +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. - */ - -#ifndef MPD_TAG_RVA2_H -#define MPD_TAG_RVA2_H - -#include "check.h" - -#include - -struct id3_tag; -struct replay_gain_info; - -/** - * Parse the RVA2 tag, and fill the #replay_gain_info struct. This is - * used by decoder plugins with ID3 support. - * - * @return true on success - */ -bool -tag_rva2_parse(struct id3_tag *tag, struct replay_gain_info *replay_gain_info); - -#endif diff --git a/test/dump_rva2.c b/test/dump_rva2.c deleted file mode 100644 index 6e978c424..000000000 --- a/test/dump_rva2.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2003-2012 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 "tag_id3.h" -#include "tag_rva2.h" -#include "replay_gain_info.h" -#include "conf.h" -#include "tag.h" - -#include - -#include - -#ifdef HAVE_LOCALE_H -#include -#endif - -#include - -const char * -config_get_string(gcc_unused enum ConfigOption option, - const char *default_value) -{ - return default_value; -} - -struct tag * -tag_new(void) -{ - return NULL; -} - -void -tag_add_item_n(gcc_unused struct tag *tag, gcc_unused enum tag_type type, - gcc_unused const char *value, gcc_unused size_t len) -{ -} - -void -tag_free(struct tag *tag) -{ - g_free(tag); -} - -int main(int argc, char **argv) -{ - GError *error = NULL; - -#ifdef HAVE_LOCALE_H - /* initialize locale */ - setlocale(LC_CTYPE,""); -#endif - - if (argc != 2) { - g_printerr("Usage: read_rva2 FILE\n"); - return 1; - } - - const char *path = argv[1]; - - struct id3_tag *tag = tag_id3_load(path, &error); - if (tag == NULL) { - if (error != NULL) { - g_printerr("%s\n", error->message); - g_error_free(error); - } else - g_printerr("No ID3 tag found\n"); - - return EXIT_FAILURE; - } - - struct replay_gain_info replay_gain; - replay_gain_info_init(&replay_gain); - - bool success = tag_rva2_parse(tag, &replay_gain); - id3_tag_delete(tag); - - if (!success) { - g_printerr("No RVA2 tag found\n"); - return EXIT_FAILURE; - } - - const struct replay_gain_tuple *tuple = - &replay_gain.tuples[REPLAY_GAIN_ALBUM]; - if (replay_gain_tuple_defined(tuple)) - g_printerr("replay_gain[album]: gain=%f peak=%f\n", - tuple->gain, tuple->peak); - - tuple = &replay_gain.tuples[REPLAY_GAIN_TRACK]; - if (replay_gain_tuple_defined(tuple)) - g_printerr("replay_gain[track]: gain=%f peak=%f\n", - tuple->gain, tuple->peak); - - return EXIT_SUCCESS; -} diff --git a/test/dump_rva2.cxx b/test/dump_rva2.cxx new file mode 100644 index 000000000..e58b8cd30 --- /dev/null +++ b/test/dump_rva2.cxx @@ -0,0 +1,114 @@ +/* + * 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" +extern "C" { +#include "tag_id3.h" +} +#include "TagRva2.hxx" +#include "replay_gain_info.h" +#include "conf.h" +#include "tag.h" + +#include + +#include + +#ifdef HAVE_LOCALE_H +#include +#endif + +#include + +const char * +config_get_string(gcc_unused enum ConfigOption option, + const char *default_value) +{ + return default_value; +} + +struct tag * +tag_new(void) +{ + return NULL; +} + +void +tag_add_item_n(gcc_unused struct tag *tag, gcc_unused enum tag_type type, + gcc_unused const char *value, gcc_unused size_t len) +{ +} + +void +tag_free(struct tag *tag) +{ + g_free(tag); +} + +int main(int argc, char **argv) +{ + GError *error = NULL; + +#ifdef HAVE_LOCALE_H + /* initialize locale */ + setlocale(LC_CTYPE,""); +#endif + + if (argc != 2) { + g_printerr("Usage: read_rva2 FILE\n"); + return 1; + } + + const char *path = argv[1]; + + struct id3_tag *tag = tag_id3_load(path, &error); + if (tag == NULL) { + if (error != NULL) { + g_printerr("%s\n", error->message); + g_error_free(error); + } else + g_printerr("No ID3 tag found\n"); + + return EXIT_FAILURE; + } + + struct replay_gain_info replay_gain; + replay_gain_info_init(&replay_gain); + + bool success = tag_rva2_parse(tag, &replay_gain); + id3_tag_delete(tag); + + if (!success) { + g_printerr("No RVA2 tag found\n"); + return EXIT_FAILURE; + } + + const struct replay_gain_tuple *tuple = + &replay_gain.tuples[REPLAY_GAIN_ALBUM]; + if (replay_gain_tuple_defined(tuple)) + g_printerr("replay_gain[album]: gain=%f peak=%f\n", + tuple->gain, tuple->peak); + + tuple = &replay_gain.tuples[REPLAY_GAIN_TRACK]; + if (replay_gain_tuple_defined(tuple)) + g_printerr("replay_gain[track]: gain=%f peak=%f\n", + tuple->gain, tuple->peak); + + return EXIT_SUCCESS; +} -- cgit v1.2.3