Format implementation

This commit is contained in:
Jamie Hardt
2020-12-26 13:41:08 -08:00
parent 620ca8a968
commit 3ab3a28d0e
3 changed files with 49 additions and 31 deletions

View File

@@ -10,14 +10,14 @@ Rust Wave File Reader/Writer with Broadcast-WAV, MBWF and RF64 Support
This is currently a work-in-progress! However many features presently work:
| Feature | Read | Write |
|---------------------------------------|:-----:|:-----:|
| Feature |Read |Write|
|---------------------------------------|:---:|:-----:|
| Standard .wav files | ☑️ | ☑ |
| Transparent promotion to RF64/BW64 | ☑️ | |
| Unified interface for regular and extended Wave format | ☑️ | |
| Channel/speaker map metadata | ☑️ | |
| Channel/speaker map metadata | ☑️ | ☑️ |
| Ambisonic B-format metadata | ☑️ | |
| EBU Broadcast-WAVE metadata | ☑️ | |
| EBU Broadcast-WAVE metadata | ☑️ | ☑️ |
| Basic iXML/ADM metadata | ☑️ | |
| Enhanced iXML metadata support | | |
| Broadcast-WAVE Level overview `levl` metadata | | |

View File

@@ -181,36 +181,57 @@ pub struct WaveFmt {
impl WaveFmt {
/// Create a new integer PCM format for a monoaural audio stream.
pub fn new_pcm_mono(sample_rate: u32, bits_per_sample: u16) -> Self {
Self::new_pcm_multichannel(sample_rate, bits_per_sample, 0x4)
}
/// Create a new integer PCM format `WaveFmt`
pub fn new_pcm(sample_rate: u32, bits_per_sample: u16, channel_count: u16) -> Self {
/// Create a new integer PCM format for a standard Left-Right stereo audio
/// stream.
pub fn new_pcm_stereo(sample_rate: u32, bits_per_sample: u16) -> Self {
Self::new_pcm_multichannel(sample_rate, bits_per_sample, 0x3)
}
/// Create a new integer PCM format for ambisonic b-format.
pub fn new_pcm_ambisonic(sample_rate: u32, bits_per_sample: u16, channel_count: u16) -> Self {
todo!()
}
/// Create a new integer PCM format `WaveFmt` with a custom channel bitmap.
///
/// The order of `channels` is not important. When reading or writing
/// audio frames you must use the standard multichannel order for Wave
/// files, the numerical order of the cases of `ChannelMask`.
pub fn new_pcm_multichannel(sample_rate: u32, bits_per_sample: u16, channel_bitmap: u32) -> Self {
let container_bits_per_sample = bits_per_sample + (bits_per_sample % 8);
let container_bytes_per_sample= container_bits_per_sample / 8;
let channel_count: u16 = (0..=31).fold(0u16, |accum, n| accum + (0x1 & (channel_bitmap >> n) as u16) );
let tag : u16 = match channel_count {
1..=2 => 0x01,
x if x > 2 => 0xFFFE,
x => panic!("Invalid channel count {}", x)
let result : (u16, Option<WaveFmtExtended>) = match channel_bitmap {
ch if bits_per_sample != container_bits_per_sample => (
(0xFFFE, Some(WaveFmtExtended { valid_bits_per_sample: bits_per_sample, channel_mask: ch,
type_guid: UUID_PCM }) )
),
0b0100 => (0x0001, None),
0b0011 => (0x0001, None),
ch => (
(0xFFFE, Some( WaveFmtExtended { valid_bits_per_sample: bits_per_sample, channel_mask: ch,
type_guid: UUID_PCM}))
)
};
let (tag, extformat) = result;
WaveFmt {
tag,
tag,
channel_count,
sample_rate,
bytes_per_second: container_bytes_per_sample as u32 * sample_rate * channel_count as u32,
block_alignment: container_bytes_per_sample * channel_count,
bits_per_sample: container_bits_per_sample,
extended_format: {
if channel_count > 2 {
Some( WaveFmtExtended {
channel_mask : !(0xFFFF_FFFF << channel_count),
type_guid: UUID_PCM,
valid_bits_per_sample: bits_per_sample
})
} else {
None
}
}
extended_format: extformat
}
}

View File

@@ -130,7 +130,7 @@ impl<W> Write for WaveChunkWriter<W> where W: Write + Seek {
///
/// // Write a three-sample wave file to a cursor
/// let mut cursor = Cursor::new(vec![0u8;0]);
/// let format = WaveFmt::new_pcm(48000, 24, 1);
/// let format = WaveFmt::new_pcm_mono(48000, 24);
/// let w = WaveWriter::new(&mut cursor, format).unwrap();
///
/// let mut frame_writer = w.audio_frame_writer().unwrap();
@@ -183,16 +183,13 @@ impl<W> WaveWriter<W> where W: Write + Seek {
Ok( retval )
}
/// Create a new chunk writer, which takes posession of the `WaveWriter`.
///
/// Begin writing a chunk segment. To close the chunk (and perhaps write
/// another), call `end()` on the chunk writer.
fn chunk(mut self, ident: FourCC) -> Result<WaveChunkWriter<W>,Error> {
self.inner.seek(SeekFrom::End(0))?;
WaveChunkWriter::begin(self, ident)
}
/// Write Broadcast-Wave metadata to the file.Bext
/// Write Broadcast-Wave metadata to the file.
///
/// This function will write the metadata chunk immediately; if you have
/// already written and closed the audio data the bext chunk will be
@@ -244,7 +241,7 @@ fn test_new() {
use byteorder::ReadBytesExt;
let mut cursor = Cursor::new(vec![0u8;0]);
let format = WaveFmt::new_pcm(4800, 24, 1);
let format = WaveFmt::new_pcm_mono(4800, 24);
WaveWriter::new(&mut cursor, format).unwrap();
cursor.seek(SeekFrom::Start(0)).unwrap();
@@ -270,7 +267,7 @@ fn test_write_audio() {
use byteorder::ReadBytesExt;
let mut cursor = Cursor::new(vec![0u8;0]);
let format = WaveFmt::new_pcm(48000, 24, 1);
let format = WaveFmt::new_pcm_mono(48000, 24);
let w = WaveWriter::new(&mut cursor, format).unwrap();
let mut frame_writer = w.audio_frame_writer().unwrap();
@@ -316,7 +313,7 @@ fn test_write_bext() {
use std::io::Cursor;
let mut cursor = Cursor::new(vec![0u8;0]);
let format = WaveFmt::new_pcm(48000, 24, 1);
let format = WaveFmt::new_pcm_mono(48000, 24);
let w = WaveWriter::new(&mut cursor, format).unwrap();
let bext = Bext {