example & help commands
This commit is contained in:
parent
1293694b0e
commit
1c3b8069aa
4 changed files with 70 additions and 25 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
18
src/lib.rs
18
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: Default + PartialEq>(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<Cow<'a, str>, 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<char, f64>,
|
||||
#[new(into_iter = "(char, Cow<'a, str>)")]
|
||||
#[serde(default)]
|
||||
#[cfg_attr(
|
||||
feature = "example-skip-defaults",
|
||||
serde(skip_serializing_if = "is_default")
|
||||
)]
|
||||
macros: HashMap<char, Cow<'a, str>>,
|
||||
#[new(into_iter = "(Cow<'a, str>, VariableChange)")]
|
||||
#[serde(default = "default_slope")]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue