1.1.0 - TOML

This commit is contained in:
2025-06-23 23:54:23 -06:00
parent 8d86d1cbfb
commit 944a33eb95
10 changed files with 550 additions and 1720 deletions

View File

@ -1,6 +1,6 @@
//! JSON configuration module for composition specifications
//! TOML configuration module for composition specifications
//!
//! This module provides structures and parsing for JSON-based composition definitions,
//! This module provides structures and parsing for TOML-based composition definitions,
//! allowing users to specify complete compositions in a declarative format.
use crate::core::{CompositionParams, CompositionStyle};
@ -235,7 +235,7 @@ pub struct PatternConfig {
/// Pattern-specific parameters
#[serde(flatten)]
pub params: serde_json::Value,
pub params: toml::Value,
}
/// Effect configuration
@ -255,7 +255,7 @@ pub struct EffectConfig {
/// Effect parameters
#[serde(flatten)]
pub params: serde_json::Value,
pub params: toml::Value,
}
/// Export settings
@ -409,29 +409,28 @@ fn parse_note_name(name: &str) -> Result<u8, String> {
}
impl CompositionConfig {
/// Load configuration from a JSON file
/// Load configuration from a TOML file
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, String> {
let content =
fs::read_to_string(path).map_err(|e| format!("Failed to read config file: {}", e))?;
Self::from_json(&content)
Self::from_toml(&content)
}
/// Parse configuration from JSON string
pub fn from_json(json: &str) -> Result<Self, String> {
serde_json::from_str(json).map_err(|e| format!("Failed to parse JSON: {}", e))
/// Parse configuration from TOML string
pub fn from_toml(toml_str: &str) -> Result<Self, String> {
toml::from_str(toml_str).map_err(|e| format!("Failed to parse TOML: {}", e))
}
/// Save configuration to a JSON file
/// Save configuration to a TOML file
pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), String> {
let json = self.to_json_pretty()?;
fs::write(path, json).map_err(|e| format!("Failed to write config file: {}", e))
let toml_str = self.to_toml_pretty()?;
fs::write(path, toml_str).map_err(|e| format!("Failed to write config file: {}", e))
}
/// Serialize configuration to pretty JSON
pub fn to_json_pretty(&self) -> Result<String, String> {
serde_json::to_string_pretty(self)
.map_err(|e| format!("Failed to serialize to JSON: {}", e))
/// Serialize configuration to pretty TOML
pub fn to_toml_pretty(&self) -> Result<String, String> {
toml::to_string_pretty(self).map_err(|e| format!("Failed to serialize to TOML: {}", e))
}
/// Convert to composition parameters (deprecated - use track-based generation instead)
@ -534,8 +533,8 @@ mod tests {
#[test]
fn test_config_serialization() {
let config = CompositionConfig::example();
let json = config.to_json_pretty().unwrap();
let parsed = CompositionConfig::from_json(&json).unwrap();
let toml_str = config.to_toml_pretty().unwrap();
let parsed = CompositionConfig::from_toml(&toml_str).unwrap();
assert_eq!(parsed.composition.tempo, config.composition.tempo);
}

View File

@ -19,16 +19,16 @@ struct Cli {
#[derive(Subcommand)]
enum Commands {
/// Generate composition from JSON configuration file
Json {
/// Path to JSON configuration file
/// Generate composition from TOML configuration file
Toml {
/// Path to TOML configuration file
config: PathBuf,
/// Override output filename
#[arg(short, long)]
output: Option<String>,
/// Print example JSON configuration
/// Print example TOML configuration
#[arg(long)]
example: bool,
},
@ -53,11 +53,11 @@ fn main() {
let cli = Cli::parse();
let result = match cli.command {
Commands::Json {
Commands::Toml {
config,
output,
example,
} => handle_json_command(config, output, example),
} => handle_toml_command(config, output, example),
Commands::Info {
scales,
@ -126,16 +126,16 @@ fn show_info(scales: bool, instruments: bool, all: bool) -> Result<(), Box<dyn s
Ok(())
}
fn handle_json_command(
fn handle_toml_command(
config_path: PathBuf,
output_override: Option<String>,
show_example: bool,
) -> Result<(), Box<dyn std::error::Error>> {
if show_example {
let example = CompositionConfig::example();
println!("{}", example.to_json_pretty()?);
println!("\n# Save this to a .json file and run:");
println!("# cargo run --bin musicgen json your_config.json");
println!("{}", example.to_toml_pretty()?);
println!("\n# Save this to a .toml file and run:");
println!("# cargo run --bin musicgen toml your_config.toml");
return Ok(());
}

View File

@ -87,12 +87,12 @@ impl TrackState {
let cutoff = effect_config
.params
.get("cutoff")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(1000.0) as f32;
let resonance = effect_config
.params
.get("resonance")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(1.0) as f32;
Box::new(LowPassFilter::new(cutoff, resonance))
}
@ -100,12 +100,12 @@ impl TrackState {
let cutoff = effect_config
.params
.get("cutoff")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(1000.0) as f32;
let resonance = effect_config
.params
.get("resonance")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(1.0) as f32;
Box::new(HighPassFilter::new(cutoff, resonance))
}
@ -113,17 +113,17 @@ impl TrackState {
let time = effect_config
.params
.get("time")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.3) as f32;
let feedback = effect_config
.params
.get("feedback")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.3) as f32;
let mix = effect_config
.params
.get("mix")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.3) as f32;
Box::new(Delay::new(time, feedback, mix))
}
@ -131,17 +131,17 @@ impl TrackState {
let room_size = effect_config
.params
.get("room_size")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.5) as f32;
let damping = effect_config
.params
.get("damping")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.5) as f32;
let mix = effect_config
.params
.get("mix")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.3) as f32;
Box::new(Reverb::new(room_size, damping, mix))
}
@ -149,12 +149,12 @@ impl TrackState {
let drive = effect_config
.params
.get("drive")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(2.0) as f32;
let tone = effect_config
.params
.get("tone")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.5) as f32;
Box::new(Distortion::new(drive, tone))
}
@ -162,22 +162,22 @@ impl TrackState {
let rate = effect_config
.params
.get("rate")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(1.0) as f32;
let depth = effect_config
.params
.get("depth")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.5) as f32;
let mix = effect_config
.params
.get("mix")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.3) as f32;
let layers = effect_config
.params
.get("layers")
.and_then(|v| v.as_u64())
.and_then(|v| v.as_integer())
.unwrap_or(3) as usize;
Box::new(Chorus::new(rate, depth, mix, layers))
}
@ -185,17 +185,17 @@ impl TrackState {
let intensity = effect_config
.params
.get("intensity")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.5) as f32;
let frequency = effect_config
.params
.get("frequency")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.5) as f32;
let mix = effect_config
.params
.get("mix")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.3) as f32;
Box::new(VinylCrackle::new(intensity, frequency, mix))
}
@ -203,17 +203,17 @@ impl TrackState {
let drive = effect_config
.params
.get("drive")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(2.0) as f32;
let warmth = effect_config
.params
.get("warmth")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.7) as f32;
let mix = effect_config
.params
.get("mix")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.5) as f32;
Box::new(TapeSaturation::new(drive, warmth, mix))
}
@ -221,17 +221,17 @@ impl TrackState {
let bit_depth = effect_config
.params
.get("bit_depth")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(8.0) as f32;
let sample_rate_reduction = effect_config
.params
.get("sample_rate_reduction")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(2.0) as f32;
let mix = effect_config
.params
.get("mix")
.and_then(|v| v.as_f64())
.and_then(|v| v.as_float())
.unwrap_or(0.5) as f32;
Box::new(BitCrusher::new(bit_depth, sample_rate_reduction, mix))
}