11#include <promeki/config.h>
12#if PROMEKI_ENABLE_PROAV
20PROMEKI_NAMESPACE_BEGIN
47 PROMEKI_SHARED_BASE(AudioMeter)
50 using Ptr = SharedPtr<AudioMeter,
false>;
52 virtual ~AudioMeter() =
default;
61 virtual void process(
const float *samples,
size_t frames,
size_t channels) = 0;
64 virtual void reset() = 0;
99class AudioPeakRmsMeter :
public AudioMeter {
100 PROMEKI_SHARED_DERIVED(AudioPeakRmsMeter)
103 using Ptr = SharedPtr<AudioPeakRmsMeter,
false>;
106 explicit AudioPeakRmsMeter(
size_t channels) { setChannels(channels); }
108 AudioPeakRmsMeter(
const AudioPeakRmsMeter &) =
delete;
109 AudioPeakRmsMeter &operator=(
const AudioPeakRmsMeter &) =
delete;
112 void setChannels(
size_t channels) {
113 _channels = channels;
117 _peak = MeterArray::createArrayValueInit(channels);
118 _rms = MeterArray::createArrayValueInit(channels);
122 size_t channels()
const {
return _channels; }
125 float peak(
size_t ch)
const {
126 if (ch >= _channels)
return 0.0f;
127 return _peak[ch].load(MemoryOrder::Relaxed);
131 float rms(
size_t ch)
const {
132 if (ch >= _channels)
return 0.0f;
133 return _rms[ch].load(MemoryOrder::Relaxed);
146 void setPeakDecay(
float decay) { _peakDecay = decay; }
156 void setRmsWindow(
size_t windowFrames) {
157 if (windowFrames == 0) windowFrames = 1;
158 _rmsAlpha = 1.0f /
static_cast<float>(windowFrames);
162 void process(
const float *samples,
size_t frames,
size_t channels)
override {
163 if (channels > _channels) channels = _channels;
164 if (frames == 0 || channels == 0)
return;
166 const float decay = _peakDecay;
167 const float alpha = _rmsAlpha;
169 for (
size_t c = 0; c < channels; ++c) {
170 float peak = _peak[c].load(MemoryOrder::Relaxed) * decay;
172 float held = _rms[c].load(MemoryOrder::Relaxed);
173 float msq = held * held;
174 for (
size_t f = 0; f < frames; ++f) {
175 float s = samples[f * channels + c];
176 float a = std::fabs(s);
177 if (a > peak) peak = a;
178 msq = msq + alpha * (s * s - msq);
180 _peak[c].store(peak, MemoryOrder::Relaxed);
181 _rms[c].store(std::sqrt(msq < 0.0f ? 0.0f : msq), MemoryOrder::Relaxed);
186 void reset()
override {
187 for (
size_t i = 0; i < _channels; ++i) {
188 _peak[i].store(0.0f, MemoryOrder::Relaxed);
189 _rms[i].store(0.0f, MemoryOrder::Relaxed);
198 using MeterArray = promeki::UniquePtr<promeki::Atomic<float>[]>;
200 size_t _channels = 0;
203 float _peakDecay = 1.0f;
204 float _rmsAlpha = 1.0f / 4800.0f;