twang/osc/
triangle.rs

1// Copyright © 2018-2022 The Twang Contributors.
2//
3// Licensed under any of:
4// - Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
5// - Boost Software License, Version 1.0 (https://www.boost.org/LICENSE_1_0.txt)
6// - MIT License (https://mit-license.org/)
7// At your choosing (See accompanying files LICENSE_APACHE_2_0.txt,
8// LICENSE_MIT.txt and LICENSE_BOOST_1_0.txt).
9
10#[cfg(not(test))]
11use crate::math::Libm;
12
13use fon::chan::Ch32;
14
15/// Triangle wave generator.
16#[derive(Default, Clone, Copy, Debug)]
17pub struct Triangle(f32);
18
19impl Triangle {
20    /// Create a new sine wave generator.
21    #[inline(always)]
22    pub fn new() -> Self {
23        Self::default()
24    }
25
26    /// Get the next sample from the oscillator without progressing oscillator.
27    #[inline(always)]
28    pub fn peek(&mut self) -> Ch32 {
29        (((1.0 - self.0).abs() - 0.5) * 2.0).into()
30    }
31
32    /// Get the next sample from this oscillator.
33    #[inline(always)]
34    pub fn step(&mut self, hz: f32) -> Ch32 {
35        let out = self.peek();
36        self.0 = (self.0 + 2.0 * super::SAMPLE_PERIOD * hz) % 2.0;
37        out
38    }
39
40    /// Get the phase-shifted sample from this oscillator.
41    #[inline(always)]
42    pub fn phase(&mut self, hz: f32, shift: Ch32) -> Ch32 {
43        let original = self.0;
44        let shift = if f32::from(shift) < 0.0 {
45            1.0 + f32::from(shift)
46        } else {
47            f32::from(shift)
48        };
49        self.0 = (original + 2.0 * (super::SAMPLE_PERIOD * hz + shift)) % 2.0;
50        let out = self.peek();
51        self.0 = (original + 2.0 * super::SAMPLE_PERIOD * hz) % 2.0;
52        out
53    }
54
55    /// Phase shift this oscillator.
56    #[inline(always)]
57    pub fn shift(&mut self, shift: Ch32) {
58        let shift = if f32::from(shift) < 0.0 {
59            1.0 + f32::from(shift)
60        } else {
61            f32::from(shift)
62        };
63        self.0 = (self.0 + 2.0 * shift) % 2.0;
64    }
65}