#pragma once #include "microphone.h" #include "esphome/components/audio/audio.h" #include #include #include #include #include namespace esphome { namespace microphone { static const int32_t MAX_GAIN_FACTOR = 64; class MicrophoneSource { /* * @brief Helper class that handles converting raw microphone data to a requested format. * Components requesting microphone audio should register a callback through this class instead of registering a * callback directly with the microphone if a particular format is required. * * Raw microphone data may have a different number of bits per sample and number of channels than the requesting * component needs. This class handles the conversion by: * - Internally adds a callback to receive the raw microphone data * - The ``process_audio_`` handles the raw data * - Only the channels set in the ``channels_`` bitset are passed through * - Passed through samples have the bits per sample converted * - A gain factor is optionally applied to increase the volume - audio may clip! * - The processed audio is passed to the callback of the component requesting microphone data * - It tracks an internal enabled state, so it ignores raw microphone data when the component requesting * microphone data is not actively requesting audio. * * Note that this class cannot convert sample rates! */ public: MicrophoneSource(Microphone *mic, uint8_t bits_per_sample, int32_t gain_factor, bool passive) : mic_(mic), bits_per_sample_(bits_per_sample), gain_factor_(gain_factor), passive_(passive) {} /// @brief Enables a channel to be processed through the callback. /// /// If the microphone component only has reads from one channel, it is always in channel number 0, regardless if it /// represents left or right. If the microphone reads from both left and right, channel number 0 and 1 represent the /// left and right channels respectively. /// /// @param channel 0-indexed channel number to enable void add_channel(uint8_t channel) { this->channels_.set(channel); } void add_data_callback(std::function &)> &&data_callback); void set_gain_factor(int32_t gain_factor) { this->gain_factor_ = clamp(gain_factor, 1, MAX_GAIN_FACTOR); } int32_t get_gain_factor() { return this->gain_factor_; } /// @brief Gets the AudioStreamInfo of the data after processing /// @return audio::AudioStreamInfo with the configured bits per sample, configured channel count, and source /// microphone's sample rate audio::AudioStreamInfo get_audio_stream_info(); void start(); void stop(); bool is_passive() const { return this->passive_; } bool is_running() const { return (this->mic_->is_running() && (this->enabled_ || this->passive_)); } bool is_stopped() const { return !this->is_running(); }; protected: void process_audio_(const std::vector &data, std::vector &filtered_data); std::shared_ptr> processed_samples_; Microphone *mic_; uint8_t bits_per_sample_; std::bitset<8> channels_; int32_t gain_factor_; bool enabled_{false}; bool passive_; // Only pass audio if ``mic_`` is already running }; } // namespace microphone } // namespace esphome