From 944a33eb95d9ca2552651bac2ebe1facde1915aa Mon Sep 17 00:00:00 2001 From: Atridad Lahiji Date: Mon, 23 Jun 2025 23:54:23 -0600 Subject: [PATCH] 1.1.0 - TOML --- Cargo.lock | 37 +- Cargo.toml | 4 +- README.md | 145 ++++--- composition-schema.toml | 385 +++++++++++++++++ examples/composition-schema.json | 666 ----------------------------- examples/enchanted.json | 697 ------------------------------- examples/fantasy.json | 231 ---------- src/config.rs | 35 +- src/main.rs | 20 +- src/sequencer.rs | 50 +-- 10 files changed, 550 insertions(+), 1720 deletions(-) create mode 100644 composition-schema.toml delete mode 100644 examples/composition-schema.json delete mode 100644 examples/enchanted.json delete mode 100644 examples/fantasy.json diff --git a/Cargo.lock b/Cargo.lock index 4dd18f9..6f067d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -684,7 +684,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "musicgen" -version = "1.0.0" +version = "1.1.0" dependencies = [ "clap", "cpal 0.16.0", @@ -693,7 +693,7 @@ dependencies = [ "rand", "rodio", "serde", - "serde_json", + "toml", ] [[package]] @@ -1148,6 +1148,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1265,11 +1274,26 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + [[package]] name = "toml_datetime" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -1278,10 +1302,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", + "serde", + "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "unicode-ident" version = "1.0.18" diff --git a/Cargo.toml b/Cargo.toml index 89bf80f..d4a6701 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "musicgen" -version = "1.0.0" +version = "1.1.0" edition = "2024" authors = ["Atridad Lahiji "] description = "Generate electronic music without AI" @@ -15,7 +15,7 @@ hound = "3.5" rand = "0.8" clap = { version = "4.5", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +toml = "0.8" # Real-time audio rodio = "0.20" diff --git a/README.md b/README.md index 810d66f..9823126 100644 --- a/README.md +++ b/README.md @@ -14,47 +14,45 @@ cd music cargo build --release ``` -## JSON Configuration +## TOML Configuration -Create declaritive songs with structured JSON: +Create declaritive songs with structured TOML: ```bash -cargo run --bin musicgen json examples/fantasy.json +cargo run --bin musicgen toml examples/enchanted.toml ``` ### From Binary ```bash -./target/release/musicgen json examples/fantasy.json +./target/release/musicgen toml examples/enchanted.toml ``` -### Basic JSON Structure +### Basic TOML Structure -```json -{ - "composition": { - "key": 60, - "scale": "minor", - "tempo": 85.0, - "measures": 16 - }, - "tracks": [ - { - "name": "bass", - "instrument": "sine", - "volume": 0.8, - "pattern": { - "type": "custom", - "steps": [ - { "time": 0.0, "note": "C2", "duration": 0.75, "velocity": 0.9 } - ] - } - } - ], - "export": { - "filename": "my_song", - "format": "wav" - } -} +```toml +[composition] +key = 60 +scale = "minor" +tempo = 85.0 +measures = 16 + +[[tracks]] +name = "bass" +instrument = "sine" +volume = 0.8 + +[tracks.pattern] +type = "custom" + +[[tracks.pattern.steps]] +time = 0.0 +note = "C2" +duration = 0.75 +velocity = 0.9 + +[export] +filename = "my_song" +format = "wav" ``` ### Definitions @@ -85,46 +83,55 @@ cargo run --bin musicgen json examples/fantasy.json ### Track Configuration -```json -{ - "tracks": [ - { - "name": "bass", - "instrument": "sine", - "volume": 0.8, - "pattern": { - "type": "custom", - "steps": [ - { "time": 0.0, "note": "C2", "duration": 0.75, "velocity": 0.9 }, - { "time": 2.0, "note": "G2", "duration": 0.75, "velocity": 0.8 } - ], - "loop_length": 4.0 - }, - "effects": [ - { - "type": "lowpass", - "cutoff": 400.0, - "resonance": 1.8 - } - ] - }, - { - "name": "drums", - "instrument": "noise", - "volume": 0.6, - "pattern": { - "type": "custom", - "steps": [ - { "time": 0.0, "note": "C1", "duration": 0.1, "velocity": 1.0 }, - { "time": 1.0, "note": "E3", "duration": 0.05, "velocity": 0.7 } - ] - } - } - ] -} +```toml +[[tracks]] +name = "bass" +instrument = "sine" +volume = 0.8 + +[tracks.pattern] +type = "custom" +loop_length = 4.0 + +[[tracks.pattern.steps]] +time = 0.0 +note = "C2" +duration = 0.75 +velocity = 0.9 + +[[tracks.pattern.steps]] +time = 2.0 +note = "G2" +duration = 0.75 +velocity = 0.8 + +[[tracks.effects]] +type = "lowpass" +cutoff = 400.0 +resonance = 1.8 + +[[tracks]] +name = "drums" +instrument = "noise" +volume = 0.6 + +[tracks.pattern] +type = "custom" + +[[tracks.pattern.steps]] +time = 0.0 +note = "C1" +duration = 0.1 +velocity = 1.0 + +[[tracks.pattern.steps]] +time = 1.0 +note = "E3" +duration = 0.05 +velocity = 0.7 ``` -See `examples` for complete examples and the full schema. +See `composition-schema` for a complete example and the full schema. ## Output diff --git a/composition-schema.toml b/composition-schema.toml new file mode 100644 index 0000000..2e7faae --- /dev/null +++ b/composition-schema.toml @@ -0,0 +1,385 @@ +# MusicGen TOML Configuration Schema +# Complete reference for all available fields and options + +# ============================================================================ +# METADATA SECTION +# Optional information about your composition +# ============================================================================ + +[metadata] +title = "My Composition" # Title of the track +artist = "Artist Name" # Your name or band name +description = "An electronic song" # Description of the composition +tags = ["electronic", "ambient", "chill"] # Genre tags or keywords + +# ============================================================================ +# COMPOSITION SECTION +# Core musical settings that define the overall structure +# ============================================================================ + +[composition] +# Musical key - can be MIDI note number (60 = C4) or note name +key = "C4" # Options: MIDI numbers 0-127 OR note names like "C4", "F#3", "Bb5" + +# Scale type - defines which notes are used +scale = "major" # Options: "major", "minor", "dorian", "phrygian", "lydian", +# "mixolydian", "aeolian", "locrian", "pentatonic", +# "blues", "chromatic" + +# Tempo in beats per minute +tempo = 120.0 # Range: 40.0 - 300.0 BPM + +# Time signature - how many beats per measure +[composition.time_signature] +numerator = 4 # Beats per measure (1-16) +denominator = 4 # Note value for one beat (2, 4, 8, or 16) + +# Composition length and complexity +measures = 32 # Number of measures (1-1000) +complexity = 0.7 # Overall complexity (0.0-1.0, default: 0.6) +harmony_density = 0.8 # How much harmony/chords (0.0-1.0, default: 0.7) +rhythmic_density = 0.6 # How busy the rhythm is (0.0-1.0, default: 0.8) +seed = 12345 # Random seed for reproducible generation (optional) + +# ============================================================================ +# TRACKS SECTION +# Each track is like one instrument in your band +# ============================================================================ + +# Example 1: Custom melody track +[[tracks]] +name = "main_melody" +instrument = "piano" # Options: "sine", "square", "sawtooth", "triangle", "noise", "piano" +volume = 0.8 # Track volume (0.0-1.0) + +[tracks.pattern] +type = "custom" # Pattern type: "custom", "chord", "arpeggio", "sequence" +loop_length = 16.0 # How long before pattern repeats (in beats) + +# Individual notes in the pattern +[[tracks.pattern.steps]] +time = 0.0 # When to play (in beats from start of loop) +note = "C5" # MIDI number or note name +duration = 1.5 # How long to hold the note (in beats) +velocity = 0.7 # How loud to play this note (0.0-1.0) + +[[tracks.pattern.steps]] +time = 2.0 +note = "E5" +duration = 1.0 +velocity = 0.6 + +[[tracks.pattern.steps]] +time = 4.0 +note = "G5" +duration = 2.0 +velocity = 0.8 + +# Effects for this track +[[tracks.effects]] +type = "reverb" +room_size = 0.7 # Size of the reverb space (0.0-1.0) +damping = 0.5 # How much high frequencies are absorbed (0.0-1.0) +mix = 0.3 # How much effect to blend in (0.0-1.0) + +[[tracks.effects]] +type = "delay" +time = 0.25 # Delay time in seconds (0.01-2.0) +feedback = 0.3 # How much delay repeats (0.0-0.95) +mix = 0.2 # How much effect to blend in (0.0-1.0) + +# Example 2: Chord progression track +[[tracks]] +name = "harmony" +instrument = "sawtooth" +volume = 0.6 + +[tracks.pattern] +type = "chord" +loop_length = 16.0 +voicing = "spread" # Options: "close", "spread", "drop2", "drop3" +octave = 3 # Which octave to play chords in (0-8) + +# Chord progression +[[tracks.pattern.chord_progression]] +time = 0.0 +chord = "Cmaj7" # Chord name (e.g., "C", "Am", "F#dim", "Bbmaj7") +duration = 4.0 + +[[tracks.pattern.chord_progression]] +time = 4.0 +chord = "Am7" +duration = 4.0 + +[[tracks.pattern.chord_progression]] +time = 8.0 +chord = "Fmaj7" +duration = 4.0 + +[[tracks.pattern.chord_progression]] +time = 12.0 +chord = "G7" +duration = 4.0 + +# Effects for chord track +[[tracks.effects]] +type = "lowpass" +cutoff = 2000.0 # Cutoff frequency in Hz (20-20000) +resonance = 1.2 # Filter resonance (0.1-10.0) + +# Example 3: Bass track +[[tracks]] +name = "bass" +instrument = "sine" +volume = 0.9 + +[tracks.pattern] +type = "custom" +loop_length = 8.0 + +[[tracks.pattern.steps]] +time = 0.0 +note = "C2" +duration = 1.0 +velocity = 0.9 + +[[tracks.pattern.steps]] +time = 2.0 +note = "G2" +duration = 1.0 +velocity = 0.8 + +[[tracks.pattern.steps]] +time = 4.0 +note = "A2" +duration = 1.0 +velocity = 0.8 + +[[tracks.pattern.steps]] +time = 6.0 +note = "F2" +duration = 1.0 +velocity = 0.9 + +# Bass effects +[[tracks.effects]] +type = "highpass" +cutoff = 80.0 # Remove very low frequencies +resonance = 0.7 + +# Example 4: Percussion track +[[tracks]] +name = "drums" +instrument = "noise" +volume = 0.7 + +[tracks.pattern] +type = "custom" +loop_length = 4.0 + +# Kick drum +[[tracks.pattern.steps]] +time = 0.0 +note = "C1" # Low note for kick +duration = 0.1 +velocity = 1.0 + +[[tracks.pattern.steps]] +time = 2.0 +note = "C1" +duration = 0.1 +velocity = 1.0 + +# Snare/hi-hat +[[tracks.pattern.steps]] +time = 1.0 +note = "D4" # Higher note for snare +duration = 0.05 +velocity = 0.7 + +[[tracks.pattern.steps]] +time = 3.0 +note = "D4" +duration = 0.05 +velocity = 0.7 + +# Drum effects +[[tracks.effects]] +type = "distortion" +drive = 1.5 # Amount of distortion (1.0-10.0) +tone = 0.6 # Tone control (0.0-1.0) + +[[tracks.effects]] +type = "chorus" +rate = 1.2 # Modulation rate in Hz (0.1-10.0) +depth = 0.4 # Modulation depth (0.0-1.0) +layers = 3 # Number of chorus layers (1-8) +mix = 0.3 + +# ============================================================================ +# SECTIONS SECTION (Optional) +# For structured compositions with different parts +# ============================================================================ + +[[sections]] +name = "intro" +measures = 8 +tempo = 100.0 # Optional tempo change for this section +complexity = 0.3 # Lower complexity for intro +repeat = 1 # How many times to repeat this section + +[[sections]] +name = "verse" +measures = 16 +complexity = 0.6 +repeat = 2 + +[[sections]] +name = "chorus" +measures = 16 +tempo = 125.0 # Faster tempo for chorus +complexity = 0.8 +key = "F4" # Optional key change +scale = "major" # Optional scale change +repeat = 2 + +[[sections]] +name = "bridge" +measures = 8 +complexity = 0.9 +key = "Am" # Relative minor +repeat = 1 + +[[sections]] +name = "outro" +measures = 8 +tempo = 90.0 # Slower outro +complexity = 0.2 +repeat = 1 + +# ============================================================================ +# EXPORT SECTION +# How to save your finished composition +# ============================================================================ + +[export] +filename = "my_song" # Output filename (without extension) +format = "wav" # Only "wav" currently supported +sample_rate = 44100 # Options: 22050, 44100, 48000, 96000 +bit_depth = 24 # Options: 16, 24, 32 +stereo = true # true for stereo, false for mono +max_duration = 180.0 # Maximum length in seconds (optional) + +# Optional: Generate variations of your composition +[export.variations] +count = 3 # Number of variations to generate +vary_complexity = true # Vary the complexity between versions +vary_rhythm = true # Vary the rhythmic patterns +vary_harmony = false # Vary the chord progressions +vary_tempo = false # Vary the tempo + +# ============================================================================ +# EFFECT TYPES REFERENCE +# Complete list of all available effects and their parameters +# ============================================================================ + +# FILTERS +# [[tracks.effects]] +# type = "lowpass" # Removes high frequencies (makes sound warmer/duller) +# cutoff = 1000.0 # Frequency cutoff in Hz (20-20000) +# resonance = 1.0 # Emphasis at cutoff frequency (0.1-10.0) + +# [[tracks.effects]] +# type = "highpass" # Removes low frequencies (makes sound thinner/brighter) +# cutoff = 100.0 # Frequency cutoff in Hz (20-20000) +# resonance = 1.0 # Emphasis at cutoff frequency (0.1-10.0) + +# TIME-BASED EFFECTS +# [[tracks.effects]] +# type = "delay" # Echo effect +# time = 0.25 # Delay time in seconds (0.01-2.0) +# feedback = 0.3 # How much delay feeds back (0.0-0.95) +# mix = 0.3 # Wet/dry mix (0.0-1.0) + +# [[tracks.effects]] +# type = "reverb" # Spatial reverb +# room_size = 0.5 # Size of reverb space (0.0-1.0) +# damping = 0.5 # High frequency absorption (0.0-1.0) +# mix = 0.3 # Wet/dry mix (0.0-1.0) + +# [[tracks.effects]] +# type = "chorus" # Thickening/modulation effect +# rate = 1.0 # Modulation rate in Hz (0.1-10.0) +# depth = 0.5 # Modulation depth (0.0-1.0) +# layers = 3 # Number of voices (1-8) +# mix = 0.3 # Wet/dry mix (0.0-1.0) + +# DISTORTION +# [[tracks.effects]] +# type = "distortion" # Hard clipping distortion +# drive = 2.0 # Amount of distortion (1.0-10.0) +# tone = 0.5 # Tone control (0.0-1.0, 0=dark, 1=bright) + +# LO-FI EFFECTS +# [[tracks.effects]] +# type = "vinyl" # Vinyl crackle and surface noise +# intensity = 0.5 # Crackle intensity (0.0-1.0) +# frequency = 0.5 # Crackle frequency (0.0-1.0) +# mix = 0.3 # Wet/dry mix (0.0-1.0) + +# [[tracks.effects]] +# type = "tape" # Tape saturation and warmth +# drive = 2.0 # Saturation amount (1.0-10.0) +# warmth = 0.7 # Warmth/color (0.0-1.0) +# mix = 0.5 # Wet/dry mix (0.0-1.0) + +# [[tracks.effects]] +# type = "bitcrusher" # Digital degradation +# bit_depth = 8.0 # Bit depth reduction (1.0-16.0) +# sample_rate_reduction = 2.0 # Sample rate reduction factor (1.0-10.0) +# mix = 0.5 # Wet/dry mix (0.0-1.0) + +# ============================================================================ +# INSTRUMENT TYPES REFERENCE +# ============================================================================ + +# instrument = "sine" # Pure sine wave - smooth, warm, flute-like +# instrument = "square" # Square wave - classic video game sound, punchy +# instrument = "sawtooth" # Sawtooth wave - bright, buzzy, good for leads +# instrument = "triangle" # Triangle wave - mellow, soft, like filtered square +# instrument = "noise" # White noise - for percussion and texture +# instrument = "piano" # Natural piano with harmonics + +# ============================================================================ +# PATTERN TYPES REFERENCE +# ============================================================================ + +# type = "custom" # Specify exact notes and timing +# type = "chord" # Play chord progressions +# type = "arpeggio" # Arpeggiate chords (play notes one after another) +# type = "sequence" # Step sequencer patterns + +# ============================================================================ +# CHORD NAMES REFERENCE +# ============================================================================ + +# Basic triads: "C", "Dm", "E", "F#", "Bb" +# Seventh chords: "Cmaj7", "Dm7", "E7", "F#m7b5", "Bbmaj7" +# Extended chords: "C9", "Dm11", "E13" +# Altered chords: "C7#11", "Dm7b5", "E7alt" +# Diminished/Augmented: "Cdim", "Caug", "C°7", "C+7" + +# ============================================================================ +# NOTE NAMES REFERENCE +# ============================================================================ + +# Format: [Note][Accidental][Octave] +# Notes: C, D, E, F, G, A, B +# Accidentals: # (sharp), b (flat), ♯, ♭ +# Octaves: 0-9 (C4 = middle C = MIDI 60) +# Examples: "C4", "F#3", "Bb5", "A0", "G9" + +# MIDI equivalents: +# C4 = 60, C#4 = 61, D4 = 62, D#4 = 63, E4 = 64, F4 = 65 +# F#4 = 66, G4 = 67, G#4 = 68, A4 = 69, A#4 = 70, B4 = 71 +# Add/subtract 12 for different octaves diff --git a/examples/composition-schema.json b/examples/composition-schema.json deleted file mode 100644 index b5759a6..0000000 --- a/examples/composition-schema.json +++ /dev/null @@ -1,666 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://example.com/schemas/composition-config.json", - "title": "Generate electronic music without AI", - "description": "JSON schema for configuring musicgen", - "type": "object", - "properties": { - "metadata": { - "type": "object", - "description": "Metadata about the composition", - "properties": { - "title": { - "type": "string", - "description": "Composition title", - "default": "" - }, - "artist": { - "type": "string", - "description": "Artist or composer name", - "default": "" - }, - "description": { - "type": "string", - "description": "Description of the composition", - "default": "" - }, - "tags": { - "type": "array", - "description": "Tags or genres", - "items": { - "type": "string" - }, - "default": [] - } - }, - "additionalProperties": false - }, - "composition": { - "type": "object", - "description": "Global composition settings", - "required": ["key", "scale", "tempo", "measures"], - "properties": { - "key": { - "description": "Musical key", - "oneOf": [ - { - "type": "integer", - "minimum": 0, - "maximum": 127, - "description": "MIDI note number (60 = C4)" - }, - { - "type": "string", - "pattern": "^[A-G][#b♯♭]?[0-9]$", - "description": "Note name (e.g., 'C4', 'F#3', 'Bb5')" - } - ] - }, - "scale": { - "type": "string", - "description": "Scale type", - "enum": [ - "major", - "minor", - "dorian", - "phrygian", - "lydian", - "mixolydian", - "aeolian", - "locrian", - "pentatonic", - "blues", - "chromatic" - ] - }, - "tempo": { - "type": "number", - "description": "Tempo in beats per minute (BPM)", - "minimum": 40, - "maximum": 300 - }, - "time_signature": { - "type": "object", - "properties": { - "numerator": { - "type": "integer", - "minimum": 1, - "maximum": 16, - "description": "Number of beats per measure" - }, - "denominator": { - "type": "integer", - "enum": [2, 4, 8, 16], - "description": "Note value that gets one beat" - } - }, - "required": ["numerator", "denominator"], - "additionalProperties": false, - "default": { - "numerator": 4, - "denominator": 4 - } - }, - "measures": { - "type": "integer", - "description": "Number of measures in the composition", - "minimum": 1, - "maximum": 1000 - }, - "complexity": { - "type": "number", - "description": "Musical complexity level (0.0 = simple, 1.0 = complex)", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.6 - }, - "harmony_density": { - "type": "number", - "description": "Harmonic density (0.0 = sparse, 1.0 = dense)", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.7 - }, - "rhythmic_density": { - "type": "number", - "description": "Rhythmic density (0.0 = sparse, 1.0 = dense)", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.8 - }, - "seed": { - "type": "integer", - "description": "Random seed for reproducible generation", - "minimum": 0, - "maximum": 18446744073709551615 - } - }, - "additionalProperties": false - }, - "tracks": { - "type": "array", - "description": "Individual track definitions", - "items": { - "type": "object", - "required": ["name", "instrument", "pattern"], - "properties": { - "name": { - "type": "string", - "description": "Track name (e.g., 'bass', 'kick', 'hihat', 'pad')" - }, - "instrument": { - "type": "string", - "description": "Instrument/waveform type", - "enum": ["sine", "square", "sawtooth", "triangle", "noise", "piano"] - }, - "volume": { - "type": "number", - "description": "Track volume level (0.0 = silent, 1.0 = full)", - "minimum": 0.0, - "maximum": 1.0, - "default": 1.0 - }, - "pattern": { - "type": "object", - "description": "Pattern definition for this track", - "required": ["type"], - "properties": { - "type": { - "type": "string", - "description": "Pattern type", - "enum": ["custom", "chord", "arpeggio", "sequence"] - }, - "loop_length": { - "type": "number", - "description": "Pattern loop length in beats", - "minimum": 0.1, - "maximum": 64.0, - "default": 4.0 - } - }, - "allOf": [ - { - "if": { - "properties": { - "type": { - "const": "custom" - } - } - }, - "then": { - "properties": { - "steps": { - "type": "array", - "description": "Individual pattern steps", - "items": { - "type": "object", - "required": ["time", "note", "duration", "velocity"], - "properties": { - "time": { - "type": "number", - "description": "Time in beats when note starts", - "minimum": 0.0 - }, - "note": { - "description": "Note to play", - "oneOf": [ - { - "type": "integer", - "minimum": 0, - "maximum": 127, - "description": "MIDI note number" - }, - { - "type": "string", - "pattern": "^[A-G][#b♯♭]?[0-9]$", - "description": "Note name (e.g., 'C4', 'F#3')" - } - ] - }, - "duration": { - "type": "number", - "description": "Note duration in beats", - "minimum": 0.01, - "maximum": 16.0 - }, - "velocity": { - "type": "number", - "description": "Note velocity/volume (0.0 to 1.0)", - "minimum": 0.0, - "maximum": 1.0 - } - }, - "additionalProperties": false - } - } - }, - "required": ["steps"] - } - }, - { - "if": { - "properties": { - "type": { - "const": "chord" - } - } - }, - "then": { - "properties": { - "chord_progression": { - "type": "array", - "description": "Chord progression steps", - "items": { - "type": "object", - "required": ["time", "chord", "duration"], - "properties": { - "time": { - "type": "number", - "description": "Time in beats when chord starts", - "minimum": 0.0 - }, - "chord": { - "type": "string", - "description": "Chord name (e.g., 'Cm7', 'F', 'G#maj7')" - }, - "duration": { - "type": "number", - "description": "Chord duration in beats", - "minimum": 0.1, - "maximum": 16.0 - } - }, - "additionalProperties": false - } - }, - "voicing": { - "type": "string", - "description": "Chord voicing style", - "enum": ["close", "spread", "drop2", "drop3"], - "default": "close" - }, - "octave": { - "type": "integer", - "description": "Base octave for chord", - "minimum": 0, - "maximum": 8, - "default": 4 - } - }, - "required": ["chord_progression"] - } - } - ], - "additionalProperties": false - }, - "effects": { - "type": "array", - "description": "Audio effects to apply to this track", - "items": { - "type": "object", - "required": ["type"], - "properties": { - "type": { - "type": "string", - "description": "Effect type", - "enum": [ - "lowpass", - "highpass", - "bandpass", - "delay", - "reverb", - "chorus", - "distortion", - "compressor" - ] - } - }, - "allOf": [ - { - "if": { - "properties": { - "type": { - "const": "lowpass" - } - } - }, - "then": { - "properties": { - "cutoff": { - "type": "number", - "description": "Cutoff frequency in Hz", - "minimum": 20, - "maximum": 20000, - "default": 1000 - }, - "resonance": { - "type": "number", - "description": "Resonance factor", - "minimum": 0.1, - "maximum": 10.0, - "default": 1.0 - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": "highpass" - } - } - }, - "then": { - "properties": { - "cutoff": { - "type": "number", - "description": "Cutoff frequency in Hz", - "minimum": 20, - "maximum": 20000, - "default": 100 - }, - "resonance": { - "type": "number", - "description": "Resonance factor", - "minimum": 0.1, - "maximum": 10.0, - "default": 1.0 - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": "delay" - } - } - }, - "then": { - "properties": { - "time": { - "type": "number", - "description": "Delay time in seconds", - "minimum": 0.001, - "maximum": 2.0, - "default": 0.25 - }, - "feedback": { - "type": "number", - "description": "Feedback amount", - "minimum": 0.0, - "maximum": 0.95, - "default": 0.3 - }, - "mix": { - "type": "number", - "description": "Wet/dry mix", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.3 - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": "reverb" - } - } - }, - "then": { - "properties": { - "room_size": { - "type": "number", - "description": "Room size", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.5 - }, - "damping": { - "type": "number", - "description": "High frequency damping", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.5 - }, - "mix": { - "type": "number", - "description": "Wet/dry mix", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.3 - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": "chorus" - } - } - }, - "then": { - "properties": { - "rate": { - "type": "number", - "description": "LFO rate in Hz", - "minimum": 0.1, - "maximum": 10.0, - "default": 1.0 - }, - "depth": { - "type": "number", - "description": "Modulation depth", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.5 - }, - "layers": { - "type": "integer", - "description": "Number of chorus layers", - "minimum": 1, - "maximum": 4, - "default": 2 - }, - "mix": { - "type": "number", - "description": "Wet/dry mix", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.5 - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": "distortion" - } - } - }, - "then": { - "properties": { - "drive": { - "type": "number", - "description": "Distortion amount", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.5 - }, - "tone": { - "type": "number", - "description": "Tone control (0.0 = dark, 1.0 = bright)", - "minimum": 0.0, - "maximum": 1.0, - "default": 0.5 - } - } - } - } - ], - "additionalProperties": false - } - } - }, - "additionalProperties": false - } - }, - "sections": { - "type": "array", - "description": "Section definitions for structured compositions", - "items": { - "type": "object", - "required": ["name", "measures"], - "properties": { - "name": { - "type": "string", - "description": "Section name (e.g., 'intro', 'verse', 'chorus', 'bridge', 'outro')" - }, - "measures": { - "type": "integer", - "description": "Number of measures in this section", - "minimum": 1, - "maximum": 1000 - }, - "tempo": { - "type": "number", - "description": "Tempo override for this section", - "minimum": 40, - "maximum": 300 - }, - "key": { - "description": "Key change for this section", - "oneOf": [ - { - "type": "integer", - "minimum": 0, - "maximum": 127 - }, - { - "type": "string", - "pattern": "^[A-G][#b♯♭]?[0-9]$" - } - ] - }, - "scale": { - "type": "string", - "description": "Scale override for this section", - "enum": [ - "major", - "minor", - "dorian", - "phrygian", - "lydian", - "mixolydian", - "aeolian", - "locrian", - "pentatonic", - "blues", - "chromatic" - ] - }, - "complexity": { - "type": "number", - "description": "Complexity override for this section", - "minimum": 0.0, - "maximum": 1.0 - }, - "repeat": { - "type": "integer", - "description": "Number of times to repeat this section", - "minimum": 1, - "maximum": 100, - "default": 1 - } - }, - "additionalProperties": false - } - }, - "export": { - "type": "object", - "description": "Export settings", - "properties": { - "filename": { - "type": "string", - "description": "Output filename (without extension)", - "default": "output" - }, - "format": { - "type": "string", - "description": "Export format", - "enum": ["wav", "mp3", "flac"], - "default": "wav" - }, - "sample_rate": { - "type": "integer", - "description": "Sample rate in Hz", - "enum": [22050, 44100, 48000, 88200, 96000], - "default": 44100 - }, - "bit_depth": { - "type": "integer", - "description": "Bit depth", - "enum": [16, 24, 32], - "default": 16 - }, - "stereo": { - "type": "boolean", - "description": "Export in stereo (true) or mono (false)", - "default": false - }, - "max_duration": { - "type": "number", - "description": "Maximum duration in seconds (null for full composition)", - "minimum": 1.0, - "maximum": 3600.0 - }, - "variations": { - "type": "object", - "description": "Variation generation settings", - "properties": { - "count": { - "type": "integer", - "description": "Number of variations to generate", - "minimum": 1, - "maximum": 100 - }, - "vary_complexity": { - "type": "boolean", - "description": "Vary complexity between variations", - "default": false - }, - "vary_rhythm": { - "type": "boolean", - "description": "Vary rhythm between variations", - "default": false - }, - "vary_harmony": { - "type": "boolean", - "description": "Vary harmony between variations", - "default": false - }, - "vary_tempo": { - "type": "boolean", - "description": "Vary tempo between variations", - "default": false - } - }, - "required": ["count"], - "additionalProperties": false - } - }, - "additionalProperties": false - } - }, - "required": ["composition"], - "additionalProperties": false -} diff --git a/examples/enchanted.json b/examples/enchanted.json deleted file mode 100644 index 103ba9e..0000000 --- a/examples/enchanted.json +++ /dev/null @@ -1,697 +0,0 @@ -{ - "metadata": { - "title": "Enchanted", - "artist": "Enchanted", - "description": "A waltx in 3/4 time." - }, - "composition": { - "key": "Bb3", - "scale": "major", - "tempo": 132, - "time_signature": { - "numerator": 3, - "denominator": 4 - }, - "measures": 64, - "complexity": 0.8, - "harmony_density": 0.9, - "rhythmic_density": 0.6 - }, - "tracks": [ - { - "name": "piano_melody", - "instrument": "piano", - "volume": 0.8, - "pattern": { - "type": "custom", - "loop_length": 96.0, - "steps": [ - { - "time": 0.0, - "note": "D5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 1.5, - "note": "Eb5", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 2.5, - "note": "F5", - "duration": 0.5, - "velocity": 0.6 - }, - { - "time": 3.0, - "note": "G5", - "duration": 2.0, - "velocity": 0.7 - }, - { - "time": 5.0, - "note": "F5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 6.0, - "note": "Eb5", - "duration": 1.5, - "velocity": 0.5 - }, - { - "time": 7.5, - "note": "D5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 9.0, - "note": "C5", - "duration": 2.0, - "velocity": 0.6 - }, - { - "time": 11.0, - "note": "Bb4", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 12.0, - "note": "C5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 13.5, - "note": "D5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 14.5, - "note": "Eb5", - "duration": 0.5, - "velocity": 0.5 - }, - { - "time": 15.0, - "note": "F5", - "duration": 2.0, - "velocity": 0.7 - }, - { - "time": 17.0, - "note": "G5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 18.0, - "note": "A5", - "duration": 1.5, - "velocity": 0.7 - }, - { - "time": 19.5, - "note": "Bb5", - "duration": 1.5, - "velocity": 0.8 - }, - { - "time": 21.0, - "note": "A5", - "duration": 1.0, - "velocity": 0.7 - }, - { - "time": 22.0, - "note": "G5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 23.0, - "note": "F5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 24.0, - "note": "Eb5", - "duration": 2.0, - "velocity": 0.6 - }, - { - "time": 26.0, - "note": "D5", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 27.0, - "note": "C5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 28.5, - "note": "Bb4", - "duration": 1.5, - "velocity": 0.5 - }, - { - "time": 30.0, - "note": "C5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 31.0, - "note": "D5", - "duration": 2.0, - "velocity": 0.6 - }, - { - "time": 36.0, - "note": "G5", - "duration": 1.5, - "velocity": 0.7 - }, - { - "time": 37.5, - "note": "A5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 38.5, - "note": "Bb5", - "duration": 0.5, - "velocity": 0.7 - }, - { - "time": 39.0, - "note": "C6", - "duration": 2.0, - "velocity": 0.8 - }, - { - "time": 41.0, - "note": "Bb5", - "duration": 1.0, - "velocity": 0.7 - }, - { - "time": 42.0, - "note": "A5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 43.5, - "note": "G5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 45.0, - "note": "F5", - "duration": 2.0, - "velocity": 0.7 - }, - { - "time": 47.0, - "note": "Eb5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 48.0, - "note": "F5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 49.5, - "note": "G5", - "duration": 1.0, - "velocity": 0.7 - }, - { - "time": 50.5, - "note": "A5", - "duration": 0.5, - "velocity": 0.6 - }, - { - "time": 51.0, - "note": "Bb5", - "duration": 2.0, - "velocity": 0.8 - }, - { - "time": 53.0, - "note": "C6", - "duration": 1.0, - "velocity": 0.7 - }, - { - "time": 54.0, - "note": "D6", - "duration": 1.5, - "velocity": 0.8 - }, - { - "time": 55.5, - "note": "C6", - "duration": 1.5, - "velocity": 0.7 - }, - { - "time": 57.0, - "note": "Bb5", - "duration": 1.0, - "velocity": 0.7 - }, - { - "time": 58.0, - "note": "A5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 59.0, - "note": "G5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 60.0, - "note": "F5", - "duration": 2.0, - "velocity": 0.6 - }, - { - "time": 62.0, - "note": "Eb5", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 63.0, - "note": "D5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 64.5, - "note": "C5", - "duration": 1.5, - "velocity": 0.5 - }, - { - "time": 66.0, - "note": "Bb4", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 67.0, - "note": "C5", - "duration": 2.0, - "velocity": 0.6 - }, - { - "time": 72.0, - "note": "F5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 73.5, - "note": "G5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 74.5, - "note": "A5", - "duration": 0.5, - "velocity": 0.7 - }, - { - "time": 75.0, - "note": "Bb5", - "duration": 2.0, - "velocity": 0.7 - }, - { - "time": 77.0, - "note": "A5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 78.0, - "note": "G5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 79.5, - "note": "F5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 81.0, - "note": "Eb5", - "duration": 2.0, - "velocity": 0.6 - }, - { - "time": 83.0, - "note": "D5", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 84.0, - "note": "Eb5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 85.5, - "note": "F5", - "duration": 1.0, - "velocity": 0.6 - }, - { - "time": 86.5, - "note": "G5", - "duration": 0.5, - "velocity": 0.7 - }, - { - "time": 87.0, - "note": "A5", - "duration": 2.0, - "velocity": 0.7 - }, - { - "time": 89.0, - "note": "Bb5", - "duration": 1.0, - "velocity": 0.7 - }, - { - "time": 90.0, - "note": "G5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 91.5, - "note": "F5", - "duration": 1.5, - "velocity": 0.6 - }, - { - "time": 93.0, - "note": "Eb5", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 94.0, - "note": "D5", - "duration": 2.0, - "velocity": 0.6 - } - ] - }, - "effects": [ - { - "type": "reverb", - "room_size": 0.8, - "damping": 0.7, - "mix": 0.4 - }, - { - "type": "delay", - "time": 0.25, - "feedback": 0.15, - "mix": 0.2 - } - ] - }, - { - "name": "string_harmony", - "instrument": "sawtooth", - "volume": 0.4, - "pattern": { - "type": "chord", - "loop_length": 48.0, - "chord_progression": [ - { - "time": 0.0, - "chord": "Bb", - "duration": 6.0 - }, - { - "time": 6.0, - "chord": "F", - "duration": 6.0 - }, - { - "time": 12.0, - "chord": "Gm", - "duration": 6.0 - }, - { - "time": 18.0, - "chord": "Eb", - "duration": 6.0 - }, - { - "time": 24.0, - "chord": "Bb", - "duration": 6.0 - }, - { - "time": 30.0, - "chord": "F", - "duration": 6.0 - }, - { - "time": 36.0, - "chord": "Gm", - "duration": 6.0 - }, - { - "time": 42.0, - "chord": "Bb", - "duration": 6.0 - } - ], - "voicing": "spread", - "octave": 3 - }, - "effects": [ - { - "type": "lowpass", - "cutoff": 4000, - "resonance": 0.6 - }, - { - "type": "reverb", - "room_size": 0.9, - "damping": 0.8, - "mix": 0.6 - } - ] - }, - { - "name": "waltz_bass", - "instrument": "sine", - "volume": 0.6, - "pattern": { - "type": "custom", - "loop_length": 12.0, - "steps": [ - { - "time": 0.0, - "note": "Bb2", - "duration": 1.0, - "velocity": 0.7 - }, - { - "time": 1.0, - "note": "F2", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 2.0, - "note": "F2", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 3.0, - "note": "F2", - "duration": 1.0, - "velocity": 0.7 - }, - { - "time": 4.0, - "note": "C3", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 5.0, - "note": "C3", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 6.0, - "note": "G2", - "duration": 1.0, - "velocity": 0.7 - }, - { - "time": 7.0, - "note": "D3", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 8.0, - "note": "D3", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 9.0, - "note": "Eb2", - "duration": 1.0, - "velocity": 0.7 - }, - { - "time": 10.0, - "note": "Bb2", - "duration": 1.0, - "velocity": 0.5 - }, - { - "time": 11.0, - "note": "Bb2", - "duration": 1.0, - "velocity": 0.5 - } - ] - }, - "effects": [ - { - "type": "lowpass", - "cutoff": 2000, - "resonance": 0.8 - } - ] - }, - { - "name": "gentle_percussion", - "instrument": "triangle", - "volume": 0.25, - "pattern": { - "type": "custom", - "loop_length": 3.0, - "steps": [ - { - "time": 0.0, - "note": "C4", - "duration": 0.1, - "velocity": 0.4 - }, - { - "time": 1.0, - "note": "C4", - "duration": 0.1, - "velocity": 0.3 - }, - { - "time": 2.0, - "note": "C4", - "duration": 0.1, - "velocity": 0.3 - } - ] - }, - "effects": [ - { - "type": "highpass", - "cutoff": 2000, - "resonance": 0.5 - }, - { - "type": "reverb", - "room_size": 0.6, - "damping": 0.9, - "mix": 0.5 - } - ] - }, - { - "name": "atmospheric_pad", - "instrument": "sine", - "volume": 0.15, - "pattern": { - "type": "chord", - "loop_length": 24.0, - "chord_progression": [ - { - "time": 0.0, - "chord": "Bbmaj7", - "duration": 12.0 - }, - { - "time": 12.0, - "chord": "Gm7", - "duration": 12.0 - } - ], - "voicing": "spread", - "octave": 2 - }, - "effects": [ - { - "type": "lowpass", - "cutoff": 1500, - "resonance": 0.4 - }, - { - "type": "reverb", - "room_size": 1.0, - "damping": 0.9, - "mix": 0.8 - } - ] - } - ], - "export": { - "filename": "enchanted", - "format": "wav", - "sample_rate": 44100, - "bit_depth": 24, - "stereo": true, - "max_duration": 88.0 - } -} diff --git a/examples/fantasy.json b/examples/fantasy.json deleted file mode 100644 index 33aecbc..0000000 --- a/examples/fantasy.json +++ /dev/null @@ -1,231 +0,0 @@ -{ - "metadata": { - "title": "Fantasy", - "artist": "Atridad Lahiji", - "description": "A generic fantasy beat." - }, - "composition": { - "key": 60, - "scale": "minor", - "tempo": 85.0, - "time_signature": { - "numerator": 4, - "denominator": 4 - }, - "measures": 18 - }, - "tracks": [ - { - "name": "deep_bass", - "instrument": "sine", - "volume": 0.7, - "pattern": { - "type": "custom", - "steps": [ - { "time": 0.0, "note": "C2", "duration": 0.75, "velocity": 0.9 }, - { "time": 1.0, "note": "C2", "duration": 0.75, "velocity": 0.8 }, - { "time": 2.0, "note": "G1", "duration": 0.75, "velocity": 0.85 }, - { "time": 3.0, "note": "G1", "duration": 0.75, "velocity": 0.8 } - ], - "loop_length": 4.0 - }, - "effects": [ - { - "type": "lowpass", - "cutoff": 400.0, - "resonance": 1.8 - } - ] - }, - { - "name": "sub_bass", - "instrument": "square", - "volume": 0.5, - "pattern": { - "type": "custom", - "steps": [ - { "time": 0.5, "note": "C3", "duration": 0.25, "velocity": 0.6 }, - { "time": 1.5, "note": "Eb3", "duration": 0.25, "velocity": 0.6 }, - { "time": 2.5, "note": "G3", "duration": 0.25, "velocity": 0.6 }, - { "time": 3.5, "note": "F3", "duration": 0.25, "velocity": 0.6 } - ], - "loop_length": 4.0 - }, - "effects": [ - { - "type": "lowpass", - "cutoff": 800.0, - "resonance": 2.0 - } - ] - }, - { - "name": "lofi_kick", - "instrument": "sine", - "volume": 0.6, - "pattern": { - "type": "custom", - "steps": [ - { "time": 0.0, "note": "C1", "duration": 0.1, "velocity": 1.0 }, - { "time": 1.0, "note": "C1", "duration": 0.1, "velocity": 0.8 }, - { "time": 2.0, "note": "C1", "duration": 0.1, "velocity": 0.9 }, - { "time": 3.0, "note": "C1", "duration": 0.1, "velocity": 0.7 } - ], - "loop_length": 4.0 - }, - "effects": [ - { - "type": "lowpass", - "cutoff": 200.0, - "resonance": 1.0 - }, - { - "type": "distortion", - "drive": 0.3, - "tone": 0.2 - } - ] - }, - { - "name": "lofi_snare", - "instrument": "noise", - "volume": 0.3, - "pattern": { - "type": "custom", - "steps": [ - { "time": 1.0, "note": "E3", "duration": 0.05, "velocity": 0.7 }, - { "time": 3.0, "note": "E3", "duration": 0.05, "velocity": 0.8 } - ], - "loop_length": 4.0 - }, - "effects": [ - { - "type": "highpass", - "cutoff": 200.0, - "resonance": 1.0 - }, - { - "type": "lowpass", - "cutoff": 600.0, - "resonance": 1.5 - } - ] - }, - { - "name": "lofi_hihat", - "instrument": "noise", - "volume": 0.2, - "pattern": { - "type": "custom", - "steps": [ - { "time": 0.5, "note": "A4", "duration": 0.02, "velocity": 0.4 }, - { "time": 1.5, "note": "A4", "duration": 0.02, "velocity": 0.4 }, - { "time": 2.5, "note": "A4", "duration": 0.02, "velocity": 0.5 }, - { "time": 3.5, "note": "A4", "duration": 0.02, "velocity": 0.3 } - ], - "loop_length": 4.0 - }, - "effects": [ - { - "type": "highpass", - "cutoff": 1000.0, - "resonance": 1.0 - }, - { - "type": "lowpass", - "cutoff": 2000.0, - "resonance": 1.0 - } - ] - }, - { - "name": "warm_pad", - "instrument": "sine", - "volume": 0.2, - "pattern": { - "type": "chord", - "chord_progression": [ - { "time": 0.0, "chord": "Cm7", "duration": 4.0 }, - { "time": 4.0, "chord": "Fm7", "duration": 4.0 }, - { "time": 8.0, "chord": "Gm7", "duration": 4.0 }, - { "time": 12.0, "chord": "Cm7", "duration": 4.0 } - ], - "voicing": "spread", - "octave": 3 - }, - "effects": [ - { - "type": "lowpass", - "cutoff": 600.0, - "resonance": 1.2 - }, - { - "type": "reverb", - "room_size": 0.8, - "damping": 0.8, - "mix": 0.4 - } - ] - }, - { - "name": "peaceful_melody", - "instrument": "sine", - "volume": 0.9, - "pattern": { - "type": "custom", - "steps": [ - { "time": 16.0, "note": "Eb4", "duration": 1.0, "velocity": 0.6 }, - { "time": 17.5, "note": "G4", "duration": 1.0, "velocity": 0.5 }, - { "time": 19.0, "note": "C5", "duration": 1.5, "velocity": 0.7 }, - { "time": 21.0, "note": "Bb4", "duration": 0.75, "velocity": 0.5 }, - { "time": 22.0, "note": "Ab4", "duration": 1.0, "velocity": 0.6 }, - { "time": 23.5, "note": "F4", "duration": 0.75, "velocity": 0.5 }, - { "time": 24.0, "note": "G4", "duration": 2.0, "velocity": 0.6 }, - { "time": 26.5, "note": "Bb4", "duration": 0.75, "velocity": 0.5 }, - { "time": 27.5, "note": "D5", "duration": 1.0, "velocity": 0.7 }, - { "time": 29.0, "note": "C5", "duration": 1.5, "velocity": 0.6 }, - { "time": 31.0, "note": "G4", "duration": 1.0, "velocity": 0.5 }, - { "time": 32.5, "note": "Eb4", "duration": 1.5, "velocity": 0.6 }, - { "time": 34.5, "note": "C5", "duration": 1.0, "velocity": 0.7 }, - { "time": 36.0, "note": "G4", "duration": 2.0, "velocity": 0.5 }, - { "time": 38.5, "note": "Eb4", "duration": 1.0, "velocity": 0.4 }, - { "time": 40.0, "note": "C5", "duration": 1.5, "velocity": 0.6 }, - { "time": 42.0, "note": "Bb4", "duration": 0.75, "velocity": 0.5 }, - { "time": 43.0, "note": "Ab4", "duration": 1.0, "velocity": 0.6 }, - { "time": 44.5, "note": "F4", "duration": 1.25, "velocity": 0.5 }, - { "time": 46.0, "note": "G4", "duration": 1.0, "velocity": 0.6 }, - { "time": 47.5, "note": "Bb4", "duration": 0.75, "velocity": 0.5 }, - { "time": 48.5, "note": "D5", "duration": 1.0, "velocity": 0.7 }, - { "time": 50.0, "note": "C5", "duration": 1.5, "velocity": 0.6 }, - { "time": 52.0, "note": "G4", "duration": 1.0, "velocity": 0.5 }, - { "time": 53.5, "note": "Eb4", "duration": 1.5, "velocity": 0.6 }, - { "time": 55.5, "note": "C5", "duration": 1.0, "velocity": 0.7 }, - { "time": 57.0, "note": "G4", "duration": 2.0, "velocity": 0.5 }, - { "time": 60.0, "note": "Eb4", "duration": 1.0, "velocity": 0.4 }, - { "time": 62.0, "note": "C5", "duration": 2.0, "velocity": 0.6 }, - { "time": 65.0, "note": "G4", "duration": 2.0, "velocity": 0.5 }, - { "time": 68.0, "note": "Eb4", "duration": 4.0, "velocity": 0.4 } - ], - "loop_length": 72.0 - }, - "effects": [ - { - "type": "highpass", - "cutoff": 2000.0, - "resonance": 1.1 - }, - { - "type": "reverb", - "room_size": 0.9, - "damping": 0.7, - "mix": 0.5 - } - ] - } - ], - "export": { - "filename": "fantasy", - "format": "wav", - "stereo": true - } -} diff --git a/src/config.rs b/src/config.rs index dfa59e7..71f6b1f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -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 { } impl CompositionConfig { - /// Load configuration from a JSON file + /// Load configuration from a TOML file pub fn from_file>(path: P) -> Result { 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 { - 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 { + 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>(&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 { - 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 { + 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); } diff --git a/src/main.rs b/src/main.rs index 68491a4..efff839 100644 --- a/src/main.rs +++ b/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, - /// 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, show_example: bool, ) -> Result<(), Box> { 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(()); } diff --git a/src/sequencer.rs b/src/sequencer.rs index 229d7d8..8f6ff32 100644 --- a/src/sequencer.rs +++ b/src/sequencer.rs @@ -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)) }