diff --git a/src/bng.rs b/src/bng.rs index df8b4cd..b1c96c8 100644 --- a/src/bng.rs +++ b/src/bng.rs @@ -1,16 +1,22 @@ +use std::collections::HashMap; + +use amplify::{From, Wrapper}; use derive_new::new; use derived_deref::Deref; use fasteval::Instruction; -use instrument::Instrument; +pub(super) use instrument::Instrument; +pub(super) use score::Atom; +#[cfg(debug_assertions)] use serde::Serialize; mod instrument; mod score; -#[derive(new, Debug, PartialEq)] -pub struct InstructionWrapper(Instruction); +#[derive(Debug, PartialEq, Wrapper, From)] +pub struct Expression(Instruction); -impl Serialize for InstructionWrapper { +#[cfg(debug_assertions)] +impl Serialize for Expression { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -20,7 +26,15 @@ impl Serialize for InstructionWrapper { } } -#[derive(Serialize)] -struct BngFile { - instruments: Vec, +#[derive(new)] +#[cfg_attr(debug_assertions, derive(Serialize))] +pub(super) struct Channel { + instr: String, + score: Vec, +} + +#[cfg_attr(debug_assertions, derive(new, Serialize))] +pub(super) struct BngFile { + instruments: Vec>, + channels: HashMap, } diff --git a/src/bng/instrument.rs b/src/bng/instrument.rs index a060371..382a636 100644 --- a/src/bng/instrument.rs +++ b/src/bng/instrument.rs @@ -1,7 +1,16 @@ +use std::collections::HashMap; + +use derive_new::new; use derived_deref::Deref; +#[cfg(debug_assertions)] use serde::Serialize; -use super::InstructionWrapper as Instruction; +use super::Expression as Instruction; -#[derive(Serialize, Deref)] -pub struct Instrument(Instruction); +#[derive(Deref, new)] +#[cfg_attr(debug_assertions, derive(Serialize))] +pub struct Instrument { + #[target] + expr: Instruction, + vars: Option>, +} diff --git a/src/bng/score.rs b/src/bng/score.rs index 1f1ec70..89174e8 100644 --- a/src/bng/score.rs +++ b/src/bng/score.rs @@ -2,15 +2,17 @@ use std::num::{NonZeroU16, NonZeroU8}; use anyhow::Context; use bng_macros::{QuickModifierParser, SlopeModifierParser}; +#[cfg(debug_assertions)] +use serde::Serialize; use strum::EnumDiscriminants; mod lex; mod utils; -use super::InstructionWrapper as Instruction; +use super::Expression as Instruction; #[cfg_attr(debug_assertions, derive(Debug, PartialEq))] -pub(super) enum Atom { +pub enum Atom { Note(u8), Rest, StartHere, @@ -22,6 +24,16 @@ pub(super) enum Atom { Comment, } +#[cfg(debug_assertions)] +impl Serialize for Atom { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str("atom") + } +} + #[cfg_attr(debug_assertions, derive(Debug, PartialEq))] pub(super) enum FlatAtom { Note(u8), @@ -55,7 +67,7 @@ impl Clone for FlatAtom { #[derive(Clone)] #[cfg_attr(debug_assertions, derive(Debug, PartialEq))] -pub(super) enum Modifier { +pub enum Modifier { Volume(u8), Octave(u8), Length(NonZeroU8), @@ -70,16 +82,16 @@ impl Default for Modifier { #[derive(QuickModifierParser, Clone)] #[cfg_attr(debug_assertions, derive(Debug, PartialEq))] -pub(super) enum QuickModifier { +pub enum QuickModifier { Volume(bool), Octave(bool), Length(bool), Pizz(bool), } -#[derive(Clone, Copy, SlopeModifierParser)] -#[cfg_attr(debug_assertions, derive(Debug, PartialEq))] -pub(super) enum SlopeModifier { +#[derive(Clone, Copy, SlopeModifierParser, Debug)] +#[cfg_attr(debug_assertions, derive(PartialEq))] +pub enum SlopeModifier { Note, Volume, Octave, diff --git a/src/bng/score/lex/lexer.rs b/src/bng/score/lex/lexer.rs index 19df019..cdafbb7 100644 --- a/src/bng/score/lex/lexer.rs +++ b/src/bng/score/lex/lexer.rs @@ -16,7 +16,7 @@ use nom::{ }; use super::{ - super::super::InstructionWrapper as Instruction, + super::super::Expression as Instruction, {Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier}, }; @@ -68,15 +68,16 @@ fn flat_atom_parser(notes: &str) -> impl Parser<&str, FlatAtom, nom::error::Erro map_res(take_till1(|c| c == ','), |s| { let parser = fasteval::Parser::new(); let mut slab = fasteval::Slab::new(); - Result::>::Ok(Instruction::new( + Result::>::Ok( parser .parse(s, &mut slab.ps) .map_err(|_| { nom::error::Error::new(s, nom::error::ErrorKind::Verify) })? .from(&slab.ps) - .compile(&slab.ps, &mut slab.cs), - )) + .compile(&slab.ps, &mut slab.cs) + .into(), + ) }), ), ), diff --git a/src/bng/score/lex/lexer/tests.rs b/src/bng/score/lex/lexer/tests.rs index 9c91afb..2b29867 100644 --- a/src/bng/score/lex/lexer/tests.rs +++ b/src/bng/score/lex/lexer/tests.rs @@ -15,7 +15,7 @@ mod flat_atom { use nom::Parser; use super::super::{ - super::super::super::InstructionWrapper as Instruction, super::UP, flat_atom_parser, Atom, + super::super::super::Expression as Instruction, super::UP, flat_atom_parser, Atom, FlatAtom, Modifier, QuickModifier, SlopeModifier, }; use super::*; @@ -136,17 +136,19 @@ mod flat_atom { assert_eq!( Ok(( SAMPLE_STR, - FlatAtom::SlopeStarts(SlopeModifier::Note, { - let parser = fasteval::Parser::new(); - let mut slab = fasteval::Slab::new(); - Instruction::new( + FlatAtom::SlopeStarts( + SlopeModifier::Note, + { + let parser = fasteval::Parser::new(); + let mut slab = fasteval::Slab::new(); parser .parse(FASTEVAL_INSTRUCTION, &mut slab.ps) .unwrap() .from(&slab.ps) - .compile(&slab.ps, &mut slab.cs), - ) - }) + .compile(&slab.ps, &mut slab.cs) + } + .into() + ) )), flat_atom_parser("abcdefg").parse(concatcp!( Atom::SLOPE.0, diff --git a/src/bng/score/utils/tests.rs b/src/bng/score/utils/tests.rs index 0bb7dad..ff32448 100644 --- a/src/bng/score/utils/tests.rs +++ b/src/bng/score/utils/tests.rs @@ -10,13 +10,12 @@ mod inflate { fn instruction() -> Instruction { let parser = fasteval::Parser::new(); let mut slab = fasteval::Slab::new(); - Instruction::new( - parser - .parse(FASTEVAL_INSTRUCTION, &mut slab.ps) - .unwrap() - .from(&slab.ps) - .compile(&slab.ps, &mut slab.cs), - ) + parser + .parse(FASTEVAL_INSTRUCTION, &mut slab.ps) + .unwrap() + .from(&slab.ps) + .compile(&slab.ps, &mut slab.cs) + .into() } #[test] diff --git a/src/cli.rs b/src/cli.rs index 1bba81e..da8fc4e 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -21,7 +21,7 @@ pub enum BngCli { #[cfg_attr(debug_assertions, derive(Debug))] pub struct PlayOpts { #[arg(value_parser = FileContents::from_str)] - input: FileContents, + pub(super) input: FileContents, } /// [`BngCli`] "export" command options diff --git a/src/main.rs b/src/main.rs index 5cb1207..23b5054 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,51 @@ +use std::collections::HashMap; + +use bng::{BngFile, Channel, Expression, Instrument}; /// TODO: remove clap, use only a file or standard in use clap::Parser; +use cli::{BngCli as Cli, PlayOpts}; +use fasteval::Compiler; mod bng; mod cli; -fn main() { +fn main() -> Result<(), serde_yml::Error> { // println!("{}", option_env!("TEST").unwrap_or("ok")); - let args = cli::BngCli::parse(); + let args = Cli::parse(); + println!( + "{}", + serde_yml::to_string(&BngFile::new( + vec![HashMap::from([ + ( + "sine".to_string(), + Instrument::new(instruction("sin(2*PI*f*t)"), None) + ), + ( + "square".to_string(), + Instrument::new( + instruction("v*abs(sin(2*PI*f*t))"), + Some(HashMap::from([("v".to_string(), 1f32)])) + ) + ) + ])], + HashMap::::from([( + "melody".to_string(), + Channel::new("sine".to_string(), vec![]) + )]) + ))? + ); #[cfg(debug_assertions)] println!("{:?}", args); + Ok(()) +} + +fn instruction(expr_str: &str) -> Expression { + let parser = fasteval::Parser::new(); + let mut slab = fasteval::Slab::new(); + parser + .parse(expr_str, &mut slab.ps) + .unwrap() + .from(&slab.ps) + .compile(&slab.ps, &mut slab.cs) + .into() }