summaryrefslogtreecommitdiff
path: root/audio/src/program.rs
diff options
context:
space:
mode:
Diffstat (limited to 'audio/src/program.rs')
-rw-r--r--audio/src/program.rs138
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(())
+ }
+}