aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Perez Llamas <[email protected]>2022-11-12 18:48:57 +0100
committerChristian Perez Llamas <[email protected]>2022-11-12 18:48:57 +0100
commit122a31d20877005c7201d4e7c98da5544666dd1d (patch)
treec97037ba880f63a4e03e642c6630efb1042a3cde
parent10e3c3f2ec358da6d81f2bb9c05936c2ab6da567 (diff)
Interrupts, async, sine oscillator
-rw-r--r--embassy-nrf/src/i2s.rs296
-rw-r--r--embassy-nrf/src/lib.rs2
-rw-r--r--examples/nrf/src/bin/i2s.rs132
3 files changed, 329 insertions, 101 deletions
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
index fb6fa4bdf..f5e36f0dd 100644
--- a/embassy-nrf/src/i2s.rs
+++ b/embassy-nrf/src/i2s.rs
@@ -2,17 +2,18 @@
2 2
3//! I2S 3//! I2S
4 4
5//use core::future::poll_fn; 5use core::future::poll_fn;
6//use core::sync::atomic::{compiler_fence, Ordering}; 6use core::sync::atomic::{compiler_fence, Ordering};
7//use core::task::Poll; 7use core::task::Poll;
8 8
9//use embassy_hal_common::drop::OnDrop; 9use embassy_cortex_m::interrupt::{InterruptExt, Priority};
10use embassy_hal_common::drop::OnDrop;
10use embassy_hal_common::{into_ref, PeripheralRef}; 11use embassy_hal_common::{into_ref, PeripheralRef};
11 12
12//use crate::gpio::sealed::Pin as _; 13//use crate::gpio::sealed::Pin as _;
13use crate::gpio::{AnyPin, Pin as GpioPin}; 14use crate::gpio::{AnyPin, Pin as GpioPin};
14use crate::interrupt::Interrupt; 15use crate::interrupt::Interrupt;
15use crate::pac::i2s::CONFIG; 16use crate::pac::i2s::{RegisterBlock, CONFIG, PSEL};
16use crate::Peripheral; 17use crate::Peripheral;
17 18
18// TODO: Define those in lib.rs somewhere else 19// TODO: Define those in lib.rs somewhere else
@@ -35,10 +36,39 @@ pub enum Error {
35 // TODO: add other error variants. 36 // TODO: add other error variants.
36} 37}
37 38
39pub const MODE_MASTER_8000: Mode = Mode::Master {
40 freq: MckFreq::_32MDiv125,
41 ratio: Ratio::_32x,
42}; // error = 0
43pub const MODE_MASTER_11025: Mode = Mode::Master {
44 freq: MckFreq::_32MDiv15,
45 ratio: Ratio::_192x,
46}; // error = 86
47pub const MODE_MASTER_16000: Mode = Mode::Master {
48 freq: MckFreq::_32MDiv21,
49 ratio: Ratio::_96x,
50}; // error = 127
51pub const MODE_MASTER_22050: Mode = Mode::Master {
52 freq: MckFreq::_32MDiv15,
53 ratio: Ratio::_96x,
54}; // error = 172
55pub const MODE_MASTER_32000: Mode = Mode::Master {
56 freq: MckFreq::_32MDiv21,
57 ratio: Ratio::_48x,
58}; // error = 254
59pub const MODE_MASTER_44100: Mode = Mode::Master {
60 freq: MckFreq::_32MDiv15,
61 ratio: Ratio::_48x,
62}; // error = 344
63pub const MODE_MASTER_48000: Mode = Mode::Master {
64 freq: MckFreq::_32MDiv21,
65 ratio: Ratio::_32x,
66}; // error = 381
67
38#[derive(Clone)] 68#[derive(Clone)]
39#[non_exhaustive] 69#[non_exhaustive]
40pub struct Config { 70pub struct Config {
41 pub ratio: Ratio, 71 pub mode: Mode,
42 pub swidth: SampleWidth, 72 pub swidth: SampleWidth,
43 pub align: Align, 73 pub align: Align,
44 pub format: Format, 74 pub format: Format,
@@ -48,7 +78,7 @@ pub struct Config {
48impl Default for Config { 78impl Default for Config {
49 fn default() -> Self { 79 fn default() -> Self {
50 Self { 80 Self {
51 ratio: Ratio::_32x, 81 mode: MODE_MASTER_32000,
52 swidth: SampleWidth::_16bit, 82 swidth: SampleWidth::_16bit,
53 align: Align::Left, 83 align: Align::Left,
54 format: Format::I2S, 84 format: Format::I2S,
@@ -57,6 +87,66 @@ impl Default for Config {
57 } 87 }
58} 88}
59 89
90/// I2S Mode
91#[derive(Debug, Eq, PartialEq, Clone, Copy)]
92pub enum Mode {
93 Master { freq: MckFreq, ratio: Ratio },
94 Slave,
95}
96
97impl Mode {
98 pub fn sample_rate(&self) -> Option<u32> {
99 match self {
100 Mode::Master { freq, ratio } => Some(freq.to_frequency() / ratio.to_divisor()),
101 Mode::Slave => None,
102 }
103 }
104}
105
106/// Master clock generator frequency.
107#[derive(Debug, Eq, PartialEq, Clone, Copy)]
108pub enum MckFreq {
109 _32MDiv8,
110 _32MDiv10,
111 _32MDiv11,
112 _32MDiv15,
113 _32MDiv16,
114 _32MDiv21,
115 _32MDiv23,
116 _32MDiv30,
117 _32MDiv31,
118 _32MDiv32,
119 _32MDiv42,
120 _32MDiv63,
121 _32MDiv125,
122}
123
124impl MckFreq {
125 const REGISTER_VALUES: &[u32] = &[
126 0x20000000, 0x18000000, 0x16000000, 0x11000000, 0x10000000, 0x0C000000, 0x0B000000, 0x08800000, 0x08400000,
127 0x08000000, 0x06000000, 0x04100000, 0x020C0000,
128 ];
129
130 const FREQUENCIES: &[u32] = &[
131 4000000, 3200000, 2909090, 2133333, 2000000, 1523809, 1391304, 1066666, 1032258, 1000000, 761904, 507936,
132 256000,
133 ];
134
135 pub fn to_register_value(&self) -> u32 {
136 Self::REGISTER_VALUES[usize::from(*self)]
137 }
138
139 pub fn to_frequency(&self) -> u32 {
140 Self::FREQUENCIES[usize::from(*self)]
141 }
142}
143
144impl From<MckFreq> for usize {
145 fn from(variant: MckFreq) -> Self {
146 variant as _
147 }
148}
149
60/// MCK / LRCK ratio. 150/// MCK / LRCK ratio.
61#[derive(Debug, Eq, PartialEq, Clone, Copy)] 151#[derive(Debug, Eq, PartialEq, Clone, Copy)]
62pub enum Ratio { 152pub enum Ratio {
@@ -71,6 +161,14 @@ pub enum Ratio {
71 _512x, 161 _512x,
72} 162}
73 163
164impl Ratio {
165 const RATIOS: &[u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512];
166
167 pub fn to_divisor(&self) -> u32 {
168 Self::RATIOS[u8::from(*self) as usize]
169 }
170}
171
74impl From<Ratio> for u8 { 172impl From<Ratio> for u8 {
75 fn from(variant: Ratio) -> Self { 173 fn from(variant: Ratio) -> Self {
76 variant as _ 174 variant as _
@@ -136,31 +234,6 @@ impl From<Channels> for u8 {
136 } 234 }
137} 235}
138 236
139/// I2S Mode
140#[derive(Debug, Eq, PartialEq, Clone, Copy)]
141pub enum Mode {
142 Controller,
143 Peripheral,
144}
145
146// /// Master clock generator frequency.
147// #[derive(Debug, Eq, PartialEq, Clone, Copy)]
148// pub enum MckFreq {
149// _32MDiv8 = 0x20000000,
150// _32MDiv10 = 0x18000000,
151// _32MDiv11 = 0x16000000,
152// _32MDiv15 = 0x11000000,
153// _32MDiv16 = 0x10000000,
154// _32MDiv21 = 0x0C000000,
155// _32MDiv23 = 0x0B000000,
156// _32MDiv30 = 0x08800000,
157// _32MDiv31 = 0x08400000,
158// _32MDiv32 = 0x08000000,
159// _32MDiv42 = 0x06000000,
160// _32MDiv63 = 0x04100000,
161// _32MDiv125 = 0x020C0000,
162// }
163
164/// Interface to the UARTE peripheral using EasyDMA to offload the transmission and reception workload. 237/// Interface to the UARTE peripheral using EasyDMA to offload the transmission and reception workload.
165/// 238///
166/// For more details about EasyDMA, consult the module documentation. 239/// For more details about EasyDMA, consult the module documentation.
@@ -185,7 +258,7 @@ impl<'d, T: Instance> I2S<'d, T> {
185 /// Create a new I2S 258 /// Create a new I2S
186 pub fn new( 259 pub fn new(
187 i2s: impl Peripheral<P = T> + 'd, 260 i2s: impl Peripheral<P = T> + 'd,
188 // irq: impl Peripheral<P = T::Interrupt> + 'd, 261 irq: impl Peripheral<P = T::Interrupt> + 'd,
189 mck: impl Peripheral<P = impl GpioPin> + 'd, 262 mck: impl Peripheral<P = impl GpioPin> + 'd,
190 sck: impl Peripheral<P = impl GpioPin> + 'd, 263 sck: impl Peripheral<P = impl GpioPin> + 'd,
191 lrck: impl Peripheral<P = impl GpioPin> + 'd, 264 lrck: impl Peripheral<P = impl GpioPin> + 'd,
@@ -196,7 +269,7 @@ impl<'d, T: Instance> I2S<'d, T> {
196 into_ref!(mck, sck, lrck, sdin, sdout); 269 into_ref!(mck, sck, lrck, sdin, sdout);
197 Self::new_inner( 270 Self::new_inner(
198 i2s, 271 i2s,
199 // irq, 272 irq,
200 mck.map_into(), 273 mck.map_into(),
201 sck.map_into(), 274 sck.map_into(),
202 lrck.map_into(), 275 lrck.map_into(),
@@ -208,7 +281,7 @@ impl<'d, T: Instance> I2S<'d, T> {
208 281
209 fn new_inner( 282 fn new_inner(
210 i2s: impl Peripheral<P = T> + 'd, 283 i2s: impl Peripheral<P = T> + 'd,
211 // irq: impl Peripheral<P = T::Interrupt> + 'd, 284 irq: impl Peripheral<P = T::Interrupt> + 'd,
212 mck: PeripheralRef<'d, AnyPin>, 285 mck: PeripheralRef<'d, AnyPin>,
213 sck: PeripheralRef<'d, AnyPin>, 286 sck: PeripheralRef<'d, AnyPin>,
214 lrck: PeripheralRef<'d, AnyPin>, 287 lrck: PeripheralRef<'d, AnyPin>,
@@ -216,36 +289,12 @@ impl<'d, T: Instance> I2S<'d, T> {
216 sdout: PeripheralRef<'d, AnyPin>, 289 sdout: PeripheralRef<'d, AnyPin>,
217 config: Config, 290 config: Config,
218 ) -> Self { 291 ) -> Self {
219 into_ref!(i2s, /* irq, */ mck, sck, lrck, sdin, sdout); 292 into_ref!(i2s, irq, mck, sck, lrck, sdin, sdout);
220 293
221 let r = T::regs(); 294 let r = T::regs();
222
223 Self::apply_config(&r.config, &config); 295 Self::apply_config(&r.config, &config);
224 296 Self::select_pins(&r.psel, mck, sck, lrck, sdin, sdout);
225 r.psel.mck.write(|w| { 297 Self::setup_interrupt(irq, r);
226 unsafe { w.bits(mck.psel_bits()) };
227 w.connect().connected()
228 });
229
230 r.psel.sck.write(|w| {
231 unsafe { w.bits(sck.psel_bits()) };
232 w.connect().connected()
233 });
234
235 r.psel.lrck.write(|w| {
236 unsafe { w.bits(lrck.psel_bits()) };
237 w.connect().connected()
238 });
239
240 r.psel.sdin.write(|w| {
241 unsafe { w.bits(sdin.psel_bits()) };
242 w.connect().connected()
243 });
244
245 r.psel.sdout.write(|w| {
246 unsafe { w.bits(sdout.psel_bits()) };
247 w.connect().connected()
248 });
249 298
250 r.enable.write(|w| w.enable().enabled()); 299 r.enable.write(|w| w.enable().enabled());
251 300
@@ -322,19 +371,87 @@ impl<'d, T: Instance> I2S<'d, T> {
322 self.input.rx(buffer).await 371 self.input.rx(buffer).await
323 } 372 }
324 373
374 fn on_interrupt(_: *mut ()) {
375 let r = T::regs();
376 let s = T::state();
377
378 if r.events_txptrupd.read().bits() != 0 {
379 s.tx_waker.wake();
380 r.intenclr.write(|w| w.txptrupd().clear());
381 }
382
383 if r.events_rxptrupd.read().bits() != 0 {
384 s.rx_waker.wake();
385 r.intenclr.write(|w| w.rxptrupd().clear());
386 }
387 }
388
325 fn apply_config(c: &CONFIG, config: &Config) { 389 fn apply_config(c: &CONFIG, config: &Config) {
326 // TODO support slave too 390 match config.mode {
327 c.mcken.write(|w| w.mcken().enabled()); 391 Mode::Master { freq, ratio } => {
328 c.mckfreq.write(|w| w.mckfreq()._32mdiv16()); 392 c.mode.write(|w| w.mode().master());
329 c.mode.write(|w| w.mode().master()); 393 c.mcken.write(|w| w.mcken().enabled());
394 c.mckfreq
395 .write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) });
396 c.ratio.write(|w| unsafe { w.ratio().bits(ratio.into()) });
397 }
398 Mode::Slave => {
399 c.mode.write(|w| w.mode().slave());
400 }
401 };
330 402
331 c.ratio.write(|w| unsafe { w.ratio().bits(config.ratio.into()) });
332 c.swidth.write(|w| unsafe { w.swidth().bits(config.swidth.into()) }); 403 c.swidth.write(|w| unsafe { w.swidth().bits(config.swidth.into()) });
333 c.align.write(|w| w.align().bit(config.align.into())); 404 c.align.write(|w| w.align().bit(config.align.into()));
334 c.format.write(|w| w.format().bit(config.format.into())); 405 c.format.write(|w| w.format().bit(config.format.into()));
335 c.channels 406 c.channels
336 .write(|w| unsafe { w.channels().bits(config.channels.into()) }); 407 .write(|w| unsafe { w.channels().bits(config.channels.into()) });
337 } 408 }
409
410 fn select_pins(
411 psel: &PSEL,
412 mck: PeripheralRef<'d, AnyPin>,
413 sck: PeripheralRef<'d, AnyPin>,
414 lrck: PeripheralRef<'d, AnyPin>,
415 sdin: PeripheralRef<'d, AnyPin>,
416 sdout: PeripheralRef<'d, AnyPin>,
417 ) {
418 psel.mck.write(|w| {
419 unsafe { w.bits(mck.psel_bits()) };
420 w.connect().connected()
421 });
422
423 psel.sck.write(|w| {
424 unsafe { w.bits(sck.psel_bits()) };
425 w.connect().connected()
426 });
427
428 psel.lrck.write(|w| {
429 unsafe { w.bits(lrck.psel_bits()) };
430 w.connect().connected()
431 });
432
433 psel.sdin.write(|w| {
434 unsafe { w.bits(sdin.psel_bits()) };
435 w.connect().connected()
436 });
437
438 psel.sdout.write(|w| {
439 unsafe { w.bits(sdout.psel_bits()) };
440 w.connect().connected()
441 });
442 }
443
444 fn setup_interrupt(irq: PeripheralRef<'d, T::Interrupt>, r: &RegisterBlock) {
445 irq.set_handler(Self::on_interrupt);
446 irq.set_priority(Priority::P1); // TODO review priorities
447 irq.unpend();
448 irq.enable();
449
450 r.intenclr.write(|w| w.rxptrupd().clear());
451 r.intenclr.write(|w| w.txptrupd().clear());
452 r.events_rxptrupd.reset();
453 r.events_txptrupd.reset();
454 }
338} 455}
339 456
340impl<'d, T: Instance> I2sOutput<'d, T> { 457impl<'d, T: Instance> I2sOutput<'d, T> {
@@ -360,15 +477,40 @@ impl<'d, T: Instance> I2sOutput<'d, T> {
360 } 477 }
361 478
362 let r = T::regs(); 479 let r = T::regs();
363 let _s = T::state(); 480 let s = T::state();
364 481
365 // TODO we can not progress until the last buffer written in TXD.PTR 482 let drop = OnDrop::new(move || {
366 // has started the transmission. 483 trace!("write drop: stopping");
367 // We can use some sync primitive from `embassy-sync`. 484
485 r.intenclr.write(|w| w.txptrupd().clear());
486 r.events_txptrupd.reset();
487 r.config.txen.write(|w| w.txen().disabled());
488
489 // TX is stopped almost instantly, spinning is fine.
490 while r.events_txptrupd.read().bits() == 0 {}
491 trace!("write drop: stopped");
492 });
368 493
369 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); 494 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
370 r.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); 495 r.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
371 496
497 r.intenset.write(|w| w.txptrupd().set());
498
499 compiler_fence(Ordering::SeqCst);
500
501 poll_fn(|cx| {
502 s.tx_waker.register(cx.waker());
503 if r.events_txptrupd.read().bits() != 0 {
504 Poll::Ready(())
505 } else {
506 Poll::Pending
507 }
508 })
509 .await;
510
511 compiler_fence(Ordering::SeqCst);
512 drop.defuse();
513
372 Ok(()) 514 Ok(())
373 } 515 }
374} 516}
@@ -451,23 +593,19 @@ impl Buffer for &[i32] {
451} 593}
452 594
453pub(crate) mod sealed { 595pub(crate) mod sealed {
454 use core::sync::atomic::AtomicU8;
455
456 use embassy_sync::waitqueue::AtomicWaker; 596 use embassy_sync::waitqueue::AtomicWaker;
457 597
458 //use super::*; 598 //use super::*;
459 599
460 pub struct State { 600 pub struct State {
461 pub input_waker: AtomicWaker, 601 pub rx_waker: AtomicWaker,
462 pub output_waker: AtomicWaker, 602 pub tx_waker: AtomicWaker,
463 pub buffers_refcount: AtomicU8,
464 } 603 }
465 impl State { 604 impl State {
466 pub const fn new() -> Self { 605 pub const fn new() -> Self {
467 Self { 606 Self {
468 input_waker: AtomicWaker::new(), 607 rx_waker: AtomicWaker::new(),
469 output_waker: AtomicWaker::new(), 608 tx_waker: AtomicWaker::new(),
470 buffers_refcount: AtomicU8::new(0),
471 } 609 }
472 } 610 }
473 } 611 }
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index bdb911ecd..dc018e08e 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -74,7 +74,7 @@ pub mod buffered_uarte;
74pub mod gpio; 74pub mod gpio;
75#[cfg(feature = "gpiote")] 75#[cfg(feature = "gpiote")]
76pub mod gpiote; 76pub mod gpiote;
77#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840",))] 77#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
78pub mod i2s; 78pub mod i2s;
79#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 79#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
80pub mod nvmc; 80pub mod nvmc;
diff --git a/examples/nrf/src/bin/i2s.rs b/examples/nrf/src/bin/i2s.rs
index e8ddb4a40..53ccb3b85 100644
--- a/examples/nrf/src/bin/i2s.rs
+++ b/examples/nrf/src/bin/i2s.rs
@@ -4,43 +4,133 @@
4#![no_main] 4#![no_main]
5#![feature(type_alias_impl_trait)] 5#![feature(type_alias_impl_trait)]
6 6
7//use defmt::*; 7use core::f32::consts::PI;
8
9use defmt::{error, info};
8use embassy_executor::Spawner; 10use embassy_executor::Spawner;
9use embassy_nrf::i2s; 11use embassy_nrf::i2s::{MckFreq, Mode, Ratio, MODE_MASTER_16000, MODE_MASTER_8000};
12use embassy_nrf::{i2s, interrupt};
10use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
11 14
12#[repr(align(4))] 15#[repr(align(4))]
13pub struct Aligned<T: ?Sized>(T); 16pub struct AlignedBuffer<T: ?Sized>(T);
17
18impl<T> AsRef<T> for AlignedBuffer<T> {
19 fn as_ref(&self) -> &T {
20 &self.0
21 }
22}
23
24impl<T> AsMut<T> for AlignedBuffer<T> {
25 fn as_mut(&mut self) -> &mut T {
26 &mut self.0
27 }
28}
14 29
15#[embassy_executor::main] 30#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 31async fn main(_spawner: Spawner) {
17 let p = embassy_nrf::init(Default::default()); 32 let p = embassy_nrf::init(Default::default());
18 let config = i2s::Config::default(); 33 let mut config = i2s::Config::default();
34 // config.mode = MODE_MASTER_16000;
35 config.mode = Mode::Master {
36 freq: MckFreq::_32MDiv10,
37 ratio: Ratio::_256x,
38 }; // 12500 Hz
39 let sample_rate = config.mode.sample_rate().expect("I2S Master");
40 let inv_sample_rate = 1.0 / sample_rate as f32;
19 41
20 let mut i2s = i2s::I2S::new(p.I2S, p.P0_28, p.P0_29, p.P0_31, p.P0_11, p.P0_30, config); 42 info!("Sample rate: {}", sample_rate);
21 43
22 let mut signal_buf: Aligned<[i16; 32]> = Aligned([0i16; 32]); 44 let irq = interrupt::take!(I2S);
23 let len = signal_buf.0.len() / 2; 45 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);
24 for x in 0..len { 46
25 signal_buf.0[2 * x] = triangle_wave(x as i32, len, 2048, 0, 1) as i16; 47 const BUF_SAMPLES: usize = 250;
26 signal_buf.0[2 * x + 1] = triangle_wave(x as i32, len, 2048, 0, 1) as i16; 48 const BUF_SIZE: usize = BUF_SAMPLES * 2;
27 } 49 let mut buf = AlignedBuffer([0i16; BUF_SIZE]);
50
51 let mut carrier = SineOsc::new();
52 carrier.set_frequency(300.0, inv_sample_rate);
53
54 let mut modulator = SineOsc::new();
55 modulator.set_frequency(0.01, inv_sample_rate);
56 modulator.set_amplitude(0.2);
28 57
29 i2s.set_tx_enabled(true); 58 i2s.set_tx_enabled(true);
30 i2s.start(); 59 i2s.start();
31 60
32 loop { 61 loop {
33 match i2s.tx(signal_buf.0.as_slice()).await { 62 for sample in buf.as_mut().chunks_mut(2) {
34 Ok(_) => todo!(), 63 let signal = carrier.generate();
35 Err(_) => todo!(), 64 // let modulation = bipolar_to_unipolar(modulator.generate());
36 }; 65 // carrier.set_frequency(200.0 + 100.0 * modulation, inv_sample_rate);
66 // carrier.set_amplitude((modulation);
67 let value = (i16::MAX as f32 * signal) as i16;
68 sample[0] = value;
69 sample[1] = value;
70 // info!("{}", signal);
71 }
72
73 if let Err(err) = i2s.tx(buf.as_ref().as_slice()).await {
74 error!("{}", err);
75 }
76 }
77}
78
79struct SineOsc {
80 amplitude: f32,
81 modulo: f32,
82 phase_inc: f32,
83}
84
85impl SineOsc {
86 const B: f32 = 4.0 / PI;
87 const C: f32 = -4.0 / (PI * PI);
88 const P: f32 = 0.225;
89
90 pub fn new() -> Self {
91 Self {
92 amplitude: 1.0,
93 modulo: 0.0,
94 phase_inc: 0.0,
95 }
96 }
97
98 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
99 self.phase_inc = freq * inv_sample_rate;
100 }
101
102 pub fn set_amplitude(&mut self, amplitude: f32) {
103 self.amplitude = amplitude;
104 }
105
106 pub fn generate(&mut self) -> f32 {
107 let signal = self.parabolic_sin(self.modulo);
108 self.modulo += self.phase_inc;
109 if self.modulo < 0.0 {
110 self.modulo += 1.0;
111 } else if self.modulo > 1.0 {
112 self.modulo -= 1.0;
113 }
114 signal * self.amplitude
115 }
116
117 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
118 let angle = PI - modulo * 2.0 * PI;
119 let y = Self::B * angle + Self::C * angle * abs(angle);
120 Self::P * (y * abs(y) - y) + y
121 }
122}
123
124#[inline]
125fn abs(value: f32) -> f32 {
126 if value < 0.0 {
127 -value
128 } else {
129 value
37 } 130 }
38} 131}
39 132
40fn triangle_wave(x: i32, length: usize, amplitude: i32, phase: i32, periods: i32) -> i32 { 133#[inline]
41 let length = length as i32; 134fn bipolar_to_unipolar(value: f32) -> f32 {
42 amplitude 135 (value + 1.0) / 2.0
43 - ((2 * periods * (x + phase + length / (4 * periods)) * amplitude / length) % (2 * amplitude) - amplitude)
44 .abs()
45 - amplitude / 2
46} 136}