FastLED 3.10.8
Loading...
Searching...
No Matches
audio.cpp.hpp
Go to the documentation of this file.
1
2#include "fl/audio/audio.h"
3#include "fl/audio/fft/fft.h"
4#include "fl/math/math.h"
5#include "fl/stl/move.h"
6#include "fl/stl/mutex.h"
7#include "fl/stl/shared_ptr.h"
8#include "fl/stl/singleton.h"
9#include "fl/stl/span.h"
10#include "fl/stl/vector.h"
11#include "fl/stl/int.h"
12#include "fl/stl/noexcept.h"
13
14namespace fl {
15namespace audio {
16
17namespace {
18
19struct GuardedFFT {
22 fl::unique_lock<fl::mutex> lock(mtx);
23 fft.run(sample, out, args);
24 }
25
26 private:
29};
30
31// Object pool implementation
32
34 void put(SampleImplPtr&& impl) FL_NO_EXCEPT {
35 if (impl.unique()) {
36 // There is no more shared_ptr to this object, so we can recycle it.
37 fl::unique_lock<fl::mutex> lock(mutex);
38 if (impl && pool.size() < MAX_POOL_SIZE) {
39 // Reset the impl for reuse (clear internal state)
40 impl->reset();
41 pool.push_back(impl);
42 return;
43 }
44 }
45 // Pool is full, discard the impl
46 impl.reset();
47 }
48 SampleImplPtr getOrCreate() FL_NO_EXCEPT {
49 {
50 fl::unique_lock<fl::mutex> lock(mutex);
51 if (!pool.empty()) {
52 SampleImplPtr impl = pool.back();
53 pool.pop_back();
54 return impl;
55 }
56 }
58 }
59
61 static constexpr fl::size MAX_POOL_SIZE = 8;
63};
64
65} // namespace
66
71
77
79 if (isValid()) {
80 return mImpl->pcm();
81 }
82 static VectorPCM empty;
83 return empty;
84}
85
87 mImpl = other.mImpl;
88 return *this;
89}
90
91fl::size Sample::size() const FL_NO_EXCEPT {
92 if (isValid()) {
93 return mImpl->pcm().size();
94 }
95 return 0;
96}
97
98const fl::i16 &Sample::at(fl::size i) const FL_NO_EXCEPT {
99 if (i < size()) {
100 return pcm()[i];
101 }
102 return empty()[0];
103}
104
105const fl::i16 &Sample::operator[](fl::size i) const FL_NO_EXCEPT { return at(i); }
106
107bool Sample::operator==(const Sample &other) const FL_NO_EXCEPT {
108 if (mImpl == other.mImpl) {
109 return true;
110 }
111 if (mImpl == nullptr || other.mImpl == nullptr) {
112 return false;
113 }
114 if (mImpl->pcm().size() != other.mImpl->pcm().size()) {
115 return false;
116 }
117 for (fl::size i = 0; i < mImpl->pcm().size(); ++i) {
118 if (mImpl->pcm()[i] != other.mImpl->pcm()[i]) {
119 return false;
120 }
121 }
122 return true;
123}
124
125bool Sample::operator!=(const Sample &other) const FL_NO_EXCEPT {
126 return !(*this == other);
127}
128
130 static fl::i16 empty_data[1] = {0}; // okay static in header
131 static VectorPCM empty(empty_data); // okay static in header
132 return empty;
133}
134
135float Sample::zcf() const FL_NO_EXCEPT { return mImpl->zcf(); }
136
138 if (isValid()) {
139 return mImpl->timestamp();
140 }
141 return 0;
142}
143
144// O(1) - returns pre-computed cached value
146 if (!isValid()) {
147 return 0.0f;
148 }
149 return mImpl->rms();
150}
151
152SoundLevelMeter::SoundLevelMeter(double spl_floor, double smoothing_alpha)
153 FL_NO_EXCEPT : mSplFloor(spl_floor), mSmoothingAlpha(smoothing_alpha),
155 mCurrentSpl(spl_floor) {}
156
157void SoundLevelMeter::processBlock(const fl::i16 *samples, fl::size count) FL_NO_EXCEPT {
158 if (count == 0) {
159 return;
160 }
161
162 // 1) compute block power → dBFS
163 double sum_sq = 0.0;
164 for (fl::size i = 0; i < count; ++i) {
165 double s = samples[i] / 32768.0; // normalize to ±1
166 sum_sq += s * s;
167 }
168 double p = sum_sq / count; // mean power
169 double dbfs = 10.0 * log10(p + 1e-12);
170 mCurrentDbfs = dbfs;
171
172 // 2) update global floor (with optional smoothing)
173 if (dbfs < mDbfsFloorGlobal) {
175 mDbfsFloorGlobal = dbfs;
176 } else {
179 }
181 }
182
183 // 3) estimate SPL
184 mCurrentSpl = dbfs + mOffset;
185}
186
190 args.samples = sample.size();
191 args.bands = out->bands();
194 args.sample_rate =
195 fft::Args::DefaultSampleRate(); // TODO: get sample rate from Sample
197}
198
199
201 if (!isValid() || gain == 1.0f) return;
202 auto& samples = mImpl->pcm_mutable();
203 for (fl::size i = 0; i < samples.size(); ++i) {
204 fl::i32 val = static_cast<fl::i32>(static_cast<float>(samples[i]) * gain);
205 if (val > 32767) val = 32767;
206 if (val < -32768) val = -32768;
207 samples[i] = static_cast<fl::i16>(val);
208 }
209 mImpl->pcmDidChange();
210}
211
218
219
220} // namespace audio
221} // namespace fl
static T & instance() FL_NO_EXCEPT
Definition singleton.h:41
void fft(fft::Bins *out) const FL_NO_EXCEPT
bool operator==(const Sample &other) const FL_NO_EXCEPT
const VectorPCM & pcm() const FL_NO_EXCEPT
Definition audio.cpp.hpp:78
const fl::i16 & at(fl::size i) const FL_NO_EXCEPT
Definition audio.cpp.hpp:98
const_iterator end() const FL_NO_EXCEPT
Definition audio.h:49
const_iterator begin() const FL_NO_EXCEPT
Definition audio.h:48
fl::u32 timestamp() const FL_NO_EXCEPT
bool isValid() const FL_NO_EXCEPT
Definition audio.h:35
const fl::i16 & operator[](fl::size i) const FL_NO_EXCEPT
SampleImplPtr mImpl
Definition audio.h:62
fl::vector< fl::i16 > VectorPCM
Definition audio.h:24
float zcf() const FL_NO_EXCEPT
static const VectorPCM & empty() FL_NO_EXCEPT
bool operator!=(const Sample &other) const FL_NO_EXCEPT
Sample() FL_NO_EXCEPT
Definition audio.h:26
fl::size size() const FL_NO_EXCEPT
Definition audio.cpp.hpp:91
Sample & operator=(const Sample &other) FL_NO_EXCEPT
Definition audio.cpp.hpp:86
float rms() const FL_NO_EXCEPT
~Sample() FL_NO_EXCEPT
Definition audio.cpp.hpp:72
void applyGain(float gain) FL_NO_EXCEPT
Apply a digital gain multiplier to all PCM samples in-place.
void initZeroCrossings() FL_NO_EXCEPT
Definition audio.h:170
void pcmDidChange() FL_NO_EXCEPT
Definition audio.cpp.hpp:67
SoundLevelMeter(double spl_floor=33.0, double smoothing_alpha=0.0) FL_NO_EXCEPT
void processBlock(const fl::i16 *samples, fl::size count) FL_NO_EXCEPT
Process a block of int16 PCM samples.
const T * data() const FL_NO_EXCEPT
Definition span.h:486
constexpr fl::size size() const FL_NO_EXCEPT
Definition span.h:483
#define FL_INFINITY_DOUBLE
Definition math.h:50
Platform-independent mutex interface.
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
Definition move.h:30
shared_ptr< T > make_shared(Args &&... args) FL_NO_EXCEPT
Definition shared_ptr.h:423
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
CRGB sample(const CRGB *grid, const XYMap &xyMap, float x, float y, SampleMode mode) FL_NO_EXCEPT
Sample a pixel from a 2D CRGB grid at floating-point coordinates.
double log10(double value) FL_NO_EXCEPT
Definition math.h:433
fl::platforms::mutex mutex
Definition mutex.h:20
Base definition for an LED controller.
Definition crgb.hpp:179
corkscrew_args args
Definition old.h:149
void run(fl::span< const fl::i16 > sample, fft::Bins *out, const fft::Args &args) FL_NO_EXCEPT
Definition audio.cpp.hpp:20
static int DefaultSampleRate() FL_NO_EXCEPT
Definition fft.h:129
static float DefaultMinFrequency() FL_NO_EXCEPT
Definition fft.h:127
static float DefaultMaxFrequency() FL_NO_EXCEPT
Definition fft.h:128