From f828749c289bad5978ff3e7a8100c9a5c65b8970 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Tue, 6 Sep 2022 13:48:40 +0200 Subject: Replace libvlc compressor gain by internal gain calculation --- README.md | 5 +---- src/VLCInput.cpp | 9 +-------- src/VLCInput.h | 9 +-------- src/odr-audioenc.cpp | 36 ++++++++++++++++++++++++++---------- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 6095af1..0449898 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ therefore also webstreams and other network sources. The GStreamer input is an alternative to read from various sources. -The ALSA and libVLC inputs support sound card clock drift +The ALSA, libVLC and GStreamer inputs support sound card clock drift compensation, that can compensate for imprecise sound card clocks. The JACK input does not automatically connect to anything. The encoder runs @@ -293,9 +293,6 @@ in a future version. ## Known Limitations -The gain option for libVLC enables the VLC audio compressor with default -settings. This has more impact than just changing the volume of the audio. - Some receivers did not decode audio anymore between v0.3.0 and v0.5.0, because of a change implemented to get PAD to work. The change was subsequently reverted in v0.5.1 because it was deemed essential that audio decoding works on all receivers. diff --git a/src/VLCInput.cpp b/src/VLCInput.cpp index 0547696..ca44f04 100644 --- a/src/VLCInput.cpp +++ b/src/VLCInput.cpp @@ -1,5 +1,5 @@ /* ------------------------------------------------------------------ - * Copyright (C) 2018 Matthias P. Braendli + * Copyright (C) 2022 Matthias P. Braendli * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -169,10 +169,6 @@ void VLCInput::prepare() vlc_args.push_back("--network-caching=" + m_cache); } - if (not m_gain.empty()) { - vlc_args.push_back("--compressor-makeup=" + m_gain); - } - copy(m_additional_opts.begin(), m_additional_opts.end(), back_inserter(vlc_args)); @@ -204,9 +200,6 @@ void VLCInput::prepare() std::stringstream transcode_options_ss; transcode_options_ss << "acodec=fl32"; transcode_options_ss << ",samplerate=" << m_rate; - if (not m_gain.empty()) { - transcode_options_ss << ",afilter=compressor"; - } string transcode_options = transcode_options_ss.str(); char smem_options[512]; diff --git a/src/VLCInput.h b/src/VLCInput.h index 47a9cdd..ed1a682 100644 --- a/src/VLCInput.h +++ b/src/VLCInput.h @@ -1,5 +1,5 @@ /* ------------------------------------------------------------------ - * Copyright (C) 2017 Matthias P. Braendli + * Copyright (C) 2022 Matthias P. Braendli * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,6 @@ class VLCInput : public InputInterface int rate, unsigned channels, unsigned verbosity, - std::string& gain, std::string& cache, std::vector& additional_opts, SampleQueue& queue) : @@ -64,7 +63,6 @@ class VLCInput : public InputInterface m_rate(rate), m_cache(cache), m_additional_opts(additional_opts), - m_gain(gain), m_vlc(nullptr), m_mp(nullptr), m_fault(false), @@ -136,11 +134,6 @@ class VLCInput : public InputInterface //! Given as-is to libvlc, useful for additional arguments std::vector m_additional_opts; - /*! value for the VLC compressor filter --compressor-makeup - * setting. Many more compressor settings could be set. - */ - std::string m_gain; - /*! VLC can give us the ICY-Text from an Icecast stream, * which we optionally write into a text file for ODR-PadEnc */ diff --git a/src/odr-audioenc.cpp b/src/odr-audioenc.cpp index 068c8a3..68a99a1 100644 --- a/src/odr-audioenc.cpp +++ b/src/odr-audioenc.cpp @@ -1,6 +1,6 @@ /* ------------------------------------------------------------------ * Copyright (C) 2011 Martin Storsjo - * Copyright (C) 2021 Matthias P. Braendli + * Copyright (C) 2022 Matthias P. Braendli * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -152,9 +152,6 @@ static void usage(const char* name) #if HAVE_VLC " -v, --vlc-uri=uri Enable VLC input and use the URI given as source\n" " -C, --vlc-cache=ms Specify VLC network cache length.\n" - " -g, --vlc-gain=db Enable VLC audio compressor, with given compressor-makeup value.\n" - " Use this as a workaround to correct the gain for streams that are\n" - " much too loud.\n" " -V Increase the VLC verbosity by one (can be given \n" " multiple times)\n" " -L OPTION Give an additional options to VLC (can be given\n" @@ -176,6 +173,9 @@ static void usage(const char* name) " -b, --bitrate={ 8, 16, ..., 192 } Output bitrate in kbps. Must be a multiple of 8.\n" " -c, --channels={ 1, 2 } Nb of input channels (default: 2).\n" " -r, --rate={ 24000, 32000, 48000 } Input sample rate (default: 48000).\n" + " -g, --audio-gain=dB Apply audio gain correction in dB to source, negative values allowed.\n" + " Use this as a workaround to correct the gain for streams that are\n" + " much too loud.\n" " DAB specific options\n" " -a, --dab Encode in DAB and not in DAB+.\n" " --dabmode=MODE Channel mode: s/d/j/m\n" @@ -405,6 +405,7 @@ struct AudioEnc { public: int sample_rate=48000; int channels=2; + double gain_dB = 0.0; string icytext_file; bool icytext_dlplus = false; @@ -420,7 +421,6 @@ public: // For the VLC input string vlc_uri; - string vlc_gain; string vlc_cache; vector vlc_additional_opts; unsigned verbosity = 0; @@ -1009,13 +1009,29 @@ int AudioEnc::run() * channels, and is formally wrong in mono, but still gives * numbers one can use. * + * At the same time, we apply gain correction. + * * \todo fix level measurement in mono */ int16_t peak_left = 0; int16_t peak_right = 0; + + const double linear_gain_correction = pow(10.0, gain_dB / 20.0); + for (int i = 0; i < read_bytes; i+=4) { int16_t l = input_buf[i] | (input_buf[i+1] << 8); int16_t r = input_buf[i+2] | (input_buf[i+3] << 8); + + if (linear_gain_correction != 1.0) { + l *= linear_gain_correction; + r *= linear_gain_correction; + + input_buf[i] = l & 0x00FF; + input_buf[i+1] = (l & 0xFF00) >> 8; + input_buf[i+2] = r & 0x00FF; + input_buf[i+3] = (r & 0xFF00) >> 8; + } + peak_left = std::max(peak_left, l); peak_right = std::max(peak_right, r); } @@ -1322,7 +1338,7 @@ shared_ptr AudioEnc::initialise_input() #if HAVE_VLC else if (not vlc_uri.empty()) { input = make_shared(vlc_uri, sample_rate, channels, verbosity, - vlc_gain, vlc_cache, vlc_additional_opts, queue); + vlc_cache, vlc_additional_opts, queue); } #endif #if HAVE_GST @@ -1353,6 +1369,7 @@ int main(int argc, char *argv[]) const struct option longopts[] = { {"bitrate", required_argument, 0, 'b'}, {"bandwidth", required_argument, 0, 'B'}, + {"audio-gain", required_argument, 0, 'g'}, {"channels", required_argument, 0, 'c'}, {"dabmode", required_argument, 0, 4 }, {"dabpsy", required_argument, 0, 5 }, @@ -1375,7 +1392,6 @@ int main(int argc, char *argv[]) {"startup-check", required_argument, 0, 9 }, {"stats", required_argument, 0, 'S'}, {"vlc-cache", required_argument, 0, 'C'}, - {"vlc-gain", required_argument, 0, 'g'}, {"vlc-uri", required_argument, 0, 'v'}, {"vlc-opt", required_argument, 0, 'L'}, {"write-icy-text", required_argument, 0, 'w'}, @@ -1516,6 +1532,9 @@ int main(int argc, char *argv[]) return 1; } break; + case 'g': + audio_enc.gain_dB = std::stod(optarg); + break; #ifdef HAVE_GST case 'G': audio_enc.gst_uri = optarg; @@ -1577,9 +1596,6 @@ int main(int argc, char *argv[]) case 'v': audio_enc.vlc_uri = optarg; break; - case 'g': - audio_enc.vlc_gain = optarg; - break; case 'C': audio_enc.vlc_cache = optarg; break; -- cgit v1.2.3