Skip to main content

oscen/
sequencer.rs

1use super::signal::*;
2use crate::{as_any_mut, std_signal};
3use pitch_calc::{hz_from_letter_octave, Letter, LetterOctave, Octave};
4use std::any::Any;
5use rand::thread_rng;
6use rand::seq::SliceRandom;
7
8fn tick(clock: Real, seq_len: usize, bps: Real, sample_rate: Real) -> Real {
9    let n = seq_len as Real;
10    (clock + 1.0) % (sample_rate / bps * n)
11}
12
13fn idx(clock: Real, bps: Real, sample_rate: Real) -> usize {
14    (clock / sample_rate * bps) as usize
15}
16
17#[derive(Clone)]
18pub struct Note {
19    pitch: LetterOctave,
20    gate: bool,
21}
22
23impl Note {
24    pub fn new(letter: Letter, octave: Octave, gate: bool) -> Self {
25        Self {
26            pitch: LetterOctave(letter, octave),
27            gate,
28        }
29    }
30}
31
32#[derive(Clone)]
33pub struct Sequencer {
34    sequence: Vec<Note>,
35    bpm: In, // beats prer minute
36    clock: Real,
37}
38
39impl Sequencer {
40    pub fn new() -> Self {
41        Sequencer {
42            sequence: vec![],
43            bpm: 120.into(),
44            clock: 0.0,
45        }
46    }
47
48    pub fn sequence(&mut self, arg: Vec<Note>) -> &mut Self {
49        self.sequence = arg;
50        self
51    }
52
53    pub fn bpm<T: Into<In>>(&mut self, arg: T) -> &mut Self {
54        self.bpm = arg.into();
55        self
56    }
57}
58
59impl Builder for Sequencer {}
60
61#[derive(Clone)]
62pub struct PitchSeq {
63    tag: Tag,
64    seq: Sequencer,
65}
66
67impl PitchSeq {
68    pub fn new(seq: Sequencer) -> Self {
69        Self { tag: mk_tag(), seq }
70    }
71}
72
73impl Builder for PitchSeq {}
74
75impl Signal for PitchSeq {
76    std_signal!();
77    fn signal(&mut self, rack: &Rack, sample_rate: Real) -> Real {
78        let bps = In::val(&rack, self.seq.bpm) / 60.0;
79        let idx = idx(self.seq.clock, bps, sample_rate);
80        if idx == 0 {
81            let mut rng = thread_rng();
82            self.seq.sequence.shuffle(&mut rng);
83        }
84        self.seq.clock = tick(self.seq.clock, self.seq.sequence.len(), bps, sample_rate);
85        let LetterOctave(letter, octave) = self.seq.sequence[idx].pitch;
86        hz_from_letter_octave(letter, octave) as Real
87    }
88}
89
90#[derive(Clone)]
91pub struct GateSeq {
92    tag: Tag,
93    seq: Sequencer,
94}
95
96impl GateSeq {
97    pub fn new(seq: Sequencer) -> Self {
98        Self { tag: mk_tag(), seq }
99    }
100}
101
102impl Builder for GateSeq {}
103
104impl Signal for GateSeq {
105    std_signal!();
106    fn signal(&mut self, rack: &Rack, sample_rate: Real) -> Real {
107        let bps = In::val(&rack, self.seq.bpm) / 60.0;
108        let idx = idx(self.seq.clock, bps, sample_rate);
109        self.seq.clock = tick(self.seq.clock, self.seq.sequence.len(), bps, sample_rate);
110        self.seq.sequence[idx].gate as usize as Real
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117    use crate::utils::signals;
118    use pitch_calc::Letter;
119
120    #[test]
121    fn pitch_seq() {
122        let notes: Vec<Note> = vec![
123            Note::new(Letter::A, 2, true),
124            Note::new(Letter::A, 3, false),
125            Note::new(Letter::A, 4, true),
126            Note::new(Letter::A, 5, false),
127        ];
128        let seq: Sequencer = Sequencer::new().sequence(notes).build();
129        let mut ps = PitchSeq::new(seq);
130        let sigs = signals(&mut ps, 0, 16, 4.0);
131        let s0 = sigs[0].1.round();
132        let s1 = sigs[1].1.round();
133        let s2 = sigs[2].1.round();
134        let s14 = sigs[14].1.round();
135
136        assert_eq!(s0, 110.0, "0 - Expected 110 actual: {}", s0);
137        assert_eq!(s1, 110.0, "1 - Expected 110 actual: {}", s1);
138        assert_eq!(s2, 220.0, "2 - Expected 220 actual: {}", s2);
139        assert_eq!(s14, 880.0, "14 - Expected 880 actual: {}", s14);
140    }
141
142    #[test]
143    fn gate_seq() {
144        let notes: Vec<Note> = vec![
145            Note::new(Letter::A, 2, true),
146            Note::new(Letter::A, 3, false),
147            Note::new(Letter::A, 4, true),
148            Note::new(Letter::A, 5, false),
149        ];
150        let seq: Sequencer = Sequencer::new().sequence(notes).build();
151        let mut ps = GateSeq::new(seq);
152        let sigs = signals(&mut ps, 0, 16, 4.0);
153        let s0 = sigs[0].1;
154        let s1 = sigs[1].1;
155        let s2 = sigs[2].1;
156        let s14 = sigs[14].1;
157
158        assert_eq!(s0, 1.0, "0 - Expected true actual: {}", s0);
159        assert_eq!(s1, 1.0, "1 - Expected true actual: {}", s1);
160        assert_eq!(s2, 0.0, "2 - Expected false actual: {}", s2);
161        assert_eq!(s14, 0.0, "14 - Expected true actual: {}", s14);
162    }
163}