|
| 1 | +//! |
| 2 | +//! signal.rs |
| 3 | +//! |
| 4 | +//! Created by Mitchell Nordine at 11:48PM on December 06, 2014. |
| 5 | +//! |
| 6 | +//! |
| 7 | +
|
| 8 | +use std::num::{Float, FloatMath}; |
| 9 | +use std::rand; |
| 10 | +use math; |
| 11 | + |
| 12 | +/// Signal generic struct for simplifying dsp signal generation. |
| 13 | +/// Signal should be able to handle any floating point primitive. |
| 14 | +#[deriving(Clone, Show, Encodable, Decodable)] |
| 15 | +pub struct Signal<F> { |
| 16 | + /// The main value. If Signal were to be plotted on a cartesian |
| 17 | + /// plane, this value would be 'x' for which we will solve 'y'. |
| 18 | + pub val: F, |
| 19 | + /// Optional: The 'x' value of the second point |
| 20 | + /// (from which we calc our range and gradient) |
| 21 | + x: F, |
| 22 | + /// Optional: The 'y' value of the second point |
| 23 | + /// (from which we calc our range and gradient) |
| 24 | + y: F, |
| 25 | + /// The calculated gradient. |
| 26 | + grad: F, |
| 27 | + /// Depth of the bezier curve. |
| 28 | + pub bez_depth: F, |
| 29 | + /// Frequency of the signal. |
| 30 | + pub freq: F, |
| 31 | + /// Amplitude of the signal. |
| 32 | + pub amp: F |
| 33 | +} |
| 34 | + |
| 35 | +/// Times two pi for most methods in 'Signal' implementations. |
| 36 | +fn times_two_pi<F>(f: F) -> F where F: FloatMath + FromPrimitive { |
| 37 | + use std::f32::consts::PI_2; |
| 38 | + f * FromPrimitive::from_f32(PI_2).unwrap() |
| 39 | +} |
| 40 | + |
| 41 | +/// Get random() mapped from -1.0 to 1.0 for 'Signal::get_noise'. |
| 42 | +fn get_rand_signal<F: FloatMath + rand::Rand + FromPrimitive>() -> F { |
| 43 | + let r: F = rand::random(); |
| 44 | + r * FromPrimitive::from_f32(2.0).unwrap() - FromPrimitive::from_f32(1.0).unwrap() |
| 45 | +} |
| 46 | + |
| 47 | +impl<F: FloatMath + rand::Rand + FromPrimitive + ToPrimitive> Signal<F> { |
| 48 | + |
| 49 | + /// Constructor for Signal |
| 50 | + #[inline] |
| 51 | + pub fn new(val: F) -> Signal<F> { |
| 52 | + Signal { |
| 53 | + val: val, |
| 54 | + x: Float::one(), |
| 55 | + y: Float::zero(), |
| 56 | + grad: Float::zero(), |
| 57 | + bez_depth: Float::zero(), |
| 58 | + freq: Float::one(), |
| 59 | + amp: Float::one(), |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + /// Set value for which you will return signal (get_sin/cos/sqr/saw) etc... |
| 64 | + #[inline] |
| 65 | + pub fn set_val(&mut self, val: F) { |
| 66 | + self.val = val; |
| 67 | + } |
| 68 | + |
| 69 | + /// If you woudl like to return the signal value on a slope, set gradient here. |
| 70 | + #[inline] |
| 71 | + pub fn set_gradient(&mut self, x: F, y: F) { |
| 72 | + self.x = x; |
| 73 | + self.y = y; |
| 74 | + self.grad = x / y; |
| 75 | + } |
| 76 | + |
| 77 | + /// Set frequency of signal. |
| 78 | + #[inline] |
| 79 | + pub fn set_freq(&mut self, freq: F) { |
| 80 | + self.freq = freq; |
| 81 | + } |
| 82 | + |
| 83 | + /// Set amplitude of signal. |
| 84 | + #[inline] |
| 85 | + pub fn set_amp(&mut self, amp: F) { |
| 86 | + self.amp = amp; |
| 87 | + } |
| 88 | + |
| 89 | + /// Set depth of bezier curve. Defaults to 0. |
| 90 | + #[inline] |
| 91 | + pub fn set_bez_depth(&mut self, bez_depth: F) { |
| 92 | + self.bez_depth = bez_depth; |
| 93 | + } |
| 94 | + |
| 95 | + /// Helper function for 'get_bezier'. |
| 96 | + #[inline] |
| 97 | + fn get_bezier_pt(na: F, nb: F, perc: F) -> F { |
| 98 | + let diff: F = nb - na; |
| 99 | + diff * perc + na |
| 100 | + } |
| 101 | + |
| 102 | + /// Helper function for 'get_bezier'. |
| 103 | + #[inline] |
| 104 | + fn get_y1(y: F, one: F) -> F { |
| 105 | + y / (one + one) |
| 106 | + } |
| 107 | + |
| 108 | + /// Get signal with bezier curve. |
| 109 | + #[inline] |
| 110 | + pub fn get_bezier(&self) -> F { |
| 111 | + let y1: F = Signal::get_y1(self.y, Float::one()); |
| 112 | + let y2: F = y1 + self.bez_depth * y1; |
| 113 | + let relative_val: F = self.val / self.x; |
| 114 | + let ya: F = Signal::get_bezier_pt(Float::zero(), y2, relative_val); |
| 115 | + let yb: F = Signal::get_bezier_pt(y2, self.y, relative_val); |
| 116 | + Signal::get_bezier_pt(ya, yb, relative_val) |
| 117 | + } |
| 118 | + |
| 119 | + /// Get oscillator with amplitude and bezier. |
| 120 | + #[inline] |
| 121 | + pub fn get_result(&self, val: F) -> F { |
| 122 | + self.amp * val + self.get_bezier() |
| 123 | + } |
| 124 | + |
| 125 | + /// Get sine wave signal result at val. |
| 126 | + #[inline] |
| 127 | + pub fn get_sin(&self) -> F { |
| 128 | + self.get_result((times_two_pi(self.val) * self.freq / self.x).sin()) |
| 129 | + } |
| 130 | + |
| 131 | + /// Get cosine wave signal result at val. |
| 132 | + #[inline] |
| 133 | + pub fn get_cos(&self) -> F { |
| 134 | + self.get_result((times_two_pi(self.val) * self.freq / self.x).cos()) |
| 135 | + } |
| 136 | + |
| 137 | + /// Get saw wave signal result at val. |
| 138 | + #[inline] |
| 139 | + pub fn get_saw(&self) -> F { |
| 140 | + self.get_result((math::fmod((self.val * self.freq / self.x), Float::one())) * FromPrimitive::from_int(-2).unwrap() + FromPrimitive::from_int(1).unwrap()) |
| 141 | + } |
| 142 | + |
| 143 | + /// Get square wave signal result at val. |
| 144 | + #[inline] |
| 145 | + pub fn get_sqr(&self) -> F { |
| 146 | + self.get_result((times_two_pi(self.val) * self.freq / self.x).sin().signum()) |
| 147 | + } |
| 148 | + |
| 149 | + /// Get noise signal result at val. |
| 150 | + #[inline] |
| 151 | + pub fn get_noise(&self) -> F { |
| 152 | + self.get_result(get_rand_signal()) |
| 153 | + } |
| 154 | + |
| 155 | + /// Ported implementation of `_slang_library_noise1()` |
| 156 | + /// for our generic noise walk! |
| 157 | + #[inline] |
| 158 | + pub fn get_noise_walk(&self) -> F { |
| 159 | + let uno: F = Float::one(); |
| 160 | + let i0: i64 = math::fast_floor(self.val); |
| 161 | + let i1: i64 = i0 + 1; |
| 162 | + let x0: F = self.val - FromPrimitive::from_i64(i0).unwrap(); |
| 163 | + let x1: F = x0 - uno; |
| 164 | + let x12d: F = x1 * x1; |
| 165 | + let x02d: F = x0 * x0; |
| 166 | + let t1: F = uno - x12d; |
| 167 | + let t0: F = uno - x02d; |
| 168 | + let t0a: F = t0 * t0; |
| 169 | + let g1: f32 = math::grad1( |
| 170 | + math::get_perm_val((i0 & 0xff) as uint) as i64, x0.to_f32().unwrap()); |
| 171 | + let n0: F = t0a * t0a * FromPrimitive::from_f32(g1).unwrap(); |
| 172 | + let t1a: F = t1 * t1; |
| 173 | + let g2: f32 = math::grad1( |
| 174 | + math::get_perm_val((i1 & 0xff) as uint) as i64, x1.to_f32().unwrap()); |
| 175 | + let n1: F = t1a * t1a * FromPrimitive::from_f32(g2).unwrap(); |
| 176 | + let n0pn1: F = n0 + n1; |
| 177 | + let quarter: F = FromPrimitive::from_f32(0.25f32).unwrap(); |
| 178 | + quarter * n0pn1 |
| 179 | + } |
| 180 | + |
| 181 | +} |
| 182 | + |
0 commit comments