wav_io/
lib.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
//! # wav_io
//! Utilities for WAV files 
//! 
//! This crate can read, write, split, resample WAV files
//! 
//! # Supported format
//! - PCM 8, 16, 24, 32 bits Int
//! - PCM 32, 64 bits Float
//! 
//! # Functoins
//! - read & write
//! - resample
//! - split by silence
//! - make sine wave & MML (music macro language)
//! 
//! ## Quick Start
//! 
//! Write Wav file:
//! 
//! ```
//! use std::f32::consts::PI;
//! fn main() {
//!     // make sine wave
//!     let head = wav_io::new_mono_header();
//!     let mut samples: Vec<f32> = vec![];
//!     for t in 0..head.sample_rate {
//!         let v = ((t as f32 / head.sample_rate as f32) * 440.0 * 2.0 * PI).sin() * 0.6;
//!         samples.push(v);
//!     }
//!     // write to file
//!     let mut file_out = std::fs::File::create("./sine.wav").unwrap();
//!     wav_io::write_to_file(&mut file_out, &head, &samples).unwrap();
//! }
//! ```
//! 
//! Read Wav file:
//! 
//! ```
//! use std::fs::File;
//! use std::f32::consts::PI;
//! fn main() {
//!     // open file
//!     let file_in = File::open("./sine.wav").unwrap();
//!     // read from file
//!     let (head, samples) = wav_io::read_from_file(file_in).unwrap();
//!     // show header info
//!     println!("header={:?}", head);
//!     // show samples
//!     println!("samples.len={}", samples.len());
//!     for (i, v) in samples.iter().enumerate() {
//!         println!("{}: {}v", i, v);
//!         if (i > 32) { break; } // show first 32 samples
//!     }
//! }
//! ```
//! 
//! ## Other Example
//! ```
//! use std::fs::File;
//! use std::f32::consts::PI;
//! use wav_io::{reader, writer, utils, resample, splitter, header::*, tone};
//! fn main() {
//!     // resample
//!     let file_in = File::open("./tone.wav").unwrap();
//!     let wav = reader::from_file(file_in).unwrap();
//!     let new_sample_rate = 16_000;
//!     let mut file_out = File::create("./tone-resample.wav").unwrap();
//!     let samples2 = resample::linear(wav.samples, wav.header.channels, wav.header.sample_rate, new_sample_rate);
//!     let mut wav2 = WavData{header: wav.header, samples: samples2};
//!     wav2.header.sample_rate = new_sample_rate;
//!     writer::to_file(&mut file_out, &wav2).unwrap();
//!     
//!     // melody
//!     let mut header = WavHeader::new_mono();
//!     let mut samples = vec![];
//!     let opt = tone::ToneOptions::new();
//!     header.sample_rate = opt.sample_rate;
//!     tone::write_mml(&mut samples, "l4 cegr rdfr egrr c1", &opt);
//!     let mut file_out = File::create("./melody.wav").unwrap();
//!     writer::to_file(&mut file_out, &WavData{header, samples}).unwrap();
//! 
//!     // split
//!    let file_in = File::open("./melody.wav").unwrap();
//!    let mut wav = reader::from_file(file_in).unwrap();
//!    let mut samples = wav.samples;
//!    if wav.header.channels >= 2 {
//!        samples = utils::stereo_to_mono(samples);
//!        wav.header.channels = 1;
//!    }
//!    let range_vec = splitter::split_samples(&mut samples, wav.header.sample_rate, &splitter::WavSplitOption::new());
//!    for (i, range) in range_vec.iter().enumerate() {
//!        let fname = format!("sub-{}.wav", i);
//!        println!("split_samples={}", fname);
//!        let mut file_out = File::create(fname).unwrap();
//!        let sub = splitter::sub_samples(&samples, *range);
//!        let wav = WavData{header: wav.header.clone(), samples: sub};
//!        writer::to_file(&mut file_out, &wav).unwrap();
//!    }
//! }
//"" ```

/// Wav file header
pub mod header;
/// Wav file Reader
pub mod reader;
/// Wav file Writer
pub mod writer;
/// Wav file Resampler
pub mod resample;
/// Wav file Splitter
pub mod splitter;
/// Tone Generator
pub mod tone;
/// Utilities
pub mod utils;

use header::*;
use writer::to_bytes;

/// new mono wav header
pub fn new_mono_header() -> WavHeader {
    WavHeader::new_mono()
}
/// new stereo wav header
pub fn new_stereo_header() -> WavHeader {
    WavHeader::new_stereo()
}
/// new wav header
pub fn new_header(sample_rate:u32, bits_per_sample:u16, is_float:bool, is_mono:bool) -> WavHeader {
    let mut h = WavHeader::new_mono();
    h.sample_rate = sample_rate;
    h.bits_per_sample = bits_per_sample;
    h.sample_format = if is_float { SampleFormat::Float } else { SampleFormat::Int };
    h.channels = if is_mono { 1 } else { 2 };
    h
}

/// Read from Wav file
pub fn read_from_file(file_in: std::fs::File) -> Result<(WavHeader, Vec<f32>), reader::DecodeError> {
    match reader::from_file(file_in) {
        Ok(wd) => { Ok((wd.header, wd.samples)) },
        Err(e) => Err(e),
    }
}
/// Write to Wav file
pub fn write_to_file(file_out: &mut std::fs::File, header: &WavHeader, samples: &Vec<f32>) -> Result<(), writer::EncoderError> {
    writer::f32samples_to_file(file_out, header, samples)
}

