mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-26 23:35:53 +00:00
allow userapps to change sample rate of audio
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use crate::Audio;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
use embassy_futures::{join::join, yield_now};
|
||||
use embassy_rp::{
|
||||
Peri,
|
||||
@@ -23,9 +23,12 @@ const SILENCE: u8 = u8::MAX / 2;
|
||||
pub static mut AUDIO_BUFFER: [u8; AUDIO_BUFFER_SAMPLES * 2] = [SILENCE; AUDIO_BUFFER_SAMPLES * 2];
|
||||
static mut AUDIO_BUFFER_1: [u8; AUDIO_BUFFER_SAMPLES * 2] = [SILENCE; AUDIO_BUFFER_SAMPLES * 2];
|
||||
|
||||
// atomics for user applications to signal changes to audio buffers
|
||||
pub static AUDIO_BUFFER_READY: AtomicBool = AtomicBool::new(true);
|
||||
pub static AUDIO_BUFFER_WRITTEN: AtomicBool = AtomicBool::new(false);
|
||||
pub static AUDIO_BUFFER_SAMPLE_RATE: AtomicU32 = AtomicU32::new(SAMPLE_RATE_HZ);
|
||||
|
||||
/// resets audio buffers after user applications are unloaded
|
||||
pub fn clear_audio_buffers() {
|
||||
unsafe {
|
||||
AUDIO_BUFFER.fill(SILENCE);
|
||||
@@ -41,8 +44,29 @@ pub async fn audio_handler(mut audio: Audio) {
|
||||
let mut pwm_pio_right =
|
||||
PioPwmAudio::new(audio.dma1, &mut audio.pio, audio.sm1, audio.right, &prg);
|
||||
|
||||
// enable sms at the same time to ensure they are synced
|
||||
audio.pio.apply_sm_batch(|pio| {
|
||||
pio.set_enable(&mut pwm_pio_right.sm, true);
|
||||
pio.set_enable(&mut pwm_pio_left.sm, true);
|
||||
});
|
||||
|
||||
let mut sample_rate = SAMPLE_RATE_HZ;
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
let new_sample_rate = AUDIO_BUFFER_SAMPLE_RATE.load(Ordering::Acquire);
|
||||
if new_sample_rate != sample_rate {
|
||||
sample_rate = new_sample_rate;
|
||||
pwm_pio_left.reconfigure(sample_rate);
|
||||
pwm_pio_right.reconfigure(sample_rate);
|
||||
|
||||
// restart sms at the same time to ensure they are synced
|
||||
audio.pio.apply_sm_batch(|pio| {
|
||||
pio.restart(&mut pwm_pio_right.sm);
|
||||
pio.restart(&mut pwm_pio_left.sm);
|
||||
});
|
||||
}
|
||||
|
||||
if AUDIO_BUFFER_WRITTEN.load(Ordering::Acquire) {
|
||||
write_samples(&mut pwm_pio_left, &mut pwm_pio_right, &AUDIO_BUFFER_1).await;
|
||||
AUDIO_BUFFER_1.fill(SILENCE);
|
||||
@@ -130,6 +154,11 @@ struct PioPwmAudio<'d, PIO: Instance, const SM: usize> {
|
||||
}
|
||||
|
||||
impl<'d, PIO: Instance, const SM: usize> PioPwmAudio<'d, PIO, SM> {
|
||||
fn get_sm_divider(sample_rate: u32) -> u32 {
|
||||
let target_clock = (u8::MAX as u32 + 1) * sample_rate;
|
||||
clk_sys_freq() / target_clock
|
||||
}
|
||||
|
||||
fn new(
|
||||
dma: Peri<'d, impl Channel>,
|
||||
pio: &mut Common<'d, PIO>,
|
||||
@@ -151,17 +180,18 @@ impl<'d, PIO: Instance, const SM: usize> PioPwmAudio<'d, PIO, SM> {
|
||||
cfg.use_program(&prg.0, &[&pin]);
|
||||
sm.set_config(&cfg);
|
||||
|
||||
let target_clock = (u8::MAX as u32 + 1) * SAMPLE_RATE_HZ;
|
||||
let divider = (clk_sys_freq() / target_clock).to_fixed();
|
||||
sm.set_clock_divider(divider);
|
||||
|
||||
sm.set_enable(true);
|
||||
sm.set_clock_divider(Self::get_sm_divider(SAMPLE_RATE_HZ).to_fixed());
|
||||
|
||||
Self {
|
||||
dma: dma.into(),
|
||||
sm,
|
||||
}
|
||||
}
|
||||
|
||||
fn reconfigure(&mut self, sample_rate: u32) {
|
||||
self.sm
|
||||
.set_clock_divider(Self::get_sm_divider(sample_rate).to_fixed());
|
||||
}
|
||||
}
|
||||
|
||||
/// packs two u8 samples into 32bit word
|
||||
|
||||
@@ -204,6 +204,9 @@ fn patch_syscalls(
|
||||
SyscallTable::ReadFile => syscalls::read_file as usize,
|
||||
SyscallTable::WriteFile => syscalls::write_file as usize,
|
||||
SyscallTable::FileLen => syscalls::file_len as usize,
|
||||
SyscallTable::ReconfigureAudioSampleRate => {
|
||||
syscalls::reconfigure_audio_sample_rate as usize
|
||||
}
|
||||
SyscallTable::AudioBufferReady => syscalls::audio_buffer_ready as usize,
|
||||
SyscallTable::SendAudioBuffer => syscalls::send_audio_buffer as usize,
|
||||
};
|
||||
|
||||
@@ -7,8 +7,8 @@ use embedded_sdmmc::LfnBuffer;
|
||||
use heapless::spsc::Queue;
|
||||
use userlib_sys::{
|
||||
AUDIO_BUFFER_SAMPLES, Alloc, AudioBufferReady, CLayout, CPixel, Dealloc, DrawIter, FileLen,
|
||||
GenRand, GetMs, ListDir, Print, ReadFile, RngRequest, SendAudioBuffer, SleepMs, WriteFile,
|
||||
keyboard::*,
|
||||
GenRand, GetMs, ListDir, Print, ReadFile, ReconfigureAudioSampleRate, RngRequest,
|
||||
SendAudioBuffer, SleepMs, WriteFile, keyboard::*,
|
||||
};
|
||||
|
||||
#[cfg(feature = "psram")]
|
||||
@@ -18,7 +18,7 @@ use crate::heap::HEAP;
|
||||
use core::alloc::GlobalAlloc;
|
||||
|
||||
use crate::{
|
||||
audio::{AUDIO_BUFFER, AUDIO_BUFFER_READY, AUDIO_BUFFER_WRITTEN},
|
||||
audio::{AUDIO_BUFFER, AUDIO_BUFFER_READY, AUDIO_BUFFER_SAMPLE_RATE, AUDIO_BUFFER_WRITTEN},
|
||||
display::FRAMEBUFFER,
|
||||
framebuffer::FB_PAUSED,
|
||||
storage::{Dir, File, SDCARD},
|
||||
@@ -333,6 +333,11 @@ pub extern "C" fn file_len(str: *const u8, len: usize) -> usize {
|
||||
len as usize
|
||||
}
|
||||
|
||||
const _: ReconfigureAudioSampleRate = reconfigure_audio_sample_rate;
|
||||
pub extern "C" fn reconfigure_audio_sample_rate(sample_rate: u32) {
|
||||
AUDIO_BUFFER_SAMPLE_RATE.store(sample_rate, Ordering::Release);
|
||||
}
|
||||
|
||||
const _: AudioBufferReady = audio_buffer_ready;
|
||||
pub extern "C" fn audio_buffer_ready() -> bool {
|
||||
AUDIO_BUFFER_READY.load(Ordering::Acquire)
|
||||
|
||||
@@ -12,7 +12,7 @@ use strum::{EnumCount, EnumIter};
|
||||
|
||||
pub type EntryFn = fn();
|
||||
|
||||
pub const SYS_CALL_TABLE_COUNT: usize = 14;
|
||||
pub const SYS_CALL_TABLE_COUNT: usize = 15;
|
||||
const _: () = assert!(SYS_CALL_TABLE_COUNT == SyscallTable::COUNT);
|
||||
|
||||
#[derive(Clone, Copy, EnumIter, EnumCount)]
|
||||
@@ -30,8 +30,9 @@ pub enum SyscallTable {
|
||||
ReadFile = 9,
|
||||
WriteFile = 10,
|
||||
FileLen = 11,
|
||||
AudioBufferReady = 12,
|
||||
SendAudioBuffer = 13,
|
||||
ReconfigureAudioSampleRate = 12,
|
||||
AudioBufferReady = 13,
|
||||
SendAudioBuffer = 14,
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -473,6 +474,17 @@ pub extern "C" fn file_len(str: *const u8, len: usize) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
pub type ReconfigureAudioSampleRate = extern "C" fn(sample_rate: u32);
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn reconfigure_audio_sample_rate(sample_rate: u32) {
|
||||
unsafe {
|
||||
let ptr = SYS_CALL_TABLE[SyscallTable::ReconfigureAudioSampleRate as usize];
|
||||
let f: ReconfigureAudioSampleRate = core::mem::transmute(ptr);
|
||||
f(sample_rate)
|
||||
}
|
||||
}
|
||||
|
||||
pub type AudioBufferReady = extern "C" fn() -> bool;
|
||||
|
||||
#[allow(unused)]
|
||||
|
||||
Reference in New Issue
Block a user