A high-performance audio element for ESP-ADF that provides real-time volume level monitoring with customizable callbacks. Perfect for creating volume indicators, VU meters, or audio level visualizations in your ESP32 audio projects.
- Real-time volume monitoring - Calculates RMS values for both stereo channels
- Configurable update rates - 1-100 Hz (recommended 10-30 Hz) callback frequency
- Logarithmic scaling - Provides perceptually accurate 0-100% volume levels
- Low CPU overhead - Optimized fast square root and efficient RMS calculations
- Stereo & Mono support - Works with both mono and stereo audio streams
- Easy integration - Simple callback-based API for UI updates
- Multiple sample rates - Supports 8kHz to 192kHz sample rates
- Memory efficient - Minimal memory footprint with no dynamic allocations during processing
- ESP-ADF: v2.7 or newer
- ESP-IDF: Compatible with ESP-ADF supported versions
- Audio formats: 16-bit PCM (8, 24, 32-bit support in header but currently only 16-bit implemented)
- Sample rates: 8kHz - 192kHz
- Channels: Mono and Stereo
- Copy
volume_meter.candvolume_meter.hto your ESP-ADF project - Add the source file to your CMakeLists.txt or component configuration
- Include the header in your main application file
#include "volume_meter.h"
// Callback function to handle volume updates
void my_volume_callback(int left_volume, int right_volume) {
printf("Volume: L=%d%% R=%d%%\n", left_volume, right_volume);
// Update your volume bars, LEDs, or display here
}
// Create volume meter with default settings
audio_element_handle_t volume_meter = create_volume_meter(44100, 15, my_volume_callback);
// Add to your audio pipeline
audio_pipeline_register(pipeline, volume_meter, "volume_meter");// Custom configuration
volume_meter_cfg_t config = {
.sample_rate = 44100,
.channels = 2,
.bits_per_sample = 16,
.frame_size = 1024,
.update_rate_hz = 20,
.volume_callback = my_volume_callback
};
audio_element_handle_t volume_meter = volume_meter_init(&config);volume_meter_cfg_t config = V_METER_CFG_DEFAULT();
config.update_rate_hz = 25;
config.volume_callback = my_volume_callback;
audio_element_handle_t volume_meter = volume_meter_init(&config);typedef struct {
int sample_rate; // Sample rate (e.g. 44100)
int channels; // Number of channels (1=mono, 2=stereo)
int bits_per_sample; // Bits per sample (currently only 16-bit supported)
int frame_size; // Buffer size in bytes
int update_rate_hz; // Update frequency (1-100 Hz)
void (*volume_callback)(int left_volume, int right_volume); // Callback function
} volume_meter_cfg_t;Initializes the volume meter element with custom configuration.
Parameters:
config: Pointer to configuration structure
Returns: audio_element_handle_t or NULL on error
Creates a volume meter with default settings and specified parameters.
Parameters:
sample_rate: Audio sample rate (8000-192000 Hz)update_rate: Callback frequency (1-100 Hz)callback: Volume update callback function
Returns: audio_element_handle_t or NULL on error
volume_meter_update_format(audio_element_handle_t self, int sample_rate, int channels, int bits_per_sample)
Updates audio format parameters during runtime.
Parameters:
self: Volume meter element handlesample_rate: New sample ratechannels: New channel count (1-2)bits_per_sample: New bit depth (8, 16, 24, 32)
Returns: ESP_OK on success, error code on failure
Changes the callback update frequency.
Parameters:
self: Volume meter element handleupdate_rate_hz: New update rate (1-100 Hz)
Returns: ESP_OK on success, error code on failure
Here's a complete example showing integration with LVGL for a visual volume meter:
#include "volume_meter.h"
#include "lvgl.h"
lv_obj_t *volume_bar_left;
lv_obj_t *volume_bar_right;
void ui_volume_callback(int left_volume, int right_volume) {
// Update LVGL volume bars
lv_bar_set_value(volume_bar_left, left_volume, LV_ANIM_OFF);
lv_bar_set_value(volume_bar_right, right_volume, LV_ANIM_OFF);
}
void setup_audio_pipeline() {
// Create pipeline
audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
audio_pipeline_handle_t pipeline = audio_pipeline_init(&pipeline_cfg);
// Create volume meter
audio_element_handle_t volume_meter = create_volume_meter(44100, 20, ui_volume_callback);
// Create other audio elements (decoder, etc.)
// ...
// Register elements
audio_pipeline_register(pipeline, volume_meter, "volume_meter");
// Link pipeline: [decoder] -> [volume_meter] -> [output]
const char *link_tag[3] = {"decoder", "volume_meter", "output"};
audio_pipeline_link(pipeline, &link_tag[0], 3);
// Start pipeline
audio_pipeline_run(pipeline);
}- Uses RMS (Root Mean Square) calculation for accurate volume measurement
- Logarithmic scaling approximation using lookup tables for perceptually correct levels
- Fast square root implementation optimized for ESP32
- Configurable silence threshold and maximum volume limits
- CPU Usage: ~1-2% at 44.1kHz, 15Hz update rate
- Memory: ~3-5KB RAM usage (including task stack)
- Latency: Minimal processing delay (pass-through design)
- Accuracy: ±1% volume level accuracy
The element uses a logarithmic approximation with 16 threshold points to convert RMS values to perceptually accurate 0-100% levels. Linear interpolation between thresholds ensures smooth level transitions.
- Audio Visualizers: Create spectrum analyzers and VU meters
- Recording Applications: Monitor input levels during recording
- Voice Applications: Voice activity detection and level monitoring
- Music Players: Real-time volume display and peak detection
- Audio Processing: Dynamic range compression and automatic gain control
Contributions are welcome! Please feel free to submit pull requests, bug reports, or feature requests.
This project is licensed under the MIT License - see the LICENSE file for details.
Jaromir Kopp - 2025
This element is designed for ESP-ADF v2.7+ and has been tested with various audio formats and sample rates. For questions or support, please open an issue on GitHub.