1use std::collections::HashMap;
2use crate::error::SynthError;
3use crate::instrument::{Instrument, InstrumentSource, SampleData, Note, Chord, SequenceElement};
4use crate::waveform::WaveformType;
5use crate::effects::{ReverbParams, DelayParams, DistortionParams, FilterParams, FilterType};
6use crate::utils::parse_note;
7
8#[derive(Debug, Clone)]
9pub struct LoopPoint {
10 pub start: f32,
11 pub end: f32,
12}
13
14#[derive(Debug, Clone)]
15pub struct MelodyTrack {
16 pub name: String,
17 pub instrument: Instrument,
18 pub sequence: Vec<SequenceElement>,
19 pub tempo: f32,
20 pub length: f32,
21 pub loop_point: Option<LoopPoint>,
22 pub time_signature: (u32, u32),
23 pub swing: f32, }
25
26impl MelodyTrack {
27 pub fn from_mel(content: &str, sample_cache: &HashMap<String, SampleData>) -> Result<Self, SynthError> {
28 let mut track = MelodyTrack {
29 name: "melody".to_string(),
30 instrument: Instrument::default(),
31 sequence: Vec::new(),
32 tempo: 120.0,
33 length: 0.0,
34 loop_point: None,
35 time_signature: (4, 4),
36 swing: 0.0,
37 };
38
39 macro_rules! parse_field {
40 ($line:expr, $prefix:expr, $field:expr) => {
41 if let Some(v) = $line.strip_prefix($prefix) {
42 $field = v.trim().parse()
43 .map_err(|_| SynthError::ParseError(format!("Invalid {}", $prefix)))?;
44 continue;
45 }
46 };
47 }
48
49 for line in content.lines() {
50 let line = line.trim();
51 if line.is_empty() || line.starts_with("//") { continue; } if let Some(v) = line.strip_prefix("name:") {
54 track.name = v.trim().to_string();
55 } else if let Some(v) = line.strip_prefix("loop:") {
56 let parts: Vec<&str> = v.split(',').map(|s| s.trim()).collect();
57 if parts.len() >= 2 {
58 track.loop_point = Some(LoopPoint {
59 start: parts[0].parse().unwrap_or(0.0),
60 end: parts[1].parse().unwrap_or(track.length),
61 });
62 }
63
64 } else if let Some(v) = line.strip_prefix("time_sig:") {
65 let parts: Vec<&str> = v.split('/').map(|s| s.trim()).collect();
66 if parts.len() >= 2 {
67 track.time_signature = (
68 parts[0].parse().unwrap_or(4),
69 parts[1].parse().unwrap_or(4),
70 );
71 }
72
73 } else if let Some(v) = line.strip_prefix("sample:") {
74 track.instrument.source = InstrumentSource::Sample(
75 sample_cache.get(v.trim())
76 .ok_or_else(|| SynthError::InvalidInstrument(format!("Sample not found: {}", v.trim())))?
77 .clone()
78 );
79
80 } else if let Some(v) = line.strip_prefix("waveform:") {
81 track.instrument.source = InstrumentSource::Synthesized(match v.trim().to_lowercase().as_str() {
82 "sine" => WaveformType::Sine,
83 "square" => WaveformType::Square,
84 "triangle" => WaveformType::Triangle,
85 "sawtooth" => WaveformType::Sawtooth,
86 "noise" => WaveformType::Noise,
87 _ => return Err(SynthError::ParseError("Unknown Waveform".to_string())),
88 });
89
90 } else if let Some(v) = line.strip_prefix("note:") {
91 let parts: Vec<&str> = v.split(',').map(|s| s.trim()).collect();
92 if parts.len() >= 3 {
93 let pitch = parse_note(parts[0])?;
94 let duration: f32 = parts[1].parse()
95 .map_err(|_| SynthError::ParseError("Invalid Duration".to_string()))?;
96 let velocity: f32 = parts[2].split("//").next().unwrap_or("0").trim().parse()
97 .map_err(|_| SynthError::ParseError("Invalid Velocity".to_string()))?;
98
99 let mut note = Note { pitch, duration, velocity, pan: None, slide_to: None };
100
101 for param in parts.iter().skip(3) {
103 if let Some((key, val)) = param.split_once('=') {
104 match key.trim() {
105 "pan" => note.pan = val.trim().parse().ok(),
106 "slide" => note.slide_to = Some(parse_note(val.trim())?),
107 _ => {}
108 }
109 }
110 }
111
112 track.sequence.push(SequenceElement::Note(note));
113 track.length += duration;
114 }
115
116 } else if let Some(v) = line.strip_prefix("chord:") { let parts: Vec<&str> = v.split(',').map(|s| s.trim()).collect();
118 if parts.len() >= 3 {
119 let notes_str = parts[0];
120 let duration: f32 = parts[1].parse()
121 .map_err(|_| SynthError::ParseError("Invalid Duration".to_string()))?;
122 let velocity: f32 = parts[2].split("//").next().unwrap_or("0").trim().parse()
123 .map_err(|_| SynthError::ParseError("Invalid Velocity".to_string()))?;
124
125 let pitches: Result<Vec<f32>, _> = notes_str
126 .split('+')
127 .map(|n| parse_note(n.trim()))
128 .collect();
129
130 track.sequence.push(SequenceElement::Chord(Chord {
131 pitches: pitches?,
132 duration,
133 velocity,
134 }));
135 track.length += duration;
136 }
137
138 } else if let Some(v) = line.strip_prefix("rest:") {
139 let duration: f32 = v.trim().parse()
140 .map_err(|_| SynthError::ParseError("Invalid rest duration".to_string()))?;
141 track.sequence.push(SequenceElement::Rest(duration));
142 track.length += duration;
143
144 } else if let Some(v) = line.strip_prefix("filter:") {
145 let parts: Vec<&str> = v.split(',').map(|s| s.trim()).collect();
146 if parts.len() >= 3 {
147 let filter_type = match parts[0].to_lowercase().as_str() {
148 "lowpass" | "lp" => FilterType::LowPass,
149 "highpass" | "hp" => FilterType::HighPass,
150 "bandpass" | "bp" => FilterType::BandPass,
151 _ => FilterType::LowPass,
152 };
153 track.instrument.effects.filter = Some(FilterParams {
154 filter_type,
155 cutoff: parts[1].parse().unwrap_or(1000.0),
156 resonance: parts[2].parse().unwrap_or(0.7),
157 });
158 }
159
160 } else if let Some(v) = line.strip_prefix("reverb:") {
161 let parts: Vec<&str> = v.split(',').map(|s| s.trim()).collect();
162 if parts.len() >= 4 {
163 track.instrument.effects.reverb = Some(ReverbParams {
164 room_size: parts[0].parse().unwrap_or(0.5),
165 damping: parts[1].parse().unwrap_or(0.5),
166 wet: parts[2].parse().unwrap_or(0.3),
167 width: parts[3].parse().unwrap_or(1.0),
168 });
169 }
170
171 } else if let Some(v) = line.strip_prefix("delay:") {
172 let parts: Vec<&str> = v.split(',').map(|s| s.trim()).collect();
173 if parts.len() >= 3 {
174 track.instrument.effects.delay = Some(DelayParams {
175 time: parts[0].parse().unwrap_or(0.25),
176 feedback: parts[1].parse().unwrap_or(0.4),
177 wet: parts[2].parse().unwrap_or(0.3),
178 });
179 }
180
181 } else if let Some(v) = line.strip_prefix("distortion:") {
182 let parts: Vec<&str> = v.split(',').map(|s| s.trim()).collect();
183 if parts.len() >= 3 {
184 track.instrument.effects.distortion = Some(DistortionParams {
185 drive: parts[0].parse().unwrap_or(2.0),
186 tone: parts[1].parse().unwrap_or(0.7),
187 wet: parts[2].parse().unwrap_or(0.5),
188 });
189 }
190
191 } else {
192 parse_field!(line, "tempo:", track.tempo);
193 parse_field!(line, "volume:", track.instrument.volume);
194 parse_field!(line, "attack:", track.instrument.attack);
195 parse_field!(line, "decay:", track.instrument.decay);
196 parse_field!(line, "sustain:", track.instrument.sustain);
197 parse_field!(line, "release:", track.instrument.release);
198 parse_field!(line, "pitch:", track.instrument.pitch);
199 parse_field!(line, "pan:", track.instrument.pan);
200 parse_field!(line, "detune:", track.instrument.detune);
201 parse_field!(line, "swing:", track.swing);
202 }
203 }
204
205 Ok(track)
206 }
207}