FastLED 3.9.15
Loading...
Searching...
No Matches
audio.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/fft.h"
4#include "fl/math.h"
5#include "fl/memory.h"
6#include "fl/span.h"
7#include "fl/vector.h"
8#include "fl/int.h"
9#include <math.h>
10#include "fl/stdint.h"
11
12namespace fl {
13
14class AudioSampleImpl;
15
17
18// AudioSample is a wrapper around AudioSampleImpl, hiding the reference
19// counting so that the api object can be simple and have standard object
20// semantics.
22 public:
26 AudioSample(const AudioSample &other) : mImpl(other.mImpl) {}
27 AudioSample(AudioSampleImplPtr impl) : mImpl(impl) {}
28 AudioSample &operator=(const AudioSample &other);
29 bool isValid() const { return mImpl != nullptr; }
30
31 fl::size size() const;
32 // Raw pcm levels.
33 const VectorPCM &pcm() const;
34 // Zero crossing factor between 0.0f -> 1.0f, detects "hiss"
35 // and sounds like cloths rubbing. Useful for sound analysis.
36 float zcf() const;
37 float rms() const;
38 fl::u32 timestamp() const; // Timestamp when sample became valid (millis)
39
40 void fft(FFTBins *out) const;
41
42 const_iterator begin() const { return pcm().begin(); }
43 const_iterator end() const { return pcm().end(); }
44 const fl::i16 &at(fl::size i) const;
45 const fl::i16 &operator[](fl::size i) const;
46 operator bool() const { return isValid(); }
47 bool operator==(const AudioSample &other) const;
48 bool operator!=(const AudioSample &other) const;
49
50 private:
51 static const VectorPCM &empty();
52 AudioSampleImplPtr mImpl;
53};
54
55// Sound level meter is a persistant measuring class that will auto-tune the
56// microphone to real world SPL levels. It will adapt to the noise floor of the
57// environment. Note that the microphone only ever outputs DBFS (dB Full Scale)
58// values, which are collected over a stream of samples. The sound level meter
59// will convert this to SPL (Sound Pressure Level) values, which are the real
60// world values.
62 public:
66 SoundLevelMeter(double spl_floor = 33.0, double smoothing_alpha = 0.0);
67
69 void processBlock(const fl::i16 *samples, fl::size count);
71 processBlock(samples.data(), samples.size());
72 }
73
75 double getDBFS() const { return current_dbfs_; }
76
78 double getSPL() const { return current_spl_; }
79
81 void setFloorSPL(double spl_floor) {
82 spl_floor_ = spl_floor;
84 }
85
87 void resetFloor() {
88 dbfs_floor_global_ = INFINITY_DOUBLE; // infinity<double>
89 offset_ = 0.0;
90 }
91
92 private:
93 double spl_floor_; // e.g. 33.0 dB SPL
94 double smoothing_alpha_; // 0 = pure min, >0 = slow adapt
95 double dbfs_floor_global_; // lowest dBFS seen so far
96 double offset_; // spl_floor_ − dbfs_floor_global_
97 double current_dbfs_; // last block’s dBFS
98 double current_spl_; // last block’s estimated SPL
99};
100
101// Implementation details.
103 public:
106 // template <typename It> void assign(It begin, It end) {
107 // assign(begin, end, 0); // Default timestamp to 0
108 // }
109 template <typename It> void assign(It begin, It end, fl::u32 timestamp) {
110 mSignedPcm.assign(begin, end);
112 // calculate zero crossings
114 }
115 const VectorPCM &pcm() const { return mSignedPcm; }
116 fl::u32 timestamp() const { return mTimestamp; }
117
118 // "Zero crossing factor". High values > .4 indicate hissing
119 // sounds. For example a microphone rubbing against a clothing.
120 // These types of signals indicate the audio should be ignored.
121 // Low zero crossing factors (with loud sound) indicate that there
122 // is organized sound like that coming from music. This is so cheap
123 // to calculate it's done automatically. It should be one of the first
124 // signals to reject or accept a sound signal.
125 //
126 // Returns: a value -> [0.0f, 1.0f)
127 float zcf() const {
128 const fl::size n = pcm().size();
129 if (n < 2) {
130 return 0.f;
131 }
132 return float(mZeroCrossings) / static_cast<float>(n - 1);
133 }
134
135 private:
137 mZeroCrossings = 0;
138 if (mSignedPcm.size() > 1) {
139 for (fl::size i = 1; i < mSignedPcm.size(); ++i) {
140 const bool crossed =
141 (mSignedPcm[i - 1] < 0 && mSignedPcm[i] >= 0) ||
142 (mSignedPcm[i - 1] >= 0 && mSignedPcm[i] < 0);
143 if (crossed) {
145 }
146 }
147 }
148 }
149
151 fl::i16 mZeroCrossings = 0;
152 fl::u32 mTimestamp = 0;
153};
154
155} // namespace fl
AudioAnalyzeFFT1024 fft
const VectorPCM & pcm() const
Definition audio.cpp:17
AudioSampleImplPtr mImpl
Definition audio.h:52
VectorPCM::const_iterator const_iterator
Definition audio.h:24
fl::vector< fl::i16 > VectorPCM
Definition audio.h:23
float zcf() const
Definition audio.cpp:74
fl::size size() const
Definition audio.cpp:30
AudioSample(const AudioSample &other)
Definition audio.h:26
bool operator!=(const AudioSample &other) const
Definition audio.cpp:64
bool isValid() const
Definition audio.h:29
AudioSample(AudioSampleImplPtr impl)
Definition audio.h:27
bool operator==(const AudioSample &other) const
Definition audio.cpp:46
const fl::i16 & operator[](fl::size i) const
Definition audio.cpp:44
float rms() const
Definition audio.cpp:83
const fl::i16 & at(fl::size i) const
Definition audio.cpp:37
fl::u32 timestamp() const
Definition audio.cpp:76
const_iterator begin() const
Definition audio.h:42
const_iterator end() const
Definition audio.h:43
AudioSample & operator=(const AudioSample &other)
Definition audio.cpp:25
static const VectorPCM & empty()
Definition audio.cpp:68
float zcf() const
Definition audio.h:127
fl::u32 mTimestamp
Definition audio.h:152
fl::u32 timestamp() const
Definition audio.h:116
fl::vector< fl::i16 > VectorPCM
Definition audio.h:104
void initZeroCrossings()
Definition audio.h:136
fl::i16 mZeroCrossings
Definition audio.h:151
void assign(It begin, It end, fl::u32 timestamp)
Definition audio.h:109
VectorPCM mSignedPcm
Definition audio.h:150
const VectorPCM & pcm() const
Definition audio.h:115
fl::size size() const
Definition vector.h:545
iterator begin()
Definition vector.h:584
iterator end()
Definition vector.h:590
const T * data() const
Definition slice.h:138
fl::size size() const
Definition slice.h:142
SoundLevelMeter(double spl_floor=33.0, double smoothing_alpha=0.0)
Definition audio.cpp:97
double getDBFS() const
Definition audio.h:75
double dbfs_floor_global_
Definition audio.h:95
double current_dbfs_
Definition audio.h:97
void processBlock(fl::span< const fl::i16 > samples)
Definition audio.h:70
void setFloorSPL(double spl_floor)
change your known noise-floor SPL at runtime
Definition audio.h:81
double getSPL() const
Definition audio.h:78
double smoothing_alpha_
Definition audio.h:94
void processBlock(const fl::i16 *samples, fl::size count)
Process a block of int16 PCM samples.
Definition audio.cpp:102
double spl_floor_
Definition audio.h:93
double current_spl_
Definition audio.h:98
void resetFloor()
reset so the next quiet block will re-initialize your floor
Definition audio.h:87
#define INFINITY_DOUBLE
Definition math_macros.h:77
Slice< T > span
Definition span.h:8
constexpr T * begin(T(&array)[N]) noexcept
Definition range_access.h:9
constexpr T * end(T(&array)[N]) noexcept
HeapVector< T, Allocator > vector
Definition vector.h:1214
IMPORTANT!
Definition crgb.h:20
#define FASTLED_SMART_PTR(type)
Definition ptr.h:33