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.rs160
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)
}
}