diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index e6dfb690..53d9f9a1 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -1,27 +1,27 @@ #![macro_use] -//! I2S +//! Support for I2S audio use core::future::poll_fn; use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; -use embassy_cortex_m::interrupt::{InterruptExt, Priority}; +use embassy_cortex_m::interrupt::InterruptExt; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; use crate::gpio::{AnyPin, Pin as GpioPin}; use crate::interrupt::Interrupt; -use crate::pac::i2s::{RegisterBlock, CONFIG, PSEL}; +use crate::pac::i2s::RegisterBlock; use crate::Peripheral; // TODO: Define those in lib.rs somewhere else -// -// I2S EasyDMA MAXCNT bit length = 14 + +/// I2S EasyDMA MAXCNT bit length = 14 const MAX_DMA_MAXCNT: u32 = 1 << 14; -// Limits for Easy DMA - it can only read from data ram +/// Limits for Easy DMA - it can only read from data ram pub const SRAM_LOWER: usize = 0x2000_0000; pub const SRAM_UPPER: usize = 0x3000_0000; @@ -36,35 +36,144 @@ pub enum Error { BufferLengthMisaligned, } -pub const MODE_MASTER_8000: Mode = Mode::Master { - freq: MckFreq::_32MDiv125, - ratio: Ratio::_32x, -}; // error = 0 -pub const MODE_MASTER_11025: Mode = Mode::Master { - freq: MckFreq::_32MDiv15, - ratio: Ratio::_192x, -}; // error = 86 -pub const MODE_MASTER_16000: Mode = Mode::Master { - freq: MckFreq::_32MDiv21, - ratio: Ratio::_96x, -}; // error = 127 -pub const MODE_MASTER_22050: Mode = Mode::Master { - freq: MckFreq::_32MDiv15, - ratio: Ratio::_96x, -}; // error = 172 -pub const MODE_MASTER_32000: Mode = Mode::Master { - freq: MckFreq::_32MDiv21, - ratio: Ratio::_48x, -}; // error = 254 -pub const MODE_MASTER_44100: Mode = Mode::Master { - freq: MckFreq::_32MDiv15, - ratio: Ratio::_48x, -}; // error = 344 -pub const MODE_MASTER_48000: Mode = Mode::Master { - freq: MckFreq::_32MDiv21, - ratio: Ratio::_32x, -}; // error = 381 +/// Approximate sample rates. +/// +/// Those are common sample rates that can not be configured without an small error. +/// +/// For custom master clock configuration, please refer to [Mode]. +#[derive(Clone, Copy)] +pub enum ApproxSampleRate { + _11025, + _16000, + _22050, + _32000, + _44100, + _48000, +} +impl From for Mode { + fn from(value: ApproxSampleRate) -> Self { + match value { + // error = 86 + ApproxSampleRate::_11025 => Mode::Master { + freq: MckFreq::_32MDiv15, + ratio: Ratio::_192x, + }, + // error = 127 + ApproxSampleRate::_16000 => Mode::Master { + freq: MckFreq::_32MDiv21, + ratio: Ratio::_96x, + }, + // error = 172 + ApproxSampleRate::_22050 => Mode::Master { + freq: MckFreq::_32MDiv15, + ratio: Ratio::_96x, + }, + // error = 254 + ApproxSampleRate::_32000 => Mode::Master { + freq: MckFreq::_32MDiv21, + ratio: Ratio::_48x, + }, + // error = 344 + ApproxSampleRate::_44100 => Mode::Master { + freq: MckFreq::_32MDiv15, + ratio: Ratio::_48x, + }, + // error = 381 + ApproxSampleRate::_48000 => Mode::Master { + freq: MckFreq::_32MDiv21, + ratio: Ratio::_32x, + }, + } + } +} + +impl ApproxSampleRate { + pub fn sample_rate(&self) -> u32 { + // This will always provide a Master mode, so it is safe to unwrap. + Mode::from(*self).sample_rate().unwrap() + } +} + +/// Exact sample rates. +/// +/// Those are non standard sample rates that can be configured without error. +/// +/// For custom master clock configuration, please refer to [Mode]. +#[derive(Clone, Copy)] +pub enum ExactSampleRate { + _8000, + _10582, + _12500, + _15625, + _15873, + _25000, + _31250, + _50000, + _62500, + _100000, + _125000, +} + +impl ExactSampleRate { + pub fn sample_rate(&self) -> u32 { + // This will always provide a Master mode, so it is safe to unwrap. + Mode::from(*self).sample_rate().unwrap() + } +} + +impl From for Mode { + fn from(value: ExactSampleRate) -> Self { + match value { + ExactSampleRate::_8000 => Mode::Master { + freq: MckFreq::_32MDiv125, + ratio: Ratio::_32x, + }, + ExactSampleRate::_10582 => Mode::Master { + freq: MckFreq::_32MDiv63, + ratio: Ratio::_48x, + }, + ExactSampleRate::_12500 => Mode::Master { + freq: MckFreq::_32MDiv10, + ratio: Ratio::_256x, + }, + ExactSampleRate::_15625 => Mode::Master { + freq: MckFreq::_32MDiv32, + ratio: Ratio::_64x, + }, + ExactSampleRate::_15873 => Mode::Master { + freq: MckFreq::_32MDiv63, + ratio: Ratio::_32x, + }, + ExactSampleRate::_25000 => Mode::Master { + freq: MckFreq::_32MDiv10, + ratio: Ratio::_128x, + }, + ExactSampleRate::_31250 => Mode::Master { + freq: MckFreq::_32MDiv32, + ratio: Ratio::_32x, + }, + ExactSampleRate::_50000 => Mode::Master { + freq: MckFreq::_32MDiv10, + ratio: Ratio::_64x, + }, + ExactSampleRate::_62500 => Mode::Master { + freq: MckFreq::_32MDiv16, + ratio: Ratio::_32x, + }, + ExactSampleRate::_100000 => Mode::Master { + freq: MckFreq::_32MDiv10, + ratio: Ratio::_32x, + }, + ExactSampleRate::_125000 => Mode::Master { + freq: MckFreq::_32MDiv8, + ratio: Ratio::_32x, + }, + } + } +} + +/// I2S configuration. #[derive(Clone)] #[non_exhaustive] pub struct Config { @@ -78,7 +187,7 @@ pub struct Config { impl Default for Config { fn default() -> Self { Self { - mode: MODE_MASTER_32000, + mode: ExactSampleRate::_31250.into(), swidth: SampleWidth::_16bit, align: Align::Left, format: Format::I2S, @@ -132,10 +241,12 @@ impl MckFreq { 256000, ]; + /// Return the value that needs to be written to the register. pub fn to_register_value(&self) -> u32 { Self::REGISTER_VALUES[usize::from(*self)] } + /// Return the master clock frequency. pub fn to_frequency(&self) -> u32 { Self::FREQUENCIES[usize::from(*self)] } @@ -147,7 +258,10 @@ impl From for usize { } } -/// MCK / LRCK ratio. +/// Master clock frequency ratio +/// +/// Sample Rate = LRCK = MCK / Ratio +/// #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum Ratio { _32x, @@ -175,6 +289,7 @@ impl From for u8 { } } +/// Sample width. #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum SampleWidth { _8bit, @@ -188,7 +303,7 @@ impl From for u8 { } } -/// Alignment of sample within a frame. +/// Channel used for the most significant sample value in a frame. #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum Align { Left, @@ -220,11 +335,13 @@ impl From for bool { } } -/// Enable channels. +/// Channels #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum Channels { Stereo, + /// Mono left Left, + /// Mono right Right, } @@ -235,8 +352,6 @@ impl From for u8 { } /// Interface to the I2S peripheral using EasyDMA to offload the transmission and reception workload. -/// -/// For more details about EasyDMA, consult the module documentation. pub struct I2S<'d, T: Instance> { _p: PeripheralRef<'d, T>, } @@ -278,29 +393,32 @@ impl<'d, T: Instance> I2S<'d, T> { ) -> Self { into_ref!(i2s, irq, mck, sck, lrck, sdin, sdout); - let r = T::regs(); - Self::apply_config(&r.config, &config); - Self::select_pins(&r.psel, mck, sck, lrck, sdin, sdout); - Self::setup_interrupt(irq, r); + Self::apply_config(&config); + Self::select_pins(mck, sck, lrck, sdin, sdout); + Self::setup_interrupt(irq); - r.enable.write(|w| w.enable().enabled()); + T::regs().enable.write(|w| w.enable().enabled()); Self { _p: i2s } } + /// I2S output only pub fn output(self) -> Output<'d, T> { Output { _p: self._p } } + /// I2S input only pub fn input(self) -> Input<'d, T> { Input { _p: self._p } } + /// I2S full duplex (input and output) pub fn full_duplex(self) -> FullDuplex<'d, T> { FullDuplex { _p: self._p } } - fn apply_config(c: &CONFIG, config: &Config) { + fn apply_config(config: &Config) { + let c = &T::regs().config; match config.mode { Mode::Master { freq, ratio } => { c.mode.write(|w| w.mode().master()); @@ -322,13 +440,14 @@ impl<'d, T: Instance> I2S<'d, T> { } fn select_pins( - psel: &PSEL, mck: PeripheralRef<'d, AnyPin>, sck: PeripheralRef<'d, AnyPin>, lrck: PeripheralRef<'d, AnyPin>, sdin: PeripheralRef<'d, AnyPin>, sdout: PeripheralRef<'d, AnyPin>, ) { + let psel = &T::regs().psel; + psel.mck.write(|w| { unsafe { w.bits(mck.psel_bits()) }; w.connect().connected() @@ -355,21 +474,23 @@ impl<'d, T: Instance> I2S<'d, T> { }); } - fn setup_interrupt(irq: PeripheralRef<'d, T::Interrupt>, r: &RegisterBlock) { + fn setup_interrupt(irq: PeripheralRef<'d, T::Interrupt>) { irq.set_handler(Self::on_interrupt); - // irq.set_priority(Priority::P1); // TODO review priorities irq.unpend(); irq.enable(); let device = Device::::new(); device.disable_tx_ptr_interrupt(); device.disable_rx_ptr_interrupt(); + device.disable_stopped_interrupt(); device.reset_tx_ptr_event(); device.reset_rx_ptr_event(); + device.reset_stopped_event(); device.enable_tx_ptr_interrupt(); device.enable_rx_ptr_interrupt(); + device.enable_stopped_interrupt(); } fn on_interrupt(_: *mut ()) { @@ -387,41 +508,40 @@ impl<'d, T: Instance> I2S<'d, T> { s.rx_waker.wake(); device.disable_rx_ptr_interrupt(); } + + if device.is_stopped() { + trace!("STOPPED INT"); + s.stop_waker.wake(); + device.disable_stopped_interrupt(); + } } -} -pub struct Output<'d, T: Instance> { - _p: PeripheralRef<'d, T>, -} - -impl<'d, T: Instance> Output<'d, T> { - /// Starts I2S transfer. - #[inline(always)] - pub fn start(&self, buffer: B) -> Result<(), Error> - where - B: Buffer, - { - // TODO what to do if it is started already? + async fn stop() { + compiler_fence(Ordering::SeqCst); let device = Device::::new(); - device.enable(); - device.set_tx_buffer(buffer)?; - device.enable_tx(); - device.start(); + device.stop(); - Ok(()) + T::state().started.store(false, Ordering::Relaxed); + + poll_fn(|cx| { + T::state().stop_waker.register(cx.waker()); + + if device.is_stopped() { + trace!("STOP: Ready"); + device.reset_stopped_event(); + Poll::Ready(()) + } else { + trace!("STOP: Pending"); + Poll::Pending + } + }) + .await; + + device.disable(); } - /// Stops the I2S transfer and waits until it has stopped. - #[inline(always)] - pub async fn stop(&self) { - todo!() - } - - /// Transmits the given `buffer`. - /// Buffer address must be 4 byte aligned and located in RAM. - #[allow(unused_mut)] - pub async fn send(&mut self, buffer: B) -> Result<(), Error> + async fn send(buffer: B) -> Result<(), Error> where B: Buffer, { @@ -454,24 +574,191 @@ impl<'d, T: Instance> Output<'d, T> { Ok(()) } + + async fn receive(buffer: B) -> Result<(), Error> + where + B: Buffer, + { + trace!("RECEIVE: {}", buffer.bytes_ptr() as u32); + + let device = Device::::new(); + let drop = device.on_rx_drop(); + + compiler_fence(Ordering::SeqCst); + + poll_fn(|cx| { + T::state().rx_waker.register(cx.waker()); + + if device.is_rx_ptr_updated() { + trace!("RX POLL: Ready"); + device.reset_rx_ptr_event(); + device.enable_rx_ptr_interrupt(); + Poll::Ready(()) + } else { + trace!("RX POLL: Pending"); + Poll::Pending + } + }) + .await; + + device.set_rx_buffer(buffer)?; + + compiler_fence(Ordering::SeqCst); + drop.defuse(); + + Ok(()) + } } +/// I2S output +pub struct Output<'d, T: Instance> { + _p: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Output<'d, T> { + /// Prepare the initial buffer and start the I2S transfer. + pub async fn start(&self, buffer: B) -> Result<(), Error> + where + B: Buffer, + { + let device = Device::::new(); + + let s = T::state(); + if s.started.load(Ordering::Relaxed) { + self.stop().await; + } + + device.enable(); + device.enable_tx(); + device.set_tx_buffer(buffer)?; + + s.started.store(true, Ordering::Relaxed); + + device.start(); + + Ok(()) + } + + /// Stops the I2S transfer and waits until it has stopped. + #[inline(always)] + pub async fn stop(&self) { + I2S::::stop().await + } + + /// Sets the given `buffer` for transmission in the DMA. + /// Buffer address must be 4 byte aligned and located in RAM. + /// The buffer must not be written while being used by the DMA, + /// which takes two other `send`s being awaited. + #[allow(unused_mut)] + pub async fn send(&mut self, buffer: B) -> Result<(), Error> + where + B: Buffer, + { + I2S::::send(buffer).await + } +} + +/// I2S input pub struct Input<'d, T: Instance> { _p: PeripheralRef<'d, T>, } impl<'d, T: Instance> Input<'d, T> { - // TODO + /// Prepare the initial buffer and start the I2S transfer. + pub async fn start(&self, buffer: B) -> Result<(), Error> + where + B: Buffer, + { + let device = Device::::new(); + + let s = T::state(); + if s.started.load(Ordering::Relaxed) { + self.stop().await; + } + + device.enable(); + device.enable_rx(); + device.set_rx_buffer(buffer)?; + + s.started.store(true, Ordering::Relaxed); + + device.start(); + + Ok(()) + } + + /// Stops the I2S transfer and waits until it has stopped. + #[inline(always)] + pub async fn stop(&self) { + I2S::::stop().await + } + + /// Sets the given `buffer` for reception from the DMA. + /// Buffer address must be 4 byte aligned and located in RAM. + /// The buffer must not be read while being used by the DMA, + /// which takes two other `receive`s being awaited. + #[allow(unused_mut)] + pub async fn receive(&mut self, buffer: B) -> Result<(), Error> + where + B: Buffer, + { + I2S::::receive(buffer).await + } } +/// I2S ful duplex (input & output) pub struct FullDuplex<'d, T: Instance> { _p: PeripheralRef<'d, T>, } impl<'d, T: Instance> FullDuplex<'d, T> { - // TODO + /// Prepare the initial buffers and start the I2S transfer. + pub async fn start(&self, buffer_out: B, buffer_in: B) -> Result<(), Error> + where + B: Buffer, + { + let device = Device::::new(); + + let s = T::state(); + if s.started.load(Ordering::Relaxed) { + self.stop().await; + } + + device.enable(); + device.enable_tx(); + device.enable_rx(); + device.set_tx_buffer(buffer_out)?; + device.set_rx_buffer(buffer_in)?; + + s.started.store(true, Ordering::Relaxed); + + device.start(); + + Ok(()) + } + + /// Stops the I2S transfer and waits until it has stopped. + #[inline(always)] + pub async fn stop(&self) { + I2S::::stop().await + } + + /// Sets the given `buffer_out` and `buffer_in` for transmission/reception from the DMA. + /// Buffer address must be 4 byte aligned and located in RAM. + /// The buffers must not be written/read while being used by the DMA, + /// which takes two other `send_and_receive` operations being awaited. + #[allow(unused_mut)] + pub async fn send_and_receive(&mut self, buffer_out: B, buffer_in: B) -> Result<(), Error> + where + B: Buffer, + { + I2S::::send(buffer_out).await?; + I2S::::receive(buffer_in).await?; + Ok(()) + } } +/// Helper encapsulating common I2S device operations. struct Device(&'static RegisterBlock, PhantomData); impl Device { @@ -521,6 +808,34 @@ impl Device { self.0.tasks_start.write(|w| unsafe { w.bits(1) }); } + #[inline(always)] + fn stop(&self) { + self.0.tasks_stop.write(|w| unsafe { w.bits(1) }); + } + + #[inline(always)] + fn is_stopped(&self) -> bool { + self.0.events_stopped.read().bits() != 0 + } + + #[inline(always)] + fn reset_stopped_event(&self) { + trace!("STOPPED EVENT: Reset"); + self.0.events_stopped.reset(); + } + + #[inline(always)] + fn disable_stopped_interrupt(&self) { + trace!("STOPPED INTERRUPT: Disabled"); + self.0.intenclr.write(|w| w.stopped().clear()); + } + + #[inline(always)] + fn enable_stopped_interrupt(&self) { + trace!("STOPPED INTERRUPT: Enabled"); + self.0.intenset.write(|w| w.stopped().set()); + } + #[inline] fn set_tx_buffer(&self, buffer: B) -> Result<(), Error> where @@ -606,6 +921,23 @@ impl Device { }) } + #[inline] + fn on_rx_drop(&self) -> OnDrop { + OnDrop::new(move || { + trace!("RX DROP: Stopping"); + + let device = Device::::new(); + device.disable_rx_ptr_interrupt(); + device.reset_rx_ptr_event(); + device.disable_rx(); + + // TX is stopped almost instantly, spinning is fine. + while !device.is_rx_ptr_updated() {} + + trace!("RX DROP: Stopped"); + }) + } + fn validate_buffer(buffer: B) -> Result<(u32, u32), Error> where B: Buffer, @@ -632,6 +964,56 @@ impl Device { } } +/// Sample details +pub trait Sample: Sized + Copy + Default { + const WIDTH: usize; + const SCALE: Self; +} + +impl Sample for i8 { + const WIDTH: usize = 8; + const SCALE: Self = 1 << (Self::WIDTH - 1); +} + +impl Sample for i16 { + const WIDTH: usize = 16; + const SCALE: Self = 1 << (Self::WIDTH - 1); +} + +impl Sample for i32 { + const WIDTH: usize = 24; + const SCALE: Self = 1 << (Self::WIDTH - 1); +} + +/// A 4-bytes aligned [Buffer]. +#[repr(align(4))] +pub struct AlignedBuffer([T; N]); + +impl AlignedBuffer { + pub fn new(array: [T; N]) -> Self { + Self(array) + } +} + +impl Default for AlignedBuffer { + fn default() -> Self { + Self([T::default(); N]) + } +} + +impl AsRef<[T]> for AlignedBuffer { + fn as_ref(&self) -> &[T] { + self.0.as_slice() + } +} + +impl AsMut<[T]> for AlignedBuffer { + fn as_mut(&mut self) -> &mut [T] { + self.0.as_mut_slice() + } +} + +/// Common operations required for a buffer to be used by the DMA pub trait Buffer: Sized { fn bytes_ptr(&self) -> *const u8; fn bytes_len(&self) -> usize; @@ -674,22 +1056,25 @@ impl Buffer for &[i32] { } pub(crate) mod sealed { - use core::sync::atomic::AtomicI32; + use core::sync::atomic::AtomicBool; use embassy_sync::waitqueue::AtomicWaker; - use super::*; - + /// Peripheral static state pub struct State { + pub started: AtomicBool, pub rx_waker: AtomicWaker, pub tx_waker: AtomicWaker, + pub stop_waker: AtomicWaker, } impl State { pub const fn new() -> Self { Self { + started: AtomicBool::new(false), rx_waker: AtomicWaker::new(), tx_waker: AtomicWaker::new(), + stop_waker: AtomicWaker::new(), } } } @@ -704,8 +1089,6 @@ pub trait Instance: Peripheral

