From 654277d89471010f57794b8022385d2a99a15a14 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 21 Nov 2025 22:25:37 -0500 Subject: audio: create orchestration system --- graphics/src/audio/parse/parser.rs | 100 +++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 graphics/src/audio/parse/parser.rs (limited to 'graphics/src/audio/parse/parser.rs') diff --git a/graphics/src/audio/parse/parser.rs b/graphics/src/audio/parse/parser.rs new file mode 100644 index 0000000..fbe5f4c --- /dev/null +++ b/graphics/src/audio/parse/parser.rs @@ -0,0 +1,100 @@ +use std::iter::Peekable; + +use crate::audio::program::{ChanSpec, Instruction}; + +use super::{ + Result, + lex::{Lexer, Token}, +}; + +pub struct Parser<'s> { + lexer: Peekable>, +} +impl<'s> Parser<'s> { + pub fn new(src: &'s str) -> Self { + Self { + lexer: Lexer::new(src).peekable(), + } + } + + fn next(&mut self) -> Result { + self.lexer + .next() + .unwrap_or_else(|| Err("should not happen".to_owned())) + } + + fn peek(&mut self) -> Result { + self.lexer + .peek() + .map_or_else(|| Err("should not happen".to_owned()), Result::clone) + } + + fn parse_chan_spec(&mut self) -> Result { + match self.next()? { + Token::ChanSpec(spec) => Ok(spec), + t => Err(format!("expected channel specifier, got {t:?}")), + } + } + + fn parse_ins(&mut self, spec: ChanSpec) -> Result { + use Token as T; + let t = self.next()?; + let ins = match t { + T::SetPitch(pitch) => Instruction::SetPitch(spec, pitch), + T::SetVolume(volume) => Instruction::SetVolume(spec, volume), + T::SetNoiseMode(mode) if spec == ChanSpec::Noise => { + Instruction::SetNoiseMode(mode) + } + T::SetPulseDuty(duty_cycle) if spec == ChanSpec::PulseA => { + Instruction::SetPulseDutyA(duty_cycle) + } + T::SetPulseDuty(duty_cycle) if spec == ChanSpec::PulseB => { + Instruction::SetPulseDutyB(duty_cycle) + } + _ => unexpected(t)?, + }; + Ok(ins) + } + + fn parse_line(&mut self, prog: &mut Vec) -> Result<()> { + let spec = self.parse_chan_spec()?; + loop { + prog.push(self.parse_ins(spec)?); + let peek = self.peek()?; + if peek.is_eol() || matches!(peek, Token::Pause(_)) { + break; + } + } + Ok(()) + } + + pub fn parse(&mut self) -> Result> { + let mut prog = vec![]; + loop { + let t = self.peek()?; + match t { + Token::Eof => break, + Token::LineSeparator => { + self.next()?; + } + Token::Pause(count) => { + self.next()?; + for _ in 0..count { + prog.push(Instruction::Pause); + } + } + Token::Jump(pc) => { + self.next()?; + prog.push(Instruction::Jump(pc)); + } + _ => self.parse_line(&mut prog)?, + } + } + Ok(prog) + } +} + +fn unexpected(t: Token) -> Result { + let msg = format!("unexpected token: {t:?}"); + Err(msg) +} -- cgit v1.2.3-freya