74 lines
2.3 KiB
C++
74 lines
2.3 KiB
C++
#include "sound.h"
|
|
|
|
#include "pico/stdlib.h"
|
|
#include "hardware/pwm.h"
|
|
#include "hardware/dma.h"
|
|
#include "hardware/irq.h"
|
|
#include "hardware/clocks.h"
|
|
#include "alarm_sound.h"
|
|
#include "pins.h"
|
|
|
|
#define SAMPLE_RATE 22050 // 22.05kHz
|
|
#define PWM_WRAP 255 // 8-bit resolution
|
|
volatile float volume_multiplier = 4.0f; // todo load from flash
|
|
|
|
static uint32_t audio_pos = 0;
|
|
static bool audio_playing = false;
|
|
|
|
// Timer callback for audio playback
|
|
bool audio_timer_callback(repeating_timer_t *rt) {
|
|
if (!audio_playing || audio_pos >= alarm_sound_wav_len) {
|
|
audio_playing = false;
|
|
return false; // Stop timer
|
|
}
|
|
|
|
// Get the original audio sample
|
|
uint8_t sample = alarm_sound_wav[audio_pos++];
|
|
|
|
// Apply volume amplification
|
|
// Convert to float, center around 0, apply multiplier, then center back around 128
|
|
float amplified = ((float)sample - 128.0f) * volume_multiplier + 128.0f;
|
|
|
|
// Clamp the result to valid 8-bit range (0-255)
|
|
if (amplified < 0.0f) amplified = 0.0f;
|
|
else if (amplified > 255.0f) amplified = 255.0f;
|
|
|
|
// Set PWM duty cycle with amplified sample
|
|
pwm_set_gpio_level(SPEAKER_PIN, (uint8_t)amplified);
|
|
|
|
return true; // Continue timer
|
|
}
|
|
|
|
void setup_pwm_audio() {
|
|
// Set up PWM for audio output
|
|
gpio_set_function(SPEAKER_PIN, GPIO_FUNC_PWM);
|
|
uint slice_num = pwm_gpio_to_slice_num(SPEAKER_PIN);
|
|
|
|
// Configure PWM for 8-bit resolution
|
|
pwm_config config = pwm_get_default_config();
|
|
|
|
// Calculate clock divider for desired PWM frequency
|
|
// PWM frequency should be much higher than audio sample rate
|
|
// Target: ~250kHz PWM frequency for good audio quality
|
|
float clock_div = (float)clock_get_hz(clk_sys) / (PWM_WRAP + 1) / 250000.0f;
|
|
pwm_config_set_clkdiv(&config, clock_div);
|
|
pwm_config_set_wrap(&config, PWM_WRAP);
|
|
|
|
pwm_init(slice_num, &config, true);
|
|
pwm_set_gpio_level(SPEAKER_PIN, 128); // Set to middle level (silence)
|
|
}
|
|
|
|
void play_alarm_audio() {
|
|
audio_pos = 0;
|
|
audio_playing = true;
|
|
|
|
// Set up timer for sample rate (22.05kHz)
|
|
static repeating_timer_t timer;
|
|
int32_t delay_us = -1000000 / SAMPLE_RATE; // Negative for precise timing
|
|
add_repeating_timer_us(delay_us, audio_timer_callback, NULL, &timer);
|
|
}
|
|
|
|
void stop_alarm_audio() {
|
|
audio_playing = false;
|
|
pwm_set_gpio_level(SPEAKER_PIN, 128); // Return to silence level
|
|
} |