diff --git a/src/filter/plugins/NormalizeFilterPlugin.cxx b/src/filter/plugins/NormalizeFilterPlugin.cxx index d347bbb43..74b9d52e9 100644 --- a/src/filter/plugins/NormalizeFilterPlugin.cxx +++ b/src/filter/plugins/NormalizeFilterPlugin.cxx @@ -12,20 +12,15 @@ #include class NormalizeFilter final : public Filter { - Compressor *const compressor; + PcmNormalizer normalizer; PcmBuffer buffer; public: explicit NormalizeFilter(const AudioFormat &audio_format) - :Filter(audio_format), compressor(Compressor_new()) { + :Filter(audio_format) { } - ~NormalizeFilter() override { - Compressor_delete(compressor); - } - - NormalizeFilter(const NormalizeFilter &) = delete; NormalizeFilter &operator=(const NormalizeFilter &) = delete; @@ -59,7 +54,7 @@ NormalizeFilter::FilterPCM(std::span src) auto *dest = (int16_t *)buffer.Get(src.size()); memcpy(dest, src.data(), src.size()); - Compressor_Process_int16(compressor, dest, src.size() / 2); + normalizer.ProcessS16(dest, src.size() / 2); return { (const std::byte *)dest, src.size() }; } diff --git a/src/pcm/Normalizer.cxx b/src/pcm/Normalizer.cxx index 0168c527c..a251d95dc 100644 --- a/src/pcm/Normalizer.cxx +++ b/src/pcm/Normalizer.cxx @@ -4,68 +4,17 @@ #include "Normalizer.hxx" -struct Compressor { - ///! Target level (on a scale of 0-32767) - static constexpr int target = 16384; - - //! The maximum amount to amplify by - static constexpr int maxgain = 32; - - //! How much inertia ramping has - static constexpr int smooth = 8; - - //! History of the peak values - int *const peaks; - - //! History of the gain values - int *const gain; - - //! History of clip amounts - int *const clipped; - - unsigned int pos = 0; - const unsigned int bufsz; - - Compressor(unsigned history) noexcept - :peaks(new int[history]{}), - gain(new int[history]{}), - clipped(new int[history]{}), - bufsz(history) - { - } - - ~Compressor() noexcept { - delete[] peaks; - delete[] gain; - delete[] clipped; - } -}; - -struct Compressor * -Compressor_new(unsigned int history) noexcept -{ - return new Compressor(history); -} - void -Compressor_delete(struct Compressor *obj) noexcept -{ - delete obj; -} - -void -Compressor_Process_int16(struct Compressor *obj, int16_t *audio, - unsigned int count) noexcept +PcmNormalizer::ProcessS16(int16_t *audio, unsigned int count) noexcept { int16_t *ap; unsigned int i; - int *peaks = obj->peaks; - int curGain = obj->gain[obj->pos]; + int curGain = gain[pos]; int newGain; int peakVal = 1; int peakPos = 0; - int slot = (obj->pos + 1) % obj->bufsz; - int *clipped = obj->clipped + slot; + int slot = (pos + 1) % bufsz; + int *clipped_ = clipped + slot; unsigned int ramp = count; int delta; @@ -84,7 +33,7 @@ Compressor_Process_int16(struct Compressor *obj, int16_t *audio, peaks[slot] = peakVal; - for (i = 0; i < obj->bufsz; i++) + for (i = 0; i < bufsz; i++) { if (peaks[i] > peakVal) { @@ -94,15 +43,14 @@ Compressor_Process_int16(struct Compressor *obj, int16_t *audio, } //! Determine target gain - newGain = (1 << 10)*obj->target/peakVal; + newGain = (1 << 10)*target/peakVal; //! Adjust the gain with inertia from the previous gain value - newGain = (curGain*((1 << obj->smooth) - 1) + newGain) - >> obj->smooth; + newGain = (curGain*((1 << smooth) - 1) + newGain) >> smooth; //! Make sure it's no more than the maximum gain value - if (newGain > (obj->maxgain << 10)) - newGain = obj->maxgain << 10; + if (newGain > (maxgain << 10)) + newGain = maxgain << 10; //! Make sure it's no less than 1:1 if (newGain < (1 << 10)) @@ -117,7 +65,7 @@ Compressor_Process_int16(struct Compressor *obj, int16_t *audio, } //! Record the new gain - obj->gain[slot] = newGain; + gain[slot] = newGain; if (!ramp) ramp = 1; @@ -126,7 +74,7 @@ Compressor_Process_int16(struct Compressor *obj, int16_t *audio, delta = (newGain - curGain) / (int)ramp; ap = audio; - *clipped = 0; + *clipped_ = 0; for (i = 0; i < count; i++) { int sample; @@ -135,11 +83,11 @@ Compressor_Process_int16(struct Compressor *obj, int16_t *audio, sample = *ap*curGain >> 10; if (sample < -32768) { - *clipped += -32768 - sample; + *clipped_ += -32768 - sample; sample = -32768; } else if (sample > 32767) { - *clipped += sample - 32767; + *clipped_ += sample - 32767; sample = 32767; } *ap++ = sample; @@ -151,6 +99,6 @@ Compressor_Process_int16(struct Compressor *obj, int16_t *audio, curGain = newGain; } - obj->pos = slot; + pos = slot; } diff --git a/src/pcm/Normalizer.hxx b/src/pcm/Normalizer.hxx index fde6b6507..a18f0fabd 100644 --- a/src/pcm/Normalizer.hxx +++ b/src/pcm/Normalizer.hxx @@ -6,19 +6,46 @@ #include -struct Compressor; +class PcmNormalizer { + ///! Target level (on a scale of 0-32767) + static constexpr int target = 16384; -//! Create a new compressor (use history value of 0 for default) -struct Compressor * -Compressor_new(unsigned int history = 400) noexcept; + //! The maximum amount to amplify by + static constexpr int maxgain = 32; -//! Delete a compressor -void -Compressor_delete(struct Compressor *) noexcept; + //! How much inertia ramping has + static constexpr int smooth = 8; -//! Process 16-bit signed data -void -Compressor_Process_int16(struct Compressor *, int16_t *data, unsigned int count) noexcept; + //! History of the peak values + int *const peaks; + + //! History of the gain values + int *const gain; + + //! History of clip amounts + int *const clipped; + + unsigned int pos = 0; + const unsigned int bufsz; + +public: + PcmNormalizer(unsigned history=400) noexcept + :peaks(new int[history]{}), + gain(new int[history]{}), + clipped(new int[history]{}), + bufsz(history) + { + } + + ~PcmNormalizer() noexcept { + delete[] peaks; + delete[] gain; + delete[] clipped; + } + + //! Process 16-bit signed data + void ProcessS16(int16_t *data, unsigned int count) noexcept; +}; //! TODO: Compressor_Process_int32, Compressor_Process_float, others as needed diff --git a/test/run_normalize.cxx b/test/run_normalize.cxx index 9de9437dc..682c5600f 100644 --- a/test/run_normalize.cxx +++ b/test/run_normalize.cxx @@ -22,7 +22,6 @@ int main(int argc, char **argv) try { - struct Compressor *compressor; static char buffer[4096]; ssize_t nbytes; @@ -35,16 +34,14 @@ try { if (argc > 1) audio_format = ParseAudioFormat(argv[1], false); - compressor = Compressor_new(); + PcmNormalizer normalizer; while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) { - Compressor_Process_int16(compressor, - (int16_t *)buffer, nbytes / 2); + normalizer.ProcessS16((int16_t *)buffer, nbytes / 2); [[maybe_unused]] ssize_t ignored = write(1, buffer, nbytes); } - Compressor_delete(compressor); return EXIT_SUCCESS; } catch (...) { PrintException(std::current_exception());