/// Write Wav data
pub fn write_to_bytes(head: &WavHeader, samples: &Vec<f32>) -> Result<Vec<u8>, writer::EncoderError> {
    to_bytes(head, samples)
}

/// convert i16 to f32 samples
pub fn convert_samples_i16_to_f32(samples: &Vec<i16>) -> Vec<f32> {
    let mut samples_f32 = vec![];
    for v in samples {
        samples_f32.push(*v as f32 / std::i16::MAX as f32);
    }
    samples_f32
}

/// convert f32 to i16 samples
pub fn convert_samples_f32_to_i16(samples: &Vec<f32>) -> Vec<i16> {
    let mut samples_i16 = vec![];
    for v in samples {
        samples_i16.push((*v * std::i16::MAX as f32) as i16);
    }
    samples_i16
}


#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::File;
    use std::f32::consts::PI;
    
    #[test]
    fn write_tone() {
        // write tone
        let header = WavHeader::new_mono();
        let mut samples = vec![];
        for t in 0..header.sample_rate {
            let v = ((t as f32 / header.sample_rate as f32) * 440.0 * 2.0 * PI).sin() * 0.6;
            samples.push(v);
        }
        let samples_len = samples.len();
        let mut file_out = File::create("./tone.wav").unwrap();
        let sample_rate = header.sample_rate;
        writer::to_file(&mut file_out, &WavData{header, samples}).unwrap();
        assert_eq!(samples_len, sample_rate as usize);

        // melody
        let mut header = WavHeader::new_mono();
        let mut samples = vec![];
        let opt = tone::ToneOptions::new();
        header.sample_rate = opt.sample_rate;
        tone::write_mml(&mut samples, "l4 crer g1", &opt);
        let mut file_out = File::create("./melody.wav").unwrap();
        writer::to_file(&mut file_out, &WavData{header, samples}).unwrap();
    }

    #[test]
    fn read_write() {
        // path
        let wavfile = "./tone.wav";
        if !std::path::Path::new(wavfile).exists() { return; }
        // read
        let file_in = File::open(wavfile).unwrap();
        let wav = reader::from_file(file_in).unwrap();
        assert_eq!(wav.header.channels, 1); // mono
        let time_sec = wav.samples.len() as f32 / wav.header.sample_rate as f32;
        assert_eq!(time_sec, 1.0);
        // println!("header={:?}", wav.header);
        // println!("samples.len={}", wav.samples.len());
        
        // write
        let wavfile2 = "./tone2.wav";
        let mut file_out = File::create(wavfile2).unwrap();
        writer::to_file(&mut file_out, &wav).unwrap();

        // read again
        let file_in = File::open(wavfile2).unwrap();
        let wav = reader::from_file(file_in).unwrap();
        assert_eq!(wav.header.channels, 1); // mono
        let time_sec = wav.samples.len() as f32 / wav.header.sample_rate as f32;
        assert_eq!(time_sec, 1.0);
    }

    #[test]
    fn resample() {    
        let wavfile = "./tone.wav";
        let wavfile2 = "./tone-resample.wav";
        if !std::path::Path::new(wavfile).exists() { return; }
        // resample
        let file_in = File::open(wavfile).unwrap();
        let wav = reader::from_file(file_in).unwrap();
        let new_sample_rate = 16_000;
        let mut file_out = File::create(wavfile2).unwrap();
        let samples2 = resample::linear(wav.samples, wav.header.channels, wav.header.sample_rate, new_sample_rate);
        let mut wav2 = header::WavData{header: wav.header, samples: samples2};
        wav2.header.sample_rate = new_sample_rate;
        writer::to_file(&mut file_out, &wav2).unwrap();
        
        // read and test
        let file_in = File::open(wavfile2).unwrap();
        let wav = reader::from_file(file_in).unwrap();
        assert_eq!(wav.header.channels, 1); // mono
        assert_eq!(wav.header.sample_rate, new_sample_rate); // sample_rate
    }

    #[test]
    fn split() {
        // split
        let wavfile = "./melody.wav";
        // write melody
        let mut header = WavHeader::new_mono();
        let mut samples = vec![];
        let opt = tone::ToneOptions::new();
        header.sample_rate = opt.sample_rate;
        tone::write_mml(&mut samples, "l1 grrr errr c1", &opt);
        let mut file_out = File::create(wavfile).unwrap();
        writer::to_file(&mut file_out, &WavData{header, samples}).unwrap();
        // read melody
        let file_in = File::open(wavfile).unwrap();
        let mut wav = reader::from_file(file_in).unwrap();
        let mut samples = wav.samples;
        // convert to mono
        if wav.header.channels >= 2 {
            samples = utils::stereo_to_mono(samples);
            wav.header.channels = 1;
        }
        assert_eq!(samples.len() > 100, true);
        // split
        let opt = splitter::WavSplitOption::new();
        let range_vec = splitter::split_samples(&mut samples, wav.header.sample_rate, &opt);
        println!("{:?}", range_vec);
        assert_eq!(range_vec.len(), 3);
        // write to file
        for (i, range) in range_vec.iter().enumerate() {
            let fname = format!("./sub-{}.wav", i);
            println!("split_samples={}", fname);
            let mut file_out = File::create(fname).unwrap();
            let sub = splitter::sub_samples(&samples, *range);
            let wav = header::WavData{header: wav.header.clone(), samples: sub};
            writer::to_file(&mut file_out, &wav).unwrap();
        }
    }
}