From acdac24d1aea778860f37515dde6c6c9c8ffcefe Mon Sep 17 00:00:00 2001 From: breel Date: Wed, 11 Mar 2026 13:33:56 -0600 Subject: [PATCH] seq maintains state, pop returns changed, none is stop singing --- src/seq.rs | 42 ++++++++----- src/syn.rs | 169 ++++++++++++++++++++++++++--------------------------- 2 files changed, 110 insertions(+), 101 deletions(-) diff --git a/src/seq.rs b/src/seq.rs index e1a652d..451c4cb 100644 --- a/src/seq.rs +++ b/src/seq.rs @@ -4,14 +4,12 @@ use crate::syn; pub struct SynSeq { seq: Seq, syn: syn::Syn, - state: Option, } pub fn new_syn(syn: syn::Syn) -> SynSeq { SynSeq{ seq: new(), syn: syn, - state: None, } } @@ -21,13 +19,13 @@ impl SynSeq { } pub fn render(&mut self, left: &mut [f32], right: &mut [f32]) { - let state = self.state.clone(); match self.seq.pop() { - Some(tone) if (state.is_none() || tone != state.unwrap()) => { - self.syn.set(tone.clone()); - self.state = Some(tone); + (Some(tone), changed) if changed => { + self.syn.set(0, Some(tone.clone())); + }, + (None, changed) if changed => { + self.syn.set(0, None); }, - None => { self.state = None; }, _ => {}, }; self.syn.render(left, right); @@ -41,6 +39,7 @@ impl SynSeq { #[derive(PartialEq)] pub struct Seq { beats: Vec<(i32, tone::Tone)>, + state: Option, } fn new() -> Seq { @@ -51,10 +50,20 @@ impl Seq { fn new() -> Seq { Seq{ beats: vec![], + state: None, } } - fn pop(&mut self) -> Option { + fn pop(&mut self) -> (Option, bool) { + let state_before = self.state.clone(); + let tone_after = self._pop(); + if state_before != tone_after { + self.state = tone_after.clone(); + } + (tone_after, self.state != state_before) + } + + fn _pop(&mut self) -> Option { match self.beats.len() { 0 => None, _ => match self.beats[0].0 { @@ -105,14 +114,15 @@ mod test { assert_eq!(seq.beats[2], (1 as i32, tone::new("g"))); assert_eq!(seq.beats[3], (2 as i32, tone::new("e"))); - assert_eq!(seq.pop(), Some(tone::new("c"))); - for _ in 0..4 { - assert_eq!(seq.pop(), Some(tone::new("d"))); + assert_eq!(seq.pop(), (Some(tone::new("c")), true)); + assert_eq!(seq.pop(), (Some(tone::new("d")), true)); + for _ in 1..4 { + assert_eq!(seq.pop(), (Some(tone::new("d")), false)); } - assert_eq!(seq.pop(), Some(tone::new("g"))); - for _ in 0..2 { - assert_eq!(seq.pop(), Some(tone::new("e"))); - } - assert_eq!(seq.pop(), None); + assert_eq!(seq.pop(), (Some(tone::new("g")), true)); + assert_eq!(seq.pop(), (Some(tone::new("e")), true)); + assert_eq!(seq.pop(), (Some(tone::new("e")), false)); + assert_eq!(seq.pop(), (None, true)); + assert_eq!(seq.pop(), (None, false)); } } diff --git a/src/syn.rs b/src/syn.rs index 96d6044..dd532b0 100644 --- a/src/syn.rs +++ b/src/syn.rs @@ -6,88 +6,87 @@ use std::sync::Arc; use crate::tone; pub enum Syn { - Real(Synthesizer), - Text{ - m: std::collections::HashMap>, - i: u32, - }, + Real(Synthesizer), + Text{ + m: std::collections::HashMap>, + i: u32, + }, } impl Syn { - pub fn new(debug: bool, sound_font: String, sample_rate: usize) -> Syn { - match debug { - false => Syn::new_real(sound_font, sample_rate), - true => Syn::Text{m: std::collections::HashMap::new(), i: 0}, - } - } + pub fn new(debug: bool, sound_font: String, sample_rate: usize) -> Syn { + match debug { + false => Syn::new_real(sound_font, sample_rate), + true => Syn::Text{m: std::collections::HashMap::new(), i: 0}, + } + } - fn new_real(sound_font: String, sample_rate: usize) -> Syn { - let mut sf2 = std::fs::File::open(sound_font).unwrap(); - let sound_font = Arc::new(SoundFont::new(&mut sf2).unwrap()); + fn new_real(sound_font: String, sample_rate: usize) -> Syn { + let mut sf2 = std::fs::File::open(sound_font).unwrap(); + let sound_font = Arc::new(SoundFont::new(&mut sf2).unwrap()); - let settings = SynthesizerSettings::new(sample_rate as i32); + let settings = SynthesizerSettings::new(sample_rate as i32); - let synthesizer = Synthesizer::new(&sound_font, &settings).unwrap(); - Syn::Real(synthesizer) - } + let synthesizer = Synthesizer::new(&sound_font, &settings).unwrap(); + Syn::Real(synthesizer) + } - pub fn set(&mut self, b: tone::Tone) { - let a = 0 as i32; - match self { - // channel=[0..16) - // velocity=[0..128) - Syn::Real(syn) => { - syn.note_off_all_channel(a, false); - }, - Syn::Text{m, ..} => { - m.clear(); - }, - }; - self.tone_on(b); - } + pub fn set(&mut self, ch: i32, b: Option) { + match self { + // channel=[0..16) + // velocity=[0..128) + Syn::Real(syn) => { + syn.note_off_all_channel(ch, false); + }, + Syn::Text{m, ..} => { + m.remove(&ch); + }, + }; + if let Some(tone) = b { + self.tone_on(ch, tone); + }; + } - fn tone_on(&mut self, b: tone::Tone) { - let a = 0 as i32; - match self { - // channel=[0..16) - // velocity=[0..128) - Syn::Real(syn) => syn.note_on(a, b.i32(), 127), - Syn::Text{m, ..} => { - match m.get_mut(&a) { - Some(m2) => { m2.insert(b.i32(), 127); }, - None => { - let mut m2 = std::collections::HashMap::new(); - m2.insert(b.i32(), 127); - m.insert(a, m2); - }, - }; - }, - }; - } + fn tone_on(&mut self, ch: i32, b: tone::Tone) { + match self { + // channel=[0..16) + // velocity=[0..128) + Syn::Real(syn) => syn.note_on(ch, b.i32(), 127), + Syn::Text{m, ..} => { + match m.get_mut(&ch) { + Some(m2) => { m2.insert(b.i32(), 127); }, + None => { + let mut m2 = std::collections::HashMap::new(); + m2.insert(b.i32(), 127); + m.insert(ch, m2); + }, + }; + }, + }; + } - fn tone_off(&mut self, b: tone::Tone) { - let a = 0 as i32; - match self { - Syn::Real(syn) => syn.note_off(a, b.i32()), - Syn::Text{m, ..} => { - match m.get_mut(&a) { - Some(m) => { m.remove(&b.i32()); }, - None => {}, - }; + fn tone_off(&mut self, ch: i32, b: tone::Tone) { + match self { + Syn::Real(syn) => syn.note_off(ch, b.i32()), + Syn::Text{m, ..} => { + match m.get_mut(&ch) { + Some(m) => { m.remove(&b.i32()); }, + None => {}, + }; - }, - }; - } + }, + }; + } - pub fn render(&mut self, a: &mut [f32], b: &mut [f32]) { - match self { - Syn::Real(syn) => syn.render(a, b), - Syn::Text{m, i} => { - eprintln!("{} | render[{}]({:?})", chrono::prelude::Utc::now(), i, m); - *i += 1; - }, - }; - } + pub fn render(&mut self, a: &mut [f32], b: &mut [f32]) { + match self { + Syn::Real(syn) => syn.render(a, b), + Syn::Text{m, i} => { + eprintln!("{} | render[{}]({:?})", chrono::prelude::Utc::now(), i, m); + *i += 1; + }, + }; + } } #[cfg(test)] @@ -96,29 +95,29 @@ mod test { #[test] fn test_new_real() { - let mut syn = Syn::new(false, "super_small_font.sf2".to_string(), 44100); + let mut syn = Syn::new(false, "super_small_font.sf2".to_string(), 44100); - syn.tone_on(tone::new("c")); - syn.tone_on(tone::new("d")); + syn.tone_on(0, tone::new("c")); + syn.tone_on(0, tone::new("d")); - syn.tone_off(tone::new("d")); + syn.tone_off(0, tone::new("d")); - let mut buffer1 = Vec::::new(); - let mut buffer2 = Vec::::new(); - syn.render(&mut buffer1, &mut buffer2); + let mut buffer1 = Vec::::new(); + let mut buffer2 = Vec::::new(); + syn.render(&mut buffer1, &mut buffer2); } #[test] fn test_text() { - let mut syn = Syn::new(true, ".sf2".to_string(), 1); + let mut syn = Syn::new(true, ".sf2".to_string(), 1); - syn.tone_on(tone::new("c")); - syn.tone_on(tone::new("d")); + syn.tone_on(0, tone::new("c")); + syn.tone_on(0, tone::new("d")); - syn.tone_off(tone::new("d")); + syn.tone_off(0, tone::new("d")); - let mut buffer1 = Vec::::new(); - let mut buffer2 = Vec::::new(); - syn.render(&mut buffer1, &mut buffer2); + let mut buffer1 = Vec::::new(); + let mut buffer2 = Vec::::new(); + syn.render(&mut buffer1, &mut buffer2); } }