1.1.0 - TOML
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
20
src/main.rs
20
src/main.rs
@ -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(());
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
Reference in New Issue
Block a user