diff --git a/Cargo.lock b/Cargo.lock index 9c21c51..ffe90be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,7 +41,6 @@ version = "0.0.2" dependencies = [ "anyhow", "bliplib", - "constcat", "derive-new", "serde", "serde_json", @@ -110,12 +109,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "constcat" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d3e02915a2cea4d74caa8681e2d44b1c3254bdbf17d11d41d587ff858832c" - [[package]] name = "core-foundation-sys" version = "0.8.7" diff --git a/Cargo.toml b/Cargo.toml index d5f4ee6..86ece52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,14 +13,14 @@ name = "bliplab" [dependencies] anyhow = { version = "1", optional = true } bliplib = { version = "0.2.5", default-features = false } -constcat = { version = "0.6.1", optional = true } derive-new = "0.7.0" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", optional = true } serde_with = "3.13" [features] -bin = ["serde_json", "anyhow", "constcat"] +bin = ["serde_json", "anyhow"] +example-skip-defaults = [] [[bin]] name = "bliplab" diff --git a/src/cli/main.rs b/src/cli/main.rs index 94b574e..4f08b46 100644 --- a/src/cli/main.rs +++ b/src/cli/main.rs @@ -3,26 +3,62 @@ use std::{env::args, fs::File}; use anyhow::Context; -use bliplab::Song; -use constcat::concat; +use bliplab::{Channel, PathOrString, Song, VariableChange}; const TARGET: &str = "BLIP lab file"; -fn main() -> anyhow::Result<()> { - let song: Song = serde_json::from_reader( - File::open(args().skip(1).next().context(concat!( - "You need to give a single argument with the filename of your ", - TARGET, - "." - ))?) - .context(concat!("Failed to open the ", TARGET, "."))?, +fn example_song() -> Song<'static> { + Song::new( + Default::default(), + [( + "Piano".into(), + Channel::new( + PathOrString::String("hi".into()), + vec!["do", "ré", "mi"].into_iter().map(Into::into), + "sin(2*pi()*(442*2^((n+1)/N))*t)".parse().unwrap(), + [ + ('l', 4f64), + ('L', 0.0), + ('t', 0.0), + ('T', 60.0), + ('N', 12.0), + ], + [], + [( + "L".into(), + VariableChange::new('L', "2^(2-log(2, l))*(60/T)".parse().unwrap()), + )], + ), + )], ) - .context(concat!("Failed to read the ", TARGET, "."))?; +} - println!( - "{}", - serde_json::to_string_pretty(&song).context("Failed to pretty print the song! What?!")? - ); +fn main() -> anyhow::Result<()> { + let string = args().skip(1).next().context(format!( + "You need to give a single argument with the filename of your {TARGET}." + ))?; + if let Some(argument) = string.strip_prefix("--") { + if argument == "example" { + println!("{}", serde_json::to_string_pretty(&example_song()).unwrap()); + } else if argument == "help" { + println!( + "BLIP lab file player. Pass it a path to a {TARGET} or use with \"--example\" for an example {TARGET}." + ); + } else { + eprintln!("Unknown argument: \"{argument}\""); + } + } else { + let song: Song = serde_json::from_reader( + File::open(string).context(format!("Failed to open the {TARGET}."))?, + ) + .context(format!("Failed to read the {TARGET}."))?; + + println!( + "{}", + serde_json::to_string_pretty(&song) + .context("Failed to pretty print the song! What?!")? + ); + } Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index b5b0922..f943349 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,19 @@ use derive_new::new; use serde::{Deserialize, Serialize}; use serde_with::{DisplayFromStr, serde_as}; +fn is_default(t: &T) -> bool { + t == &T::default() +} + /// Entry point to a BLIPlab song. Made of BLIP channels. #[derive(new, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct Song<'a> { #[serde(default)] + #[cfg_attr( + feature = "example-skip-defaults", + serde(skip_serializing_if = "is_default") + )] global_variables: Globals, #[new(into_iter = "(Cow<'a, str>, Channel<'a>)")] channels: HashMap, Channel<'a>>, @@ -19,7 +27,7 @@ pub struct Song<'a> { /// Global variables used by the compiler for rendering every sample. /// They are made global for the sake of consistency but can be modified. -#[derive(new, Serialize, Deserialize)] +#[derive(new, Serialize, Deserialize, PartialEq)] #[serde(deny_unknown_fields)] pub struct Globals { #[new(into)] @@ -46,9 +54,17 @@ pub struct Channel<'a> { instrument: Expression, #[new(into_iter = "(char, f64)")] #[serde(default)] + #[cfg_attr( + feature = "example-skip-defaults", + serde(skip_serializing_if = "is_default") + )] variables: HashMap, #[new(into_iter = "(char, Cow<'a, str>)")] #[serde(default)] + #[cfg_attr( + feature = "example-skip-defaults", + serde(skip_serializing_if = "is_default") + )] macros: HashMap>, #[new(into_iter = "(Cow<'a, str>, VariableChange)")] #[serde(default = "default_slope")]