diff options
Diffstat (limited to 'audio/src/program.rs')
| -rw-r--r-- | audio/src/program.rs | 160 |
1 files changed, 74 insertions, 86 deletions
diff --git a/audio/src/program.rs b/audio/src/program.rs index e5d31bb..c6f048d 100644 --- a/audio/src/program.rs +++ b/audio/src/program.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::{fmt, rc::Rc}; use crate::{ channel::{ChannelKind, Channels}, @@ -50,48 +50,19 @@ impl fmt::Display for Instruction { } use Instruction as I; -fn map_pitch(pitch: u8) -> f32 { - const HALF_STEP: f32 = 1.059_463_1; - HALF_STEP.powf(pitch as f32 - 128.0) +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Track { + pub ins: Rc<Vec<Instruction>>, + pub looping: bool, } - -const fn map_volume(volume: u8) -> f32 { - if volume > 100 { - 1.0 - } else { - (volume as f32) / 100.0 - } -} - -#[derive(Debug, Clone)] -pub struct Program { - ins: Vec<Instruction>, - pc: usize, - pause_cnt: usize, - pause_len: usize, - looping: bool, - playing: bool, -} -impl Program { - pub const fn new(ins: Vec<Instruction>, looping: bool) -> Self { - Self { - ins, - pc: 0, - pause_cnt: 0, - pause_len: 4, - looping, - playing: false, - } - } - +impl Track { pub fn parse(src: &str, looping: bool) -> parse::Result<Self> { - let ins = parse::parse(src)?; - Ok(Self::new(ins, looping)) + let ins = Rc::new(parse::parse(src)?); + Ok(Self { ins, looping }) } pub fn merge(self, other: Self) -> Self { let mut res = vec![]; - let mut l = 0; let mut r = 0; let mut l_pause = 0; @@ -154,10 +125,46 @@ impl Program { } } - Self::new(res, self.looping) + Self { + ins: Rc::new(res), + looping: self.looping, + } + } +} +impl fmt::Display for Track { + 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(()) } +} - fn exec_ins(&mut self, channels: &mut Channels, ins: Instruction) { +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Program { + track: Track, + priority: u32, + pc: usize, + pause_cnt: usize, + pause_len: usize, + channels: Channels, +} +impl Program { + pub const fn new(track: Track, priority: u32) -> Self { + Self { + track, + priority, + pc: 0, + pause_cnt: 0, + pause_len: 4, + channels: Channels::new(), + } + } + + const fn exec_ins(&mut self, ins: Instruction) { use Instruction as I; match ins { I::Pause(cnt) => { @@ -172,93 +179,74 @@ impl Program { 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.volume = v, - C::PulseB => channels.pulse_b.volume = v, - C::Triangle => channels.triangle.volume = v, - C::Noise => channels.noise.volume = v, + C::PulseA => self.channels.pulse_a.volume = volume, + C::PulseB => self.channels.pulse_b.volume = volume, + C::Triangle => self.channels.triangle.volume = volume, + C::Noise => self.channels.noise.volume = volume, } } I::SetPitch(chan_spec, pitch) => { // set the pitch (freq) on a given channel use ChanSpec as C; - let p = map_pitch(pitch); match chan_spec { - 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, + C::PulseA => self.channels.pulse_a.pitch = pitch, + C::PulseB => self.channels.pulse_b.pitch = pitch, + C::Triangle => self.channels.triangle.pitch = pitch, + C::Noise => self.channels.noise.pitch = pitch, } } I::SetPulseDutyA(dc) => { - if let ChannelKind::Pulse { duty_cycle } = &mut channels.pulse_a.kind { + if let ChannelKind::Pulse { duty_cycle } = &mut self.channels.pulse_a.kind { *duty_cycle = dc; } } I::SetPulseDutyB(dc) => { - if let ChannelKind::Pulse { duty_cycle } = &mut channels.pulse_b.kind { + if let ChannelKind::Pulse { duty_cycle } = &mut self.channels.pulse_b.kind { *duty_cycle = dc; } } I::SetNoiseMode(m) => { - if let ChannelKind::Noise { mode, .. } = &mut channels.noise.kind { + if let ChannelKind::Noise { mode, .. } = &mut self.channels.noise.kind { *mode = m; } } } } - pub fn exec(&mut self, channels: &mut Channels) { - if !self.playing { - return; - } + pub fn exec(&mut self) -> Channels { if self.pause_cnt > 0 { self.pause_cnt -= 1; } loop { - if self.pause_cnt > 0 { - break; - } if self.is_finished() { - if self.looping { + if self.track.looping { self.pc = 0; } else { - self.playing = false; break; } } - let ins = self.ins[self.pc]; - self.exec_ins(channels, ins); + if self.pause_cnt > 0 { + break; + } + let ins = self.track.ins[self.pc]; + self.exec_ins(ins); self.pc += 1; } + self.channels } - pub const fn is_finished(&self) -> bool { - self.pc >= self.ins.len() - } - - pub const fn is_playing(&self) -> bool { - self.playing + pub fn is_finished(&self) -> bool { + self.pc >= self.track.ins.len() } - - pub const fn play(&mut self) { - self.playing = true; - self.pc = 0; - } - - pub const fn set_looping(&mut self, looping: bool) { - self.looping = looping; +} +impl PartialOrd for Program { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + Some(self.cmp(other)) } } -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(()) +impl Ord for Program { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + other.priority.cmp(&self.priority) } } |