wavefile/
lib.rs

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/// Contains information included in the wavefile's header section,
75/// describing the format, sample size, and number of audio channels
76/// present.
77#[derive(Debug,Copy,Clone)]
78pub struct WaveInfo {
79  /// Which encoding format this file uses.
80  /// If the format is `Format::Extended`, then the actual audio format is
81  /// instead determined by the `subformat` field.
82  pub audio_format:    Format,
83  /// Number of distinct audio channels.
84  pub channels:        u16,
85  /// Number of audio samples per second.
86  pub sample_rate:     u32,
87  pub byte_rate:       u32,
88  pub block_align:     u16,
89  /// Number of bits used to represent each sample.
90  pub bits_per_sample: u16,
91  /// Number of frames present in the file.  Each frame contains one sample per
92  /// channel.
93  pub total_frames:    u32,
94  pub valid_bps:       Option<u16>,
95  pub channel_mask:    Option<u32>,
96  /// For `Format::Extended` files, this field contains the actual audo encoding
97  /// of the file, either `Format::PCM` or `Format::IEEEFloat`.
98  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
108/// An iterator which yields successive `Frames` of audio from the associated
109/// wavefile.
110pub struct WaveFileIterator<'a> {
111  file:             &'a WaveFile,
112  pos:              usize,
113  base:             usize,
114  end:              usize,
115  bytes_per_sample: usize,
116}
117
118/// Represents a single frame of audio, containing one sample per audio channel.
119/// For example, a mono audio file will contain only one sample; a stereo file
120/// will contain two.
121pub type Frame = Vec<i32>;
122
123impl WaveFile {
124  /// Constructs a new `WaveFile`.
125  ///
126  /// # Example
127  ///
128  /// ```
129  /// use wavefile::{WaveFile,WaveError};
130  ///
131  /// match WaveFile::open("./fixtures/test-s24le.wav") {
132  ///   Ok(f)  => f,
133  ///   Err(e) => panic!("Couldn't open example file: {}", e)
134  /// };
135  /// ```
136  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  /// The number of audio channels in the file.
159  pub fn channels(&self) -> usize {
160    self.info.channels as usize
161  }
162
163  /// The number of samples present for one second of audio.
164  pub fn sample_rate(&self) -> usize {
165    self.info.sample_rate as usize
166  }
167
168  /// The total number of frames present in the file.
169  /// Each frame will contain `channels()` number of samples.
170  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  /// Returns a copy of the `WaveInfo` for this file,
225  /// parsed from the file header.
226  pub fn info(&self) -> WaveInfo {
227    self.info
228  }
229
230  /// Returns an iterator which yields each individual `Frame` successively
231  /// until it reaches the end of the file.
232  ///
233  /// # Example
234  ///
235  /// ```no_run
236  /// use wavefile::WaveFile;
237  ///
238  /// let wav = WaveFile::open("./fixtures/test-s24le.wav").unwrap();
239  ///
240  /// for frame in wav.iter() {
241  ///   println!("{:?}", frame);
242  /// }
243  /// ```
244  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  // these are the same values as the 24-bit samples,
481  // however we've scaled to 32-bit.
482  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}