+ sealed::Instance + 'static + Send { type Interrupt: Interrupt; } -// TODO: Unsure why this macro is flagged as unused by CI when in fact it's used elsewhere? -#[allow(unused_macros)] macro_rules! impl_i2s { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::i2s::sealed::Instance for peripherals::$type { diff --git a/examples/nrf/src/bin/i2s.rs b/examples/nrf/src/bin/i2s-generate.rs similarity index 62% rename from examples/nrf/src/bin/i2s.rs rename to examples/nrf/src/bin/i2s-generate.rs index 9b3144f2..f59b63ce 100644 --- a/examples/nrf/src/bin/i2s.rs +++ b/examples/nrf/src/bin/i2s-generate.rs @@ -4,59 +4,41 @@ use core::f32::consts::PI; -use defmt::{error, info, trace}; +use defmt::{error, info}; use embassy_executor::Spawner; -use embassy_nrf::gpio::{Input, Pin, Pull}; -use embassy_nrf::i2s::{Channels, MckFreq, Mode, Ratio, SampleWidth, MODE_MASTER_32000}; -use embassy_nrf::pac::ficr::info; -use embassy_nrf::{i2s, interrupt}; +use embassy_nrf::i2s::{self, Sample as _}; +use embassy_nrf::interrupt; use {defmt_rtt as _, panic_probe as _}; -#[repr(align(4))] -pub struct AlignedBuffer(T); - -impl AsRef for AlignedBuffer { - fn as_ref(&self) -> &T { - &self.0 - } -} - -impl AsMut for AlignedBuffer { - fn as_mut(&mut self) -> &mut T { - &mut self.0 - } -} - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); + let mut config = i2s::Config::default(); - config.mode = MODE_MASTER_32000; - // config.mode = Mode::Master { - // freq: MckFreq::_32MDiv10, - // ratio: Ratio::_256x, - // }; // 12500 Hz - config.channels = Channels::Left; - config.swidth = SampleWidth::_16bit; + config.mode = i2s::ExactSampleRate::_50000.into(); + config.channels = i2s::Channels::Left; + config.swidth = i2s::SampleWidth::_16bit; let sample_rate = config.mode.sample_rate().expect("I2S Master"); let inv_sample_rate = 1.0 / sample_rate as f32; info!("Sample rate: {}", sample_rate); // Wait for a button press + // use embassy_nrf::gpio::{Input, Pin, Pull}; // let mut btn1 = Input::new(p.P1_00.degrade(), Pull::Up); // btn1.wait_for_low().await; let irq = interrupt::take!(I2S); - let mut i2s = i2s::I2S::new(p.I2S, irq, p.P0_28, p.P0_29, p.P0_31, p.P0_11, p.P0_30, config).output(); + let mut i2s = i2s::I2S::new(p.I2S, irq, p.P0_28, p.P0_29, p.P0_31, p.P0_27, p.P0_30, config) + .output(); type Sample = i16; - const MAX_UNIPOLAR_VALUE: Sample = (1 << 15) as Sample; - const NUM_SAMPLES: usize = 2000; - let mut buffers: [AlignedBuffer<[Sample; NUM_SAMPLES]>; 3] = [ - AlignedBuffer([0; NUM_SAMPLES]), - AlignedBuffer([0; NUM_SAMPLES]), - AlignedBuffer([0; NUM_SAMPLES]), + const NUM_SAMPLES: usize = 6000; + + let mut buffers: [i2s::AlignedBuffer; 3] = [ + i2s::AlignedBuffer::default(), + i2s::AlignedBuffer::default(), + i2s::AlignedBuffer::default(), ]; let mut carrier = SineOsc::new(); @@ -66,32 +48,29 @@ async fn main(_spawner: Spawner) { freq_mod.set_amplitude(1.0); let mut amp_mod = SineOsc::new(); - amp_mod.set_frequency(4.0, inv_sample_rate); + amp_mod.set_frequency(16.0, inv_sample_rate); amp_mod.set_amplitude(0.5); let mut generate = |buf: &mut [Sample]| { - let ptr = buf as *const [Sample] as *const Sample as u32; - trace!("GEN: {}", ptr); - - for sample in &mut buf.as_mut().chunks_mut(1) { - let signal = carrier.generate(); + for sample in &mut buf.chunks_mut(1) { let freq_modulation = bipolar_to_unipolar(freq_mod.generate()); - carrier.set_frequency(220.0 + 220.0 * freq_modulation, inv_sample_rate); + carrier.set_frequency(220.0 + 440.0 * freq_modulation, inv_sample_rate); let amp_modulation = bipolar_to_unipolar(amp_mod.generate()); carrier.set_amplitude(amp_modulation); - let value = (MAX_UNIPOLAR_VALUE as f32 * signal) as Sample; + let signal = carrier.generate(); + let value = (Sample::SCALE as f32 * signal) as Sample; sample[0] = value; } }; - generate(buffers[0].as_mut().as_mut_slice()); - generate(buffers[1].as_mut().as_mut_slice()); + generate(buffers[0].as_mut()); + generate(buffers[1].as_mut()); - i2s.start(buffers[0].as_ref().as_slice()).expect("I2S Start"); + i2s.start(buffers[0].as_ref()).await.expect("I2S Start"); let mut index = 1; loop { - if let Err(err) = i2s.send(buffers[index].as_ref().as_slice()).await { + if let Err(err) = i2s.send(buffers[index].as_ref()).await { error!("{}", err); } @@ -99,7 +78,7 @@ async fn main(_spawner: Spawner) { if index >= 3 { index = 0; } - generate(buffers[index].as_mut().as_mut_slice()); + generate(buffers[index].as_mut()); } }