ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
microphone_source.cpp
Go to the documentation of this file.
1#include "microphone_source.h"
2
3namespace esphome::microphone {
4
5static const int32_t Q25_MAX_VALUE = (1 << 25) - 1;
6static const int32_t Q25_MIN_VALUE = ~Q25_MAX_VALUE;
7
9 return audio::AudioStreamInfo(this->bits_per_sample_, this->channels_.count(),
10 this->mic_->get_audio_stream_info().get_sample_rate());
11}
12
14 if (!this->enabled_ && !this->passive_) {
15 this->enabled_ = true;
16 this->mic_->start();
17 }
18}
19
21 if (this->enabled_ && !this->passive_) {
22 this->enabled_ = false;
23 this->mic_->stop();
24 this->processed_samples_.reset();
25 }
26}
27
28void MicrophoneSource::process_audio_(const std::vector<uint8_t> &data, std::vector<uint8_t> &filtered_data) {
29 // - Bit depth conversions are obtained by truncating bits or padding with zeros - no dithering is applied.
30 // - In the comments, Qxx refers to a fixed point number with xx bits of precision for representing fractional values.
31 // For example, audio with a bit depth of 16 can store a sample in a int16, which can be considered a Q15 number.
32 // - All samples are converted to Q25 before applying the gain factor - this results in a small precision loss for
33 // data with 32 bits per sample. Since the maximum gain factor is 64 = (1<<6), this ensures that applying the gain
34 // will never overflow a 32 bit signed integer. This still retains more bit depth than what is audibly noticeable.
35 // - Loops for reading/writing data buffers are unrolled, assuming little endian, for a small performance increase.
36
37 const size_t source_bytes_per_sample = this->mic_->get_audio_stream_info().samples_to_bytes(1);
38 const uint32_t source_channels = this->mic_->get_audio_stream_info().get_channels();
39
40 const size_t source_bytes_per_frame = this->mic_->get_audio_stream_info().frames_to_bytes(1);
41
42 const uint32_t total_frames = this->mic_->get_audio_stream_info().bytes_to_frames(data.size());
43 const size_t target_bytes_per_sample = (this->bits_per_sample_ + 7) / 8;
44 const size_t target_bytes_per_frame = target_bytes_per_sample * this->channels_.count();
45
46 filtered_data.resize(target_bytes_per_frame * total_frames);
47
48 uint8_t *current_data = filtered_data.data();
49
50 for (uint32_t frame_index = 0; frame_index < total_frames; ++frame_index) {
51 for (uint32_t channel_index = 0; channel_index < source_channels; ++channel_index) {
52 if (this->channels_.test(channel_index)) {
53 // Channel's current sample is included in the target mask. Convert bits per sample, if necessary.
54
55 const uint32_t sample_index = frame_index * source_bytes_per_frame + channel_index * source_bytes_per_sample;
56
57 int32_t sample = audio::unpack_audio_sample_to_q31(&data[sample_index], source_bytes_per_sample); // Q31
58 sample >>= 6; // Q31 -> Q25
59
60 // Apply gain using multiplication
61 sample *= this->gain_factor_; // Q25
62
63 // Clamp ``sample`` in case gain multiplication overflows 25 bits
64 sample = clamp<int32_t>(sample, Q25_MIN_VALUE, Q25_MAX_VALUE); // Q25
65
66 sample *= (1 << 6); // Q25 -> Q31
67
68 audio::pack_q31_as_audio_sample(sample, current_data, target_bytes_per_sample);
69 current_data = current_data + target_bytes_per_sample;
70 }
71 }
72 }
73}
74
75} // namespace esphome::microphone
size_t frames_to_bytes(uint32_t frames) const
Converts frames to bytes.
Definition audio.h:53
size_t samples_to_bytes(uint32_t samples) const
Converts samples to bytes.
Definition audio.h:58
uint32_t bytes_to_frames(size_t bytes) const
Convert bytes to frames.
Definition audio.h:43
uint8_t get_channels() const
Definition audio.h:29
audio::AudioStreamInfo get_audio_stream_info()
Definition microphone.h:39
std::shared_ptr< std::vector< uint8_t > > processed_samples_
audio::AudioStreamInfo get_audio_stream_info()
Gets the AudioStreamInfo of the data after processing.
void process_audio_(const std::vector< uint8_t > &data, std::vector< uint8_t > &filtered_data)
int32_t unpack_audio_sample_to_q31(const uint8_t *data, size_t bytes_per_sample)
Unpacks a quantized audio sample into a Q31 fixed-point number.
Definition audio.h:156
void pack_q31_as_audio_sample(int32_t sample, uint8_t *data, size_t bytes_per_sample)
Packs a Q31 fixed-point number as an audio sample with the specified number of bytes per sample.
Definition audio.h:182
static void uint32_t