diff options
Diffstat (limited to 'audio/src/program.rs')
| -rw-r--r-- | audio/src/program.rs | 138 |
1 files changed, 104 insertions, 34 deletions
diff --git a/audio/src/program.rs b/audio/src/program.rs index d8ece2c..e5d31bb 100644 --- a/audio/src/program.rs +++ b/audio/src/program.rs @@ -1,6 +1,7 @@ +use std::fmt; + use crate::{ - Channels, - channel::{Channel, DutyCycle}, + channel::{ChannelKind, Channels}, parse, }; @@ -11,18 +12,43 @@ pub enum ChanSpec { Triangle, Noise, } +impl fmt::Display for ChanSpec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::PulseA => f.write_str("pulsea"), + Self::PulseB => f.write_str("pulseb"), + Self::Triangle => f.write_str("triangle"), + Self::Noise => f.write_str("noise"), + } + } +} #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Instruction { - Pause, - PauseLen(u32), - Jump(usize), + Pause(u16), + PauseLen(u16), + Jump(u16), SetVolume(ChanSpec, u8), SetPitch(ChanSpec, u8), - SetPulseDutyA(DutyCycle), - SetPulseDutyB(DutyCycle), + SetPulseDutyA(u8), + SetPulseDutyB(u8), SetNoiseMode(bool), } +impl fmt::Display for Instruction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Pause(len) => write!(f, "pause {len}"), + Self::PauseLen(len) => write!(f, "pause_len {len}"), + Self::Jump(pc) => write!(f, "jump {pc}"), + Self::SetVolume(chan, v) => write!(f, "{chan} volume {v}"), + Self::SetPitch(chan, p) => write!(f, "{chan} pitch {p}"), + Self::SetPulseDutyA(dc) => write!(f, "{} duty_cycle {dc}", ChanSpec::PulseA), + Self::SetPulseDutyB(dc) => write!(f, "{} duty_cycle {dc}", ChanSpec::PulseB), + Self::SetNoiseMode(mode) => write!(f, "{} mode {mode}", ChanSpec::Noise), + } + } +} +use Instruction as I; fn map_pitch(pitch: u8) -> f32 { const HALF_STEP: f32 = 1.059_463_1; @@ -41,8 +67,8 @@ const fn map_volume(volume: u8) -> f32 { pub struct Program { ins: Vec<Instruction>, pc: usize, - pause_cnt: u32, - pause_len: u32, + pause_cnt: usize, + pause_len: usize, looping: bool, playing: bool, } @@ -68,6 +94,8 @@ impl Program { let mut l = 0; let mut r = 0; + let mut l_pause = 0; + let mut r_pause = 0; let l_ins = self.ins; let r_ins = other.ins; @@ -77,27 +105,52 @@ impl Program { break; } - let mut has_pause = false; while l < l_ins.len() { + if l_pause > 0 { + break; + } let ins = l_ins[l]; l += 1; - if matches!(ins, Instruction::Pause) { - has_pause = true; + if let I::Pause(cnt) = ins { + l_pause = cnt; break; } res.push(ins); } + while r < r_ins.len() { + if r_pause > 0 { + break; + } let ins = r_ins[r]; r += 1; - if matches!(ins, Instruction::Pause) { - has_pause = true; + if let I::Pause(cnt) = ins { + r_pause = cnt; break; } res.push(ins); } - if has_pause { - res.push(Instruction::Pause); + + if l_pause > 0 { + if r_pause > 0 && l_pause >= r_pause { + l_pause -= r_pause; + res.push(I::Pause(r_pause)); + r_pause = 0; + } else if r_pause == 0 { + res.push(I::Pause(l_pause)); + l_pause = 0; + } + } + + if r_pause > 0 { + if l_pause > 0 && r_pause >= l_pause { + r_pause -= l_pause; + res.push(I::Pause(l_pause)); + l_pause = 0; + } else if l_pause == 0 { + res.push(I::Pause(r_pause)); + r_pause = 0; + } } } @@ -107,24 +160,24 @@ impl Program { fn exec_ins(&mut self, channels: &mut Channels, ins: Instruction) { use Instruction as I; match ins { - I::Pause => { - self.pause_cnt = self.pause_len; + I::Pause(cnt) => { + self.pause_cnt = self.pause_len * (cnt as usize); } I::PauseLen(pause_len) => { - self.pause_len = pause_len; + self.pause_len = pause_len as usize; } I::Jump(pc) => { - self.pc = pc; + self.pc = pc as usize; } I::SetVolume(chan_spec, volume) => { // set the volume (amplitude) on a given channel use ChanSpec as C; let v = map_volume(volume); match chan_spec { - C::PulseA => channels.pulse_a.set_volume(v), - C::PulseB => channels.pulse_b.set_volume(v), - C::Triangle => channels.triangle.set_volume(v), - C::Noise => channels.noise.set_volume(v), + C::PulseA => channels.pulse_a.volume = v, + C::PulseB => channels.pulse_b.volume = v, + C::Triangle => channels.triangle.volume = v, + C::Noise => channels.noise.volume = v, } } I::SetPitch(chan_spec, pitch) => { @@ -132,20 +185,26 @@ impl Program { use ChanSpec as C; let p = map_pitch(pitch); match chan_spec { - C::PulseA => channels.pulse_a.set_pitch(p), - C::PulseB => channels.pulse_b.set_pitch(p), - C::Triangle => channels.triangle.set_pitch(p), - C::Noise => channels.noise.set_pitch(p), + C::PulseA => channels.pulse_a.pitch = p, + C::PulseB => channels.pulse_b.pitch = p, + C::Triangle => channels.triangle.pitch = p, + C::Noise => channels.noise.pitch = p, } } - I::SetPulseDutyA(duty_cycle) => { - channels.pulse_a.set_duty(duty_cycle); + I::SetPulseDutyA(dc) => { + if let ChannelKind::Pulse { duty_cycle } = &mut channels.pulse_a.kind { + *duty_cycle = dc; + } } - I::SetPulseDutyB(duty_cycle) => { - channels.pulse_b.set_duty(duty_cycle); + I::SetPulseDutyB(dc) => { + if let ChannelKind::Pulse { duty_cycle } = &mut channels.pulse_b.kind { + *duty_cycle = dc; + } } - I::SetNoiseMode(mode) => { - channels.noise.set_mode(mode); + I::SetNoiseMode(m) => { + if let ChannelKind::Noise { mode, .. } = &mut channels.noise.kind { + *mode = m; + } } } } @@ -192,3 +251,14 @@ impl Program { self.looping = looping; } } +impl fmt::Display for Program { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for (idx, ins) in self.ins.iter().enumerate() { + if idx != 0 { + writeln!(f)?; + } + write!(f, "{ins}")?; + } + Ok(()) + } +} |