1#![allow(dead_code)]
3
4extern crate alloc;
5use alloc::vec::Vec;
6
7#[derive(Debug, Clone, Copy)]
8pub struct Note {
9 pub freq: u32,
10 pub duration_ms: u32,
11}
12
13pub fn parse_mml(mml: &str) -> Vec<Note> {
15 let mut notes = Vec::new();
16 let chars: Vec<char> = mml.to_ascii_uppercase().chars().collect();
17 let mut idx = 0;
18
19 let mut tempo = 120u32;
20 let mut octave = 4i32;
21 let mut default_len = 4u32; let note_freqs = [
25 261.63f32, 277.18f32, 293.66f32, 311.13f32, 329.63f32, 349.23f32, 369.99f32, 392.00f32, 415.30f32, 440.00f32, 466.16f32, 493.88f32, ];
38
39 while idx < chars.len() {
40 let c = chars[idx];
41 if c.is_whitespace() {
42 idx += 1;
43 continue;
44 }
45
46 match c {
47 'T' => {
48 idx += 1;
49 let mut num = 0;
50 while idx < chars.len() && chars[idx].is_ascii_digit() {
51 num = num * 10 + (chars[idx] as u32 - '0' as u32);
52 idx += 1;
53 }
54 if num > 0 {
55 tempo = num;
56 }
57 }
58 'O' => {
59 idx += 1;
60 if idx < chars.len() && chars[idx].is_ascii_digit() {
61 octave = chars[idx] as i32 - '0' as i32;
62 idx += 1;
63 }
64 }
65 '>' => {
66 octave += 1;
67 if octave > 8 {
68 octave = 8;
69 }
70 idx += 1;
71 }
72 '<' => {
73 octave -= 1;
74 if octave < 1 {
75 octave = 1;
76 }
77 idx += 1;
78 }
79 'L' => {
80 idx += 1;
81 let mut num = 0;
82 while idx < chars.len() && chars[idx].is_ascii_digit() {
83 num = num * 10 + (chars[idx] as u32 - '0' as u32);
84 idx += 1;
85 }
86 if num > 0 {
87 default_len = num;
88 }
89 }
90 'C' | 'D' | 'E' | 'F' | 'G' | 'A' | 'B' | 'R' => {
91 let note_char = c;
92 idx += 1;
93
94 let mut sharp = 0i32;
96 if idx < chars.len() {
97 let next = chars[idx];
98 if next == '+' || next == '#' {
99 sharp = 1;
100 idx += 1;
101 } else if next == '-' {
102 sharp = -1;
103 idx += 1;
104 }
105 }
106
107 let mut len = 0u32;
109 while idx < chars.len() && chars[idx].is_ascii_digit() {
110 len = len * 10 + (chars[idx] as u32 - '0' as u32);
111 idx += 1;
112 }
113 let final_len = if len > 0 { len } else { default_len };
114
115 let mut has_dot = false;
117 if idx < chars.len() && chars[idx] == '.' {
118 has_dot = true;
119 idx += 1;
120 }
121
122 let mut duration = 240_000u32 / (tempo * final_len);
125 if has_dot {
126 duration = (duration * 3) / 2;
127 }
128
129 if note_char == 'R' {
130 notes.push(Note {
131 freq: 0,
132 duration_ms: duration,
133 });
134 } else {
135 let base_idx = match note_char {
136 'C' => 0,
137 'D' => 2,
138 'E' => 4,
139 'F' => 5,
140 'G' => 7,
141 'A' => 9,
142 'B' => 11,
143 _ => 0,
144 };
145
146 let mut final_idx = base_idx + sharp;
147 let mut final_octave = octave;
148 while final_idx < 0 {
149 final_idx += 12;
150 final_octave -= 1;
151 }
152 while final_idx >= 12 {
153 final_idx -= 12;
154 final_octave += 1;
155 }
156
157 final_octave = final_octave.clamp(1, 8);
158
159 let base_freq = note_freqs[final_idx as usize];
160 let freq = if final_octave >= 4 {
161 (base_freq * (1 << (final_octave - 4)) as f32) as u32
162 } else {
163 (base_freq / (1 << (4 - final_octave)) as f32) as u32
164 };
165
166 notes.push(Note {
167 freq,
168 duration_ms: duration,
169 });
170 }
171 }
172 _ => {
173 idx += 1;
175 }
176 }
177 }
178
179 notes
180}