ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
microphone_source.cpp
Go to the documentation of this file.
1#include "microphone_source.h"
2
3#include <array>
4
5#include <gain.h> // esp-audio-libs
6#include <pcm_convert.h> // esp-audio-libs
7
8namespace esphome::microphone {
9
10// Builds the exact LinearGain for an integer factor without the float dB conversion: the factor is
11// mantissa / 2^31 * 2^exponent, with the exponent set to the factor's bit width.
12static esp_audio_libs::gain::LinearGain factor_to_linear_gain(uint32_t factor) {
13 esp_audio_libs::gain::LinearGain gain;
14 gain.exponent = 32 - __builtin_clz(factor);
15 gain.mantissa_q31 = static_cast<int32_t>(factor << (31 - gain.exponent));
16 return gain;
17}
18
20 return audio::AudioStreamInfo(this->bits_per_sample_, this->channels_.count(),
21 this->mic_->get_audio_stream_info().get_sample_rate());
22}
23
25 if (!this->enabled_ && !this->passive_) {
26 this->enabled_ = true;
27 this->mic_->start();
28 }
29}
30
32 if (this->enabled_ && !this->passive_) {
33 this->enabled_ = false;
34 this->mic_->stop();
35 this->processed_samples_.reset();
36 }
37}
38
39void MicrophoneSource::process_audio_(const std::vector<uint8_t> &data, std::vector<uint8_t> &filtered_data) {
40 const audio::AudioStreamInfo source_info = this->mic_->get_audio_stream_info();
41 const uint32_t total_frames = source_info.bytes_to_frames(data.size());
42 const uint8_t target_bytes_per_sample = (this->bits_per_sample_ + 7) / 8;
43
44 // Enabled channels in ascending order, which is their order in each output frame
45 std::array<uint8_t, 8> channel_map;
46 uint8_t target_channels = 0;
47 for (size_t channel = 0; channel < this->channels_.size(); ++channel) {
48 if (this->channels_.test(channel)) {
49 channel_map[target_channels++] = static_cast<uint8_t>(channel);
50 }
51 }
52
53 filtered_data.resize(static_cast<size_t>(total_frames) * target_bytes_per_sample * target_channels);
54
55 // Applies the gain at full precision before narrowing; samples saturate at full scale, and narrowing rounds
56 esp_audio_libs::pcm_convert::copy_frames_with_gain(data.data(), filtered_data.data(), source_info.samples_to_bytes(1),
57 source_info.get_channels(), target_bytes_per_sample,
58 channel_map.data(), target_channels,
59 factor_to_linear_gain(this->gain_factor_), total_frames);
60}
61
62} // namespace esphome::microphone
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)
AlsGain501 gain
static void uint32_t