1extern crate memmap;
2extern crate byteorder;
3
4pub mod error;
5
6pub use self::error::WaveError;
7
8use std::io::{Seek,SeekFrom,Cursor};
9use memmap::{Mmap,Protection};
10
11use byteorder::{LittleEndian, ReadBytesExt};
12
13const RIFF : u32 = 0x46464952;
14const WAVE : u32 = 0x45564157;
15const FMT_ : u32 = 0x20746d66;
16const DATA : u32 = 0x61746164;
17const LIST : u32 = 0x5453494c;
18const FACT : u32 = 0x74636166;
19
20const FORMAT_PCM : u16 = 1;
21const FORMAT_IEEE : u16 = 3;
22const FORMAT_EXT : u16 = 0xfffe;
23
24const SPEAKER_FRONT_LEFT : isize = (1 << 0);
25const SPEAKER_FRONT_RIGHT : isize = (1 << 1);
26const SPEAKER_FRONT_CENTER : isize = (1 << 2);
27const SPEAKER_LOW_FREQUENCY : isize = (1 << 3);
28const SPEAKER_BACK_LEFT : isize = (1 << 4);
29const SPEAKER_BACK_RIGHT : isize = (1 << 5);
30const SPEAKER_FRONT_LEFT_OF_CENTER : isize = (1 << 6);
31const SPEAKER_FRONT_RIGHT_OF_CENTER : isize = (1 << 7);
32const SPEAKER_BACK_CENTER : isize = (1 << 8);
33const SPEAKER_SIDE_LEFT : isize = (1 << 9);
34const SPEAKER_SIDE_RIGHT : isize = (1 << 10);
35const SPEAKER_TOP_CENTER : isize = (1 << 11);
36const SPEAKER_TOP_FRONT_LEFT : isize = (1 << 12);
37const SPEAKER_TOP_FRONT_CENTER : isize = (1 << 13);
38const SPEAKER_TOP_FRONT_RIGHT : isize = (1 << 14);
39const SPEAKER_TOP_BACK_LEFT : isize = (1 << 15);
40const SPEAKER_TOP_BACK_CENTER : isize = (1 << 16);
41const SPEAKER_TOP_BACK_RIGHT : isize = (1 << 17);
42const SPEAKER_RESERVED : isize = (1 << 31);
43
44#[derive(Debug,Copy,Clone,PartialEq)]
45pub enum SpeakerPosition {
46 FrontLeft = SPEAKER_FRONT_LEFT,
47 FrontRight = SPEAKER_FRONT_RIGHT,
48 FrontCenter = SPEAKER_FRONT_CENTER,
49 LowFrequency = SPEAKER_LOW_FREQUENCY,
50 BackLeft = SPEAKER_BACK_LEFT,
51 BackRight = SPEAKER_BACK_RIGHT,
52 FrontLeftOfCenter = SPEAKER_FRONT_LEFT_OF_CENTER,
53 FrontRightOfCenter = SPEAKER_FRONT_RIGHT_OF_CENTER,
54 BackCenter = SPEAKER_BACK_CENTER,
55 SideLeft = SPEAKER_SIDE_LEFT,
56 SideRight = SPEAKER_SIDE_RIGHT,
57 TopCenter = SPEAKER_TOP_CENTER,
58 TopFrontLeft = SPEAKER_TOP_FRONT_LEFT,
59 TopFrontCenter = SPEAKER_TOP_FRONT_CENTER,
60 TopFrontRight = SPEAKER_TOP_FRONT_RIGHT,
61 TopBackLeft = SPEAKER_TOP_BACK_LEFT,
62 TopBackCenter = SPEAKER_TOP_BACK_CENTER,
63 TopBackRight = SPEAKER_TOP_BACK_RIGHT,
64 Reserved = SPEAKER_RESERVED,
65}
66
67#[derive(Debug,Copy,Clone,PartialEq)]
68pub enum Format {
69 PCM = FORMAT_PCM as isize,
70 IEEEFloat = FORMAT_IEEE as isize,
71 Extended = FORMAT_EXT as isize
72}
73
74#[derive(Debug,Copy,Clone)]
78pub struct WaveInfo {
79 pub audio_format: Format,
83 pub channels: u16,
85 pub sample_rate: u32,
87 pub byte_rate: u32,
88 pub block_align: u16,
89 pub bits_per_sample: u16,
91 pub total_frames: u32,
94 pub valid_bps: Option<u16>,
95 pub channel_mask: Option<u32>,
96 pub subformat: Option<Format>
99}
100
101pub struct WaveFile {
102 mmap: Mmap,
103 data_offset: usize,
104 data_size: usize,
105 info: WaveInfo
106}
107
108pub struct WaveFileIterator<'a> {
111 file: &'a WaveFile,
112 pos: usize,
113 base: usize,
114 end: usize,
115 bytes_per_sample: usize,
116}
117
118pub type Frame = Vec<i32>;
122
123impl WaveFile {
124 pub fn open<S: Into<String>>(path: S) -> Result<WaveFile, WaveError> {
137 let filename = path.into();
138 let mmap = try!(Mmap::open_path(filename, Protection::Read));
139 let info = WaveInfo {
140 audio_format: Format::PCM,
141 channels: 0,
142 sample_rate: 0,
143 byte_rate: 0,
144 block_align: 0,
145 bits_per_sample: 0,
146 total_frames: 0,
147 valid_bps: None,
148 channel_mask: None,
149 subformat: None
150 };
151 let mut file = WaveFile { mmap: mmap, data_offset: 0, data_size: 0, info: info };
152
153 try!(file.read_header_chunks());
154
155 Ok(file)
156 }
157
158 pub fn channels(&self) -> usize {
160 self.info.channels as usize
161 }
162
163 pub fn sample_rate(&self) -> usize {
165 self.info.sample_rate as usize
166 }
167
168 pub fn len(&self) -> usize {
171 self.info.total_frames as usize
172 }
173
174 pub fn bits_per_sample(&self) -> usize {
175 self.info.bits_per_sample as usize
176 }
177
178 pub fn data_format(&self) -> Format {
179 if self.info.audio_format == Format::Extended {
180 self.info.subformat.unwrap()
181 } else {
182 self.info.audio_format
183 }
184 }
185
186 pub fn speakers(&self) -> Option<Vec<SpeakerPosition>> {
187 match self.info.channel_mask {
188 None => None,
189 Some(mask) => {
190 let mask = mask as isize;
191 let mut speakers = vec![];
192 let mut i = SPEAKER_FRONT_LEFT;
193 while i < SPEAKER_RESERVED {
194 if mask & i != 0 {
195 speakers.push(match i {
196 SPEAKER_FRONT_LEFT => SpeakerPosition::FrontLeft,
197 SPEAKER_FRONT_RIGHT => SpeakerPosition::FrontRight,
198 SPEAKER_FRONT_CENTER => SpeakerPosition::FrontCenter,
199 SPEAKER_LOW_FREQUENCY => SpeakerPosition::LowFrequency,
200 SPEAKER_BACK_LEFT => SpeakerPosition::BackLeft,
201 SPEAKER_BACK_RIGHT => SpeakerPosition::BackRight,
202 SPEAKER_FRONT_LEFT_OF_CENTER => SpeakerPosition::FrontLeftOfCenter,
203 SPEAKER_FRONT_RIGHT_OF_CENTER => SpeakerPosition::FrontRightOfCenter,
204 SPEAKER_BACK_CENTER => SpeakerPosition::BackCenter,
205 SPEAKER_SIDE_LEFT => SpeakerPosition::SideLeft,
206 SPEAKER_SIDE_RIGHT => SpeakerPosition::SideRight,
207 SPEAKER_TOP_CENTER => SpeakerPosition::TopCenter,
208 SPEAKER_TOP_FRONT_LEFT => SpeakerPosition::TopFrontLeft,
209 SPEAKER_TOP_FRONT_CENTER => SpeakerPosition::TopFrontCenter,
210 SPEAKER_TOP_FRONT_RIGHT => SpeakerPosition::TopFrontRight,
211 SPEAKER_TOP_BACK_LEFT => SpeakerPosition::TopBackLeft,
212 SPEAKER_TOP_BACK_CENTER => SpeakerPosition::TopBackCenter,
213 SPEAKER_TOP_BACK_RIGHT => SpeakerPosition::TopBackRight,
214 _ => unreachable!()
215 });
216 }
217 i <<= 1;
218 }
219 Some(speakers)
220 }
221 }
222 }
223
224 pub fn info(&self) -> WaveInfo {
227 self.info
228 }
229
230 pub fn iter(&self) -> WaveFileIterator {
245 let bytes_per_sample = self.info.bits_per_sample as usize / 8;
246 WaveFileIterator {
247 file: &self,
248 pos: 0,
249 base: self.data_offset,
250 end: self.data_offset + self.data_size,
251 bytes_per_sample: bytes_per_sample
252 }
253 }
254
255 fn read_header_chunks(&mut self) -> Result<(), WaveError> {
256 let mut cursor = Cursor::new(unsafe { self.mmap.as_slice() } );
257 let mut have_fmt = false;
258 let mut chunk_id = try!(cursor.read_u32::<LittleEndian>());
259
260 let mut chunk_size : u32;
261
262 try!(cursor.read_u32::<LittleEndian>());
263
264 let riff_type = try!(cursor.read_u32::<LittleEndian>());
265
266 if chunk_id != RIFF || riff_type != WAVE {
267 return Err(WaveError::ParseError("Not a Wavefile".into()));
268 }
269
270
271 loop {
272 chunk_id = try!(cursor.read_u32::<LittleEndian>());
273 chunk_size = try!(cursor.read_u32::<LittleEndian>());
274
275 match chunk_id {
276 FMT_ => {
277 have_fmt = true;
278 self.info.audio_format = match try!(cursor.read_u16::<LittleEndian>()) {
279 FORMAT_PCM => Format::PCM,
280 FORMAT_IEEE => Format::IEEEFloat,
281 FORMAT_EXT => Format::Extended,
282 other => {
283 let msg = format!("Unexpected format {0:x}", other);
284 return Err(WaveError::ParseError(msg));
285 }
286 };
287 self.info.channels = try!(cursor.read_u16::<LittleEndian>());
288 self.info.sample_rate = try!(cursor.read_u32::<LittleEndian>());
289 self.info.byte_rate = try!(cursor.read_u32::<LittleEndian>());
290 self.info.block_align = try!(cursor.read_u16::<LittleEndian>());
291 self.info.bits_per_sample = try!(cursor.read_u16::<LittleEndian>());
292
293 if self.info.audio_format == Format::Extended {
294 match try!(cursor.read_u16::<LittleEndian>()) {
295 0 => { },
296 22 => {
297 self.info.valid_bps = Some(try!(cursor.read_u16::<LittleEndian>()));
298 self.info.channel_mask = Some(try!(cursor.read_u32::<LittleEndian>()));
299 self.info.subformat = match try!(cursor.read_u16::<LittleEndian>()) {
300 FORMAT_PCM => Some(Format::PCM),
301 FORMAT_IEEE => Some(Format::IEEEFloat),
302 other => {
303 let msg = format!("Unexpected subformat {0:x}", other);
304 return Err(WaveError::ParseError(msg));
305 }
306 };
307 try!(cursor.seek(SeekFrom::Current(14)));
308 },
309 x => {
310 let msg = format!("Unexpected extension size: {}", x);
311 return Err(WaveError::ParseError(msg));
312 }
313 }
314
315 }
316 },
317 DATA => {
318 self.data_size = chunk_size as usize;
319 break;
320 },
321 LIST => { try!(cursor.seek(SeekFrom::Current(chunk_size as i64))); },
322 FACT => { try!(cursor.seek(SeekFrom::Current(chunk_size as i64))); },
323 other => {
324 let msg = format!("Unexpected Chunk ID {0:x}", other);
325 return Err(WaveError::ParseError(msg));
326 }
327 }
328 }
329
330 if !have_fmt {
331 return Err(WaveError::ParseError("Format Chunk not found".into()));
332 }
333
334 if self.info.channels == 0 || self.info.bits_per_sample < 8 {
335 let msg = format!("Invalid channel count {} or bits per sample {} value",
336 self.info.channels, self.info.bits_per_sample);
337
338 return Err(WaveError::ParseError(msg));
339 }
340
341 self.info.total_frames = self.data_size as u32 / (self.info.channels as u32 * self.info.bits_per_sample as u32 / 8 );
342
343 self.data_offset = cursor.position() as usize;
344 Ok(())
345 }
346}
347
348impl<'a> Iterator for WaveFileIterator<'a> {
349 type Item = Frame;
350
351 fn next(&mut self) -> Option<Self::Item> {
352 let mut cursor = Cursor::new(unsafe { self.file.mmap.as_slice() });
353
354 if let Err(_) = cursor.seek(SeekFrom::Start((self.base + self.pos) as u64)) {
355 return None;
356 };
357
358 if cursor.position() as usize == self.end {
359 return None;
360 }
361
362 let (frame, new_pos) = match self.file.data_format() {
363 Format::PCM => WaveFileIterator::next_pcm(&mut cursor,
364 self.file.channels(),
365 self.bytes_per_sample),
366 Format::IEEEFloat => WaveFileIterator::next_float(&mut cursor,
367 self.file.channels(),
368 self.bytes_per_sample),
369 _ => unreachable!()
370 };
371
372 self.pos = new_pos - self.base;
373
374
375 Some(frame)
376 }
377}
378
379impl<'a> WaveFileIterator<'a> {
380 fn next_pcm(cursor: &mut Cursor<&[u8]>, channels: usize, bps: usize) -> (Frame, usize) {
381 let mut samples : Vec<i32> = Vec::with_capacity(channels);
382
383 for _ in 0..channels {
384 match cursor.read_int::<LittleEndian>(bps) {
385 Ok(sample) => samples.push(sample as i32),
386 Err(e) => { panic!("{:?}", e); }
387 }
388 }
389
390 (samples, cursor.position() as usize)
391 }
392
393 fn next_float(cursor: &mut Cursor<&[u8]>, channels: usize, bps: usize) -> (Frame, usize) {
394 if bps != 4 {
395 panic!("Can't handle the specified bytes per sample");
396 }
397
398 let mut samples : Vec<i32> = Vec::with_capacity(channels);
399
400 for _ in 0..channels {
401 match cursor.read_f32::<LittleEndian>() {
402 Ok(sample) => {
403 let scaled = (sample * 2147483647.0) as i32;
404 samples.push(scaled);
405 },
406 Err(e) => { panic!("{:?}", e); }
407 }
408 }
409
410 (samples, cursor.position() as usize)
411 }
412
413}
414
415#[test]
416fn test_info() {
417 let file = match WaveFile::open("./fixtures/test-s24le.wav") {
418 Ok(f) => f,
419 Err(e) => panic!("Error: {:?}", e)
420 };
421 let info = file.info();
422
423 assert_eq!(info.audio_format, Format::PCM);
424 assert_eq!(info.channels, 2);
425 assert_eq!(info.sample_rate, 48000);
426 assert_eq!(info.byte_rate, 288000);
427 assert_eq!(info.block_align, 6);
428 assert_eq!(info.bits_per_sample, 24);
429 assert_eq!(info.total_frames, 501888);
430
431 let file = match WaveFile::open("./fixtures/test-u8.wav") {
432 Ok(f) => f,
433 Err(e) => panic!("Error: {:?}", e)
434 };
435 let info = file.info();
436
437 assert_eq!(info.audio_format, Format::PCM);
438 assert_eq!(info.channels, 2);
439 assert_eq!(info.sample_rate, 48000);
440 assert_eq!(info.byte_rate, 96000);
441 assert_eq!(info.bits_per_sample, 8);
442 assert_eq!(info.block_align, 2);
443 assert_eq!(info.total_frames, 501888);
444}
445
446#[test]
447fn test_iter() {
448 let file = match WaveFile::open("./fixtures/test-s24le.wav") {
449 Ok(f) => f,
450 Err(e) => panic!("Error: {:?}", e)
451 };
452
453 let frames = file.iter().take(2).collect::<Vec<_>>();
454 let expected = vec![
455 [19581, 19581],
456 [24337, 24337]
457 ];
458
459 for i in 0..expected.len() {
460 assert_eq!(frames[i], expected[i]);
461 }
462
463 let frame = file.iter().last().unwrap();
464 let expected = [244, 244];
465
466 assert_eq!(frame, expected)
467}
468
469
470#[test]
471fn test_float_extended() {
472 let file = WaveFile::open("./fixtures/test-f32le.wav").unwrap();
473 let info = file.info();
474
475 assert_eq!(info.audio_format, Format::Extended);
476 assert_eq!(file.data_format(), Format::IEEEFloat);
477 assert_eq!(file.len(), 501888);
478
479 let frames = file.iter().take(2).collect::<Vec<_>>();
480 let expected = vec![
483 [5012736, 5012736],
484 [6230272, 6230272]
485 ];
486
487 for i in 0..expected.len() {
488 assert_eq!(frames[i], expected[i]);
489 }
490
491 assert_eq!(file.speakers().unwrap(),
492 [SpeakerPosition::FrontLeft, SpeakerPosition::FrontRight]);
493}