ledstick-rs/src/main.rs
2025-03-21 22:27:53 +01:00

116 lines
3.7 KiB
Rust

pub mod audio_input;
pub mod audio_process;
pub mod config;
pub mod effects;
pub mod helpers;
pub mod led_output;
pub mod triple_buffer;
use esp_idf_svc::{
hal::peripherals::Peripherals,
sys::{esp_dsp, esp_nofail},
};
use embassy_executor::Spawner;
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use static_cell::StaticCell;
use audio_input::mic_input_task;
use audio_process::{process_audio, AudioBuffer, AudioStats, DspBuffer};
use config::{AUDIO_SAMPLES_PER_BUF, LED_COUNT};
use effects::{
bass_sparks::LedEffectBassSparks,
led_effect::{LedData, LedEffect},
};
use led_output::output_leds;
use triple_buffer::{Receiver, Sender, TripleBuffer};
#[embassy_executor::task]
async fn effect_task(
mut led_effect: LedEffectBassSparks,
input: Receiver<'static, NoopRawMutex, (DspBuffer, AudioStats)>,
output: Sender<'static, NoopRawMutex, LedData>,
) {
led_effect.process_led_effect(input, output).await;
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
// It is necessary to call this function once. Otherwise some patches to the runtime
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
esp_idf_svc::sys::link_patches();
// Bind the log crate to the ESP Logging facilities
esp_idf_svc::log::EspLogger::initialize_default();
let peripherals = Peripherals::take().unwrap();
// mic buffers
static AUDIO_BUFFER_CELL: StaticCell<[AudioBuffer; 3]> = StaticCell::new();
let audio_buffer = AUDIO_BUFFER_CELL.init([[0; AUDIO_SAMPLES_PER_BUF]; 3]);
static AUDIO_CHANNEL_CELL: StaticCell<TripleBuffer<'_, NoopRawMutex, AudioBuffer>> =
StaticCell::new();
let audio_channel = AUDIO_CHANNEL_CELL.init(TripleBuffer::new(audio_buffer));
let (audio_sender, audio_receiver) = audio_channel.split();
// fft buffers
static FFT_BUFFER_CELL: StaticCell<[(DspBuffer, AudioStats); 3]> = StaticCell::new();
let fft_buffer =
FFT_BUFFER_CELL.init([([0f32; AUDIO_SAMPLES_PER_BUF], AudioStats::default()); 3]);
static FFT_CHANNEL_CELL: StaticCell<TripleBuffer<'_, NoopRawMutex, (DspBuffer, AudioStats)>> =
StaticCell::new();
let fft_channel = FFT_CHANNEL_CELL.init(TripleBuffer::new(fft_buffer));
let (fft_sender, fft_receiver) = fft_channel.split();
// leds
static LED_DATA: StaticCell<[LedData; 3]> = StaticCell::new();
let leds = LED_DATA.init([LedData::default(); 3]);
static LED_CHANNEL: StaticCell<TripleBuffer<'_, NoopRawMutex, LedData>> = StaticCell::new();
let led_channel = LED_CHANNEL.init(TripleBuffer::new(leds));
let (led_sender, led_receiver) = led_channel.split();
unsafe {
esp_nofail!(esp_dsp::dsps_fft2r_init_fc32(
std::ptr::null_mut(),
(AUDIO_SAMPLES_PER_BUF / 2) as i32
));
esp_nofail!(esp_dsp::dsps_fft4r_init_fc32(
std::ptr::null_mut(),
(AUDIO_SAMPLES_PER_BUF / 2) as i32
));
}
spawner
.spawn(mic_input_task(
peripherals.i2s0,
peripherals.pins.gpio5,
peripherals.pins.gpio4,
peripherals.pins.gpio6,
audio_sender,
))
.expect("spawn failed");
spawner
.spawn(process_audio(audio_receiver, fft_sender))
.expect("spawn failed");
spawner
.spawn(effect_task(
LedEffectBassSparks::default(),
fft_receiver,
led_sender,
))
.expect("spawn failed");
spawner
.spawn(output_leds(
peripherals.spi2,
peripherals.pins.gpio11,
peripherals.pins.gpio12,
led_receiver,
))
.expect("spawn failed");
}