wav_io/
tone.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/// tone generator

use std::f32::consts::PI;

/// Tone note
#[derive(Debug)]
pub struct Note {
    pub no: i32,
    pub len: i32,
    pub vel: f32, // 0.0 - 1.0
}

/// Tone options
pub struct ToneOptions {
    pub sample_rate: u32,
    pub bpm: f32,
    pub volume: f32, // 0.0 - 1.0
}
impl ToneOptions {
    pub fn new() -> Self {
        ToneOptions {
            sample_rate: 44000,
            bpm: 120.0,
            volume: 0.9,
        }
    }
}

/// write notes
pub fn write_notes(samples: &mut Vec<f32>, notes: Vec<Note>, opt: &ToneOptions) {
    for note in notes.iter() {
        let len = (4.0 / note.len as f32 * (60.0 / opt.bpm) * opt.sample_rate as f32) as usize;
        let tone = if note.no < 0 { 0.0 } else {
            440.0 * 2.0f32.powf((note.no - 69) as f32 / 12.0)
        };
        for t in 0..len {
            let a = t as f32 / opt.sample_rate as f32;
            let v = (a * tone * 2.0 * PI).sin() * opt.volume * note.vel;
            samples.push(v);
        }
    }
}

/// write mml
pub fn write_mml(samples: &mut Vec<f32>, mml: &str, opt: &ToneOptions) {
    let notes = parse_mml(String::from(mml));
    write_notes(samples, notes, opt);
}

/// parse mml string
fn parse_mml(src: String) -> Vec<Note> {
    let mut result = vec![];
    let mut octave = 5;
    let mut length = 4;
    let mut vel = 8; // 0-9
    let mut it = src.chars();
    while let Some(ch) = it.next() {
        match ch {
            'a'..='g' => { // Note
                let note = match ch {
                    'c' => 0, 'd' => 2, 'e' => 4, 'f' => 5, 
                    'g' => 7, 'a' => 9, 'b' => 11, _ => 0,
                };
                let no = note + octave * 12;
                result.push(Note{no, len: length, vel: vel as f32 / 9.0});
            },
            'r' => result.push(Note{no: -1, len: length, vel: 0.0}), // Rest
            'o' => { // Octave
                let v = it.next().expect("should be number");
                let o = v as i32 - '0' as i32;
                if o >= 0 && o < 9 { octave = o; }
            },
            'l' => { // Length
                let v = it.next().expect("should be number");
                let l = v as i32 - '0' as i32;
                if l >= 1 && l <= 9 { length = l; }
            },
            'v' => { // Velocity
                let n = it.next().expect("should be number");
                let v = n as i32 - '0' as i32;
                if v >= 0 && v <= 9 { vel = v; }
            },
            _ => {}, // skip
        };
    }
    result
}