From 7715311117972984459dfbc1a4d8be9a83205b8c Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 15 Mar 2020 23:33:21 -0700 Subject: [PATCH 1/3] fix double promotions Found with -Wdouble-promotion Signed-off-by: Rosen Penev --- src/ReplayGainGlobal.cxx | 12 ++++++------ src/ReplayGainInfo.cxx | 12 ++++++------ src/command/PlayerCommands.cxx | 2 +- src/decoder/Bridge.cxx | 4 ++-- src/decoder/plugins/MadDecoderPlugin.cxx | 12 ++++++------ src/decoder/plugins/OpusTags.cxx | 4 ++-- src/encoder/plugins/LameEncoderPlugin.cxx | 8 ++++---- src/encoder/plugins/TwolameEncoderPlugin.cxx | 6 +++--- src/encoder/plugins/VorbisEncoderPlugin.cxx | 8 ++++---- src/mixer/plugins/PulseMixerPlugin.cxx | 10 +++++----- src/mixer/plugins/SoftwareMixerPlugin.cxx | 12 ++++++------ src/output/Source.cxx | 2 +- src/pcm/FloatConvert.hxx | 2 +- src/pcm/PcmMix.cxx | 4 +++- src/pcm/SoxrResampler.cxx | 2 +- src/pcm/Volume.hxx | 2 +- src/queue/PlaylistState.cxx | 3 ++- 17 files changed, 54 insertions(+), 51 deletions(-) diff --git a/src/ReplayGainGlobal.cxx b/src/ReplayGainGlobal.cxx index 56aaa7890..fc4306821 100644 --- a/src/ReplayGainGlobal.cxx +++ b/src/ReplayGainGlobal.cxx @@ -23,9 +23,9 @@ #include "config/Data.hxx" #include "util/RuntimeError.hxx" -#include -#include -#include +#include +#include +#include static float ParsePreamp(const char *s) @@ -33,14 +33,14 @@ ParsePreamp(const char *s) assert(s != nullptr); char *endptr; - float f = strtod(s, &endptr); + float f = std::strtof(s, &endptr); if (endptr == s || *endptr != '\0') throw std::invalid_argument("Not a numeric value"); - if (f < -15 || f > 15) + if (f < -15.0f || f > 15.0f) throw std::invalid_argument("Number must be between -15 and 15"); - return pow(10, f / 20.0); + return std::pow(10.0f, f / 20.0f); } static float diff --git a/src/ReplayGainInfo.cxx b/src/ReplayGainInfo.cxx index 18f40ec4b..7963ff7be 100644 --- a/src/ReplayGainInfo.cxx +++ b/src/ReplayGainInfo.cxx @@ -20,7 +20,7 @@ #include "ReplayGainInfo.hxx" #include "ReplayGainConfig.hxx" -#include +#include float ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept @@ -28,13 +28,13 @@ ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept float scale; if (IsDefined()) { - scale = pow(10.0, gain / 20.0); + scale = std::pow(10.0f, gain / 20.0f); scale *= config.preamp; - if (scale > 15.0) - scale = 15.0; + if (scale > 15.0f) + scale = 15.0f; - if (config.limit && scale * peak > 1.0) - scale = 1.0 / peak; + if (config.limit && scale * peak > 1.0f) + scale = 1.0f / peak; } else scale = config.missing_preamp; diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx index e8d88e6cf..cf9438620 100644 --- a/src/command/PlayerCommands.cxx +++ b/src/command/PlayerCommands.cxx @@ -148,7 +148,7 @@ handle_status(Client &client, gcc_unused Request args, Response &r) playlist.GetConsume(), (unsigned long)playlist.GetVersion(), playlist.GetLength(), - pc.GetMixRampDb(), + (double)pc.GetMixRampDb(), state); if (pc.GetCrossFade() > FloatDuration::zero()) diff --git a/src/decoder/Bridge.cxx b/src/decoder/Bridge.cxx index e11a0a45a..9947bc3e5 100644 --- a/src/decoder/Bridge.cxx +++ b/src/decoder/Bridge.cxx @@ -33,11 +33,11 @@ #include "util/ConstBuffer.hxx" #include "util/StringBuffer.hxx" +#include #include #include #include -#include DecoderBridge::~DecoderBridge() { @@ -597,7 +597,7 @@ DecoderBridge::SubmitReplayGain(const ReplayGainInfo *new_replay_gain_info) const auto &tuple = new_replay_gain_info->Get(rgm); const auto scale = tuple.CalculateScale(dc.replay_gain_config); - dc.replay_gain_db = 20.0 * log10f(scale); + dc.replay_gain_db = 20.0f * std::log10(scale); } replay_gain_info = *new_replay_gain_info; diff --git a/src/decoder/plugins/MadDecoderPlugin.cxx b/src/decoder/plugins/MadDecoderPlugin.cxx index b5a688bbf..a01a44001 100644 --- a/src/decoder/plugins/MadDecoderPlugin.cxx +++ b/src/decoder/plugins/MadDecoderPlugin.cxx @@ -617,8 +617,8 @@ parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen) noexcept mad_bit_skip(ptr, 16); - lame->peak = mad_f_todouble(mad_bit_read(ptr, 32) << 5); /* peak */ - FormatDebug(mad_domain, "LAME peak found: %f", lame->peak); + lame->peak = MAD_F(mad_bit_read(ptr, 32) << 5); /* peak */ + FormatDebug(mad_domain, "LAME peak found: %f", double(lame->peak)); lame->track_gain = 0; unsigned name = mad_bit_read(ptr, 3); /* gain name */ @@ -626,9 +626,9 @@ parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen) noexcept unsigned sign = mad_bit_read(ptr, 1); /* sign bit */ int gain = mad_bit_read(ptr, 9); /* gain*10 */ if (gain && name == 1 && orig != 0) { - lame->track_gain = ((sign ? -gain : gain) / 10.0) + adj; + lame->track_gain = ((sign ? -gain : gain) / 10.0f) + adj; FormatDebug(mad_domain, "LAME track gain found: %f", - lame->track_gain); + double(lame->track_gain)); } /* tmz reports that this isn't currently written by any version of lame @@ -644,7 +644,7 @@ parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen) noexcept if (gain && name == 2 && orig != 0) { lame->album_gain = ((sign ? -gain : gain) / 10.0) + adj; FormatDebug(mad_domain, "LAME album gain found: %f", - lame->track_gain); + double(lame->track_gain)); } #else mad_bit_skip(ptr, 16); @@ -778,7 +778,7 @@ MadDecoder::DecodeFirstFrame(Tag *tag) noexcept /* Album gain isn't currently used. See comment in * parse_lame() for details. -- jat */ if (client != nullptr && !found_replay_gain && - lame.track_gain) { + lame.track_gain > 0.0f) { ReplayGainInfo rgi; rgi.Clear(); rgi.track.gain = lame.track_gain; diff --git a/src/decoder/plugins/OpusTags.cxx b/src/decoder/plugins/OpusTags.cxx index 76ea63e6e..70e452860 100644 --- a/src/decoder/plugins/OpusTags.cxx +++ b/src/decoder/plugins/OpusTags.cxx @@ -53,7 +53,7 @@ ScanOneOpusTag(const char *name, const char *value, char *endptr; long l = strtol(value, &endptr, 10); if (endptr > value && *endptr == 0) - rgi->track.gain = double(l) / 256.; + rgi->track.gain = float(l) / 256.0f; } else if (rgi != nullptr && StringEqualsCaseASCII(name, "R128_ALBUM_GAIN")) { /* R128_ALBUM_GAIN is a Q7.8 fixed point number in @@ -62,7 +62,7 @@ ScanOneOpusTag(const char *name, const char *value, char *endptr; long l = strtol(value, &endptr, 10); if (endptr > value && *endptr == 0) - rgi->album.gain = double(l) / 256.; + rgi->album.gain = float(l) / 256.0f; } handler.OnPair(name, value); diff --git a/src/encoder/plugins/LameEncoderPlugin.cxx b/src/encoder/plugins/LameEncoderPlugin.cxx index fe663c28c..7f6df6eb0 100644 --- a/src/encoder/plugins/LameEncoderPlugin.cxx +++ b/src/encoder/plugins/LameEncoderPlugin.cxx @@ -77,9 +77,9 @@ PreparedLameEncoder::PreparedLameEncoder(const ConfigBlock &block) if (value != nullptr) { /* a quality was configured (VBR) */ - quality = ParseDouble(value, &endptr); + quality = float(ParseDouble(value, &endptr)); - if (*endptr != '\0' || quality < -1.0 || quality > 10.0) + if (*endptr != '\0' || quality < -1.0f || quality > 10.0f) throw FormatRuntimeError("quality \"%s\" is not a number in the " "range -1 to 10", value); @@ -111,13 +111,13 @@ static void lame_encoder_setup(lame_global_flags *gfp, float quality, int bitrate, const AudioFormat &audio_format) { - if (quality >= -1.0) { + if (quality >= -1.0f) { /* a quality was configured (VBR) */ if (0 != lame_set_VBR(gfp, vbr_rh)) throw std::runtime_error("error setting lame VBR mode"); - if (0 != lame_set_VBR_q(gfp, quality)) + if (0 != lame_set_VBR_q(gfp, int(quality))) throw std::runtime_error("error setting lame VBR quality"); } else { /* a bit rate was configured */ diff --git a/src/encoder/plugins/TwolameEncoderPlugin.cxx b/src/encoder/plugins/TwolameEncoderPlugin.cxx index e05f64764..debed7871 100644 --- a/src/encoder/plugins/TwolameEncoderPlugin.cxx +++ b/src/encoder/plugins/TwolameEncoderPlugin.cxx @@ -95,9 +95,9 @@ PreparedTwolameEncoder::PreparedTwolameEncoder(const ConfigBlock &block) if (value != nullptr) { /* a quality was configured (VBR) */ - quality = ParseDouble(value, &endptr); + quality = float(ParseDouble(value, &endptr)); - if (*endptr != '\0' || quality < -1.0 || quality > 10.0) + if (*endptr != '\0' || quality < -1.0f || quality > 10.0f) throw FormatRuntimeError("quality \"%s\" is not a number in the " "range -1 to 10", value); @@ -132,7 +132,7 @@ static void twolame_encoder_setup(twolame_options *options, float quality, int bitrate, const AudioFormat &audio_format) { - if (quality >= -1.0) { + if (quality >= -1.0f) { /* a quality was configured (VBR) */ if (0 != twolame_set_VBR(options, true)) diff --git a/src/encoder/plugins/VorbisEncoderPlugin.cxx b/src/encoder/plugins/VorbisEncoderPlugin.cxx index 7a17a77f3..90a8120c6 100644 --- a/src/encoder/plugins/VorbisEncoderPlugin.cxx +++ b/src/encoder/plugins/VorbisEncoderPlugin.cxx @@ -84,7 +84,7 @@ PreparedVorbisEncoder::PreparedVorbisEncoder(const ConfigBlock &block) char *endptr; quality = ParseDouble(value, &endptr); - if (*endptr != '\0' || quality < -1.0 || quality > 10.0) + if (*endptr != '\0' || quality < -1.0f || quality > 10.0f) throw FormatRuntimeError("quality \"%s\" is not a number in the " "range -1 to 10", value); @@ -122,13 +122,13 @@ VorbisEncoder::VorbisEncoder(float quality, int bitrate, _audio_format.format = SampleFormat::FLOAT; audio_format = _audio_format; - if (quality >= -1.0) { + if (quality >= -1.0f) { /* a quality was configured (VBR) */ if (0 != vorbis_encode_init_vbr(&vi, audio_format.channels, audio_format.sample_rate, - quality * 0.1)) { + quality * 0.1f)) { vorbis_info_clear(&vi); throw std::runtime_error("error initializing vorbis vbr"); } @@ -138,7 +138,7 @@ VorbisEncoder::VorbisEncoder(float quality, int bitrate, if (0 != vorbis_encode_init(&vi, audio_format.channels, audio_format.sample_rate, -1.0, - bitrate * 1000, -1.0)) { + bitrate * 1000, -1.0f)) { vorbis_info_clear(&vi); throw std::runtime_error("error initializing vorbis encoder"); } diff --git a/src/mixer/plugins/PulseMixerPlugin.cxx b/src/mixer/plugins/PulseMixerPlugin.cxx index 44fcb56f7..f39044459 100644 --- a/src/mixer/plugins/PulseMixerPlugin.cxx +++ b/src/mixer/plugins/PulseMixerPlugin.cxx @@ -51,7 +51,7 @@ public: double _volume_scale_factor) :Mixer(pulse_mixer_plugin, _listener), output(_output), - volume_scale_factor(_volume_scale_factor) + volume_scale_factor(float(_volume_scale_factor)) { } @@ -175,7 +175,7 @@ parse_volume_scale_factor(const char *value) { char *endptr; float factor = ParseFloat(value, &endptr); - if (endptr == value || *endptr != '\0' || factor < 0.5 || factor > 5.0) + if (endptr == value || *endptr != '\0' || factor < 0.5f || factor > 5.0f) throw FormatRuntimeError("\"%s\" is not a number in the " "range 0.5 to 5.0", value); @@ -190,7 +190,7 @@ pulse_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao, { PulseOutput &po = (PulseOutput &)ao; float scale = parse_volume_scale_factor(block.GetBlockValue("scale_volume")); - PulseMixer *pm = new PulseMixer(po, listener, scale); + auto *pm = new PulseMixer(po, listener, (double)scale); pulse_output_set_mixer(po, *pm); @@ -216,7 +216,7 @@ PulseMixer::GetVolume() int PulseMixer::GetVolumeInternal() { - pa_volume_t max_pa_volume = volume_scale_factor * PA_VOLUME_NORM; + pa_volume_t max_pa_volume = pa_volume_t(volume_scale_factor * PA_VOLUME_NORM); return online ? (int)((100 * (pa_cvolume_avg(&volume) + 1)) / max_pa_volume) : -1; @@ -230,7 +230,7 @@ PulseMixer::SetVolume(unsigned new_volume) if (!online) throw std::runtime_error("disconnected"); - pa_volume_t max_pa_volume = volume_scale_factor * PA_VOLUME_NORM; + pa_volume_t max_pa_volume = pa_volume_t(volume_scale_factor * PA_VOLUME_NORM); struct pa_cvolume cvolume; pa_cvolume_set(&cvolume, volume.channels, diff --git a/src/mixer/plugins/SoftwareMixerPlugin.cxx b/src/mixer/plugins/SoftwareMixerPlugin.cxx index 177c875d2..8105db537 100644 --- a/src/mixer/plugins/SoftwareMixerPlugin.cxx +++ b/src/mixer/plugins/SoftwareMixerPlugin.cxx @@ -22,8 +22,8 @@ #include "filter/plugins/VolumeFilterPlugin.hxx" #include "pcm/Volume.hxx" -#include -#include +#include +#include class SoftwareMixer final : public Mixer { Filter *filter = nullptr; @@ -70,13 +70,13 @@ PercentVolumeToSoftwareVolume(unsigned volume) noexcept { assert(volume <= 100); - if (volume >= 100) + if (volume == 100) return PCM_VOLUME_1; else if (volume > 0) - return pcm_float_to_volume((exp(volume / 25.0) - 1) / + return pcm_float_to_volume((std::exp(volume / 25.0f) - 1) / (54.5981500331F - 1)); - else - return 0; + + return 0; } void diff --git a/src/output/Source.cxx b/src/output/Source.cxx index 7c5098d8e..27c7c362b 100644 --- a/src/output/Source.cxx +++ b/src/output/Source.cxx @@ -187,7 +187,7 @@ AudioOutputSource::FilterChunk(const MusicChunk &chunk) only if the mix ratio is non-negative; a negative mix ratio is a MixRamp special case */ - mix_ratio = 1.0 - mix_ratio; + mix_ratio = 1.0f - mix_ratio; void *dest = cross_fade_buffer.Get(other_data.size); memcpy(dest, other_data.data, other_data.size); diff --git a/src/pcm/FloatConvert.hxx b/src/pcm/FloatConvert.hxx index 28f923c7a..17fcd27ce 100644 --- a/src/pcm/FloatConvert.hxx +++ b/src/pcm/FloatConvert.hxx @@ -53,7 +53,7 @@ struct IntegerToFloatSampleConvert { typedef typename SrcTraits::value_type SV; typedef typename DstTraits::value_type DV; - static constexpr DV factor = 1.0 / FloatToIntegerSampleConvert::factor; + static constexpr DV factor = 1.0f / FloatToIntegerSampleConvert::factor; static_assert(factor > 0, "Wrong factor"); static constexpr DV Convert(SV src) noexcept { diff --git a/src/pcm/PcmMix.cxx b/src/pcm/PcmMix.cxx index bbb26d1c4..11d201c3e 100644 --- a/src/pcm/PcmMix.cxx +++ b/src/pcm/PcmMix.cxx @@ -26,6 +26,8 @@ #include "PcmDither.cxx" // including the .cxx file to get inlined templates +#include + #include template> @@ -221,7 +223,7 @@ pcm_mix(PcmDither &dither, void *buffer1, const void *buffer2, size_t size, if (portion1 < 0) return pcm_add(buffer1, buffer2, size, format); - s = sin(M_PI_2 * portion1); + s = std::sin((float)M_PI_2 * portion1); s *= s; int vol1 = lround(s * PCM_VOLUME_1S); diff --git a/src/pcm/SoxrResampler.cxx b/src/pcm/SoxrResampler.cxx index 411e79b43..2dcb507e0 100644 --- a/src/pcm/SoxrResampler.cxx +++ b/src/pcm/SoxrResampler.cxx @@ -122,7 +122,7 @@ SoxrPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate) ratio = float(new_sample_rate) / float(af.sample_rate); FormatDebug(soxr_domain, "samplerate conversion ratio to %.2lf", - ratio); + double(ratio)); /* libsoxr works with floating point samples */ af.format = SampleFormat::FLOAT; diff --git a/src/pcm/Volume.hxx b/src/pcm/Volume.hxx index ddc6cb854..52a63d819 100644 --- a/src/pcm/Volume.hxx +++ b/src/pcm/Volume.hxx @@ -48,7 +48,7 @@ static constexpr int PCM_VOLUME_1S = PCM_VOLUME_1; static constexpr inline int pcm_float_to_volume(float volume) noexcept { - return volume * PCM_VOLUME_1 + 0.5; + return int(volume * PCM_VOLUME_1 + 0.5f); } static constexpr inline float diff --git a/src/queue/PlaylistState.cxx b/src/queue/PlaylistState.cxx index f57409de0..2e2ab3ec1 100644 --- a/src/queue/PlaylistState.cxx +++ b/src/queue/PlaylistState.cxx @@ -92,7 +92,8 @@ playlist_state_save(BufferedOutputStream &os, const struct playlist &playlist, os.Format(PLAYLIST_STATE_FILE_CONSUME "%i\n", playlist.queue.consume); os.Format(PLAYLIST_STATE_FILE_CROSSFADE "%i\n", (int)pc.GetCrossFade().count()); - os.Format(PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", pc.GetMixRampDb()); + os.Format(PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", + (double)pc.GetMixRampDb()); os.Format(PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n", pc.GetMixRampDelay().count()); os.Write(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n"); From 23d5a2b8620cea69958d087fc7e13fe1e5adb83d Mon Sep 17 00:00:00 2001 From: Desuwa Date: Fri, 18 Sep 2020 03:46:37 -0700 Subject: [PATCH 2/3] Support opus header gain tags and match opus playback volume to other tracks when ReplayGain is enabled. --- NEWS | 1 + src/decoder/plugins/OpusDecoderPlugin.cxx | 24 +++++++++++++++++++---- src/decoder/plugins/OpusHead.cxx | 5 ++++- src/decoder/plugins/OpusHead.hxx | 2 +- src/decoder/plugins/OpusTags.cxx | 4 ++-- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index aeb7eb5bf..9ece34870 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ ver 0.21.26 (not yet released) * decoder - ffmpeg: remove "rtsp://" from the list of supported protocols - ffmpeg: add "hls+http://" to the list of supported protocols + - opus: support the gain value from the Opus header - sndfile: fix lost samples at end of file * fix "single" mode bug after resuming playback * the default log_level is "default", not "info" diff --git a/src/decoder/plugins/OpusDecoderPlugin.cxx b/src/decoder/plugins/OpusDecoderPlugin.cxx index 5284ac9a1..b1ed9c4e9 100644 --- a/src/decoder/plugins/OpusDecoderPlugin.cxx +++ b/src/decoder/plugins/OpusDecoderPlugin.cxx @@ -75,6 +75,12 @@ class MPDOpusDecoder final : public OggDecoder { OpusDecoder *opus_decoder = nullptr; opus_int16 *output_buffer = nullptr; + /** + * The output gain from the Opus header. Initialized by + * OnOggBeginning(). + */ + signed output_gain; + /** * The pre-skip value from the Opus header. Initialized by * OnOggBeginning(). @@ -164,7 +170,7 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet) throw std::runtime_error("BOS packet must be OpusHead"); unsigned channels; - if (!ScanOpusHeader(packet.packet, packet.bytes, channels, pre_skip) || + if (!ScanOpusHeader(packet.packet, packet.bytes, channels, output_gain, pre_skip) || !audio_valid_channel_count(channels)) throw std::runtime_error("Malformed BOS packet"); @@ -239,6 +245,15 @@ MPDOpusDecoder::HandleTags(const ogg_packet &packet) ReplayGainInfo rgi; rgi.Clear(); + /** + * Output gain is a Q7.8 fixed point number in dB that should be, + * applied unconditionally, but is often used specifically for + * ReplayGain. Add 5dB to compensate for the different + * reference levels between ReplayGain (89dB) and EBU R128 (-23 LUFS). + */ + rgi.track.gain = float(output_gain) / 256.0f + 5; + rgi.album.gain = float(output_gain) / 256.0f + 5; + TagBuilder tag_builder; AddTagHandler h(tag_builder); @@ -384,14 +399,14 @@ mpd_opus_stream_decode(DecoderClient &client, static bool ReadAndParseOpusHead(OggSyncState &sync, OggStreamState &stream, - unsigned &channels, unsigned &pre_skip) + unsigned &channels, signed &output_gain, unsigned &pre_skip) { ogg_packet packet; return OggReadPacket(sync, stream, packet) && packet.b_o_s && IsOpusHead(packet) && ScanOpusHeader(packet.packet, packet.bytes, channels, - pre_skip) && + output_gain, pre_skip) && audio_valid_channel_count(channels); } @@ -436,7 +451,8 @@ mpd_opus_scan_stream(InputStream &is, TagHandler &handler) OggStreamState os(first_page); unsigned channels, pre_skip; - if (!ReadAndParseOpusHead(oy, os, channels, pre_skip) || + signed output_gain; + if (!ReadAndParseOpusHead(oy, os, channels, output_gain, pre_skip) || !ReadAndVisitOpusTags(oy, os, handler)) return false; diff --git a/src/decoder/plugins/OpusHead.cxx b/src/decoder/plugins/OpusHead.cxx index 30d959f04..7a1c766a9 100644 --- a/src/decoder/plugins/OpusHead.cxx +++ b/src/decoder/plugins/OpusHead.cxx @@ -33,12 +33,15 @@ struct OpusHead { bool ScanOpusHeader(const void *data, size_t size, unsigned &channels_r, - unsigned &pre_skip_r) + signed &output_gain_r, unsigned &pre_skip_r) { const OpusHead *h = (const OpusHead *)data; if (size < 19 || (h->version & 0xf0) != 0) return false; + uint16_t gain_bits = FromLE16(h->output_gain); + output_gain_r = (gain_bits & 0x8000) ? gain_bits - 0x10000 : gain_bits; + channels_r = h->channels; pre_skip_r = FromLE16(h->pre_skip); return true; diff --git a/src/decoder/plugins/OpusHead.hxx b/src/decoder/plugins/OpusHead.hxx index 39b5f832a..4fada6459 100644 --- a/src/decoder/plugins/OpusHead.hxx +++ b/src/decoder/plugins/OpusHead.hxx @@ -24,6 +24,6 @@ bool ScanOpusHeader(const void *data, size_t size, unsigned &channels_r, - unsigned &pre_skip_r); + signed &output_gain_r, unsigned &pre_skip_r); #endif diff --git a/src/decoder/plugins/OpusTags.cxx b/src/decoder/plugins/OpusTags.cxx index 70e452860..3133dcc4d 100644 --- a/src/decoder/plugins/OpusTags.cxx +++ b/src/decoder/plugins/OpusTags.cxx @@ -53,7 +53,7 @@ ScanOneOpusTag(const char *name, const char *value, char *endptr; long l = strtol(value, &endptr, 10); if (endptr > value && *endptr == 0) - rgi->track.gain = float(l) / 256.0f; + rgi->track.gain += float(l) / 256.0f; } else if (rgi != nullptr && StringEqualsCaseASCII(name, "R128_ALBUM_GAIN")) { /* R128_ALBUM_GAIN is a Q7.8 fixed point number in @@ -62,7 +62,7 @@ ScanOneOpusTag(const char *name, const char *value, char *endptr; long l = strtol(value, &endptr, 10); if (endptr > value && *endptr == 0) - rgi->album.gain = float(l) / 256.0f; + rgi->album.gain += float(l) / 256.0f; } handler.OnPair(name, value); From b72801abf3bba84565bb040215071a21182e698c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 21 Sep 2020 11:15:21 +0200 Subject: [PATCH 3/3] util/ByteOrder: add FromLE16S() --- src/decoder/plugins/OpusHead.cxx | 3 +-- src/util/ByteOrder.hxx | 11 +++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/decoder/plugins/OpusHead.cxx b/src/decoder/plugins/OpusHead.cxx index 7a1c766a9..e93e754b4 100644 --- a/src/decoder/plugins/OpusHead.cxx +++ b/src/decoder/plugins/OpusHead.cxx @@ -39,8 +39,7 @@ ScanOpusHeader(const void *data, size_t size, unsigned &channels_r, if (size < 19 || (h->version & 0xf0) != 0) return false; - uint16_t gain_bits = FromLE16(h->output_gain); - output_gain_r = (gain_bits & 0x8000) ? gain_bits - 0x10000 : gain_bits; + output_gain_r = FromLE16S(h->output_gain); channels_r = h->channels; pre_skip_r = FromLE16(h->pre_skip); diff --git a/src/util/ByteOrder.hxx b/src/util/ByteOrder.hxx index f52c2bd38..121f458f2 100644 --- a/src/util/ByteOrder.hxx +++ b/src/util/ByteOrder.hxx @@ -243,4 +243,15 @@ ToLE64(uint64_t value) noexcept return IsLittleEndian() ? value : ByteSwap64(value); } +/** + * Converts a 16 bit integer from little endian to the host byte order + * and returns it as a signed integer. + */ +constexpr int16_t +FromLE16S(uint16_t value) noexcept +{ + /* assuming two's complement representation */ + return static_cast(FromLE16(value)); +} + #endif