mirror of
https://github.com/iluvcapra/bwavfile.git
synced 2026-01-02 09:50:44 +00:00
Format implementation
This commit is contained in:
@@ -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:
|
This is currently a work-in-progress! However many features presently work:
|
||||||
|
|
||||||
| Feature | Read | Write |
|
| Feature |Read |Write|
|
||||||
|---------------------------------------|:-----:|:-----:|
|
|---------------------------------------|:---:|:-----:|
|
||||||
| Standard .wav files | ☑️ | ☑ ️ |
|
| Standard .wav files | ☑️ | ☑ ️ |
|
||||||
| Transparent promotion to RF64/BW64 | ☑️ | |
|
| Transparent promotion to RF64/BW64 | ☑️ | |
|
||||||
| Unified interface for regular and extended Wave format | ☑️ | |
|
| Unified interface for regular and extended Wave format | ☑️ | |
|
||||||
| Channel/speaker map metadata | ☑️ | |
|
| Channel/speaker map metadata | ☑️ | ☑️ |
|
||||||
| Ambisonic B-format metadata | ☑️ | |
|
| Ambisonic B-format metadata | ☑️ | |
|
||||||
| EBU Broadcast-WAVE metadata | ☑️ | |
|
| EBU Broadcast-WAVE metadata | ☑️ | ☑️ |
|
||||||
| Basic iXML/ADM metadata | ☑️ | |
|
| Basic iXML/ADM metadata | ☑️ | |
|
||||||
| Enhanced iXML metadata support | | |
|
| Enhanced iXML metadata support | | |
|
||||||
| Broadcast-WAVE Level overview `levl` metadata | | |
|
| Broadcast-WAVE Level overview `levl` metadata | | |
|
||||||
|
|||||||
55
src/fmt.rs
55
src/fmt.rs
@@ -182,17 +182,48 @@ pub struct WaveFmt {
|
|||||||
|
|
||||||
impl WaveFmt {
|
impl WaveFmt {
|
||||||
|
|
||||||
/// Create a new integer PCM format `WaveFmt`
|
/// Create a new integer PCM format for a monoaural audio stream.
|
||||||
pub fn new_pcm(sample_rate: u32, bits_per_sample: u16, channel_count: u16) -> Self {
|
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 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_bits_per_sample = bits_per_sample + (bits_per_sample % 8);
|
||||||
let container_bytes_per_sample= container_bits_per_sample / 8;
|
let container_bytes_per_sample= container_bits_per_sample / 8;
|
||||||
|
|
||||||
let tag : u16 = match channel_count {
|
let channel_count: u16 = (0..=31).fold(0u16, |accum, n| accum + (0x1 & (channel_bitmap >> n) as u16) );
|
||||||
1..=2 => 0x01,
|
|
||||||
x if x > 2 => 0xFFFE,
|
let result : (u16, Option<WaveFmtExtended>) = match channel_bitmap {
|
||||||
x => panic!("Invalid channel count {}", x)
|
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 {
|
WaveFmt {
|
||||||
tag,
|
tag,
|
||||||
channel_count,
|
channel_count,
|
||||||
@@ -200,17 +231,7 @@ impl WaveFmt {
|
|||||||
bytes_per_second: container_bytes_per_sample as u32 * sample_rate * channel_count as u32,
|
bytes_per_second: container_bytes_per_sample as u32 * sample_rate * channel_count as u32,
|
||||||
block_alignment: container_bytes_per_sample * channel_count,
|
block_alignment: container_bytes_per_sample * channel_count,
|
||||||
bits_per_sample: container_bits_per_sample,
|
bits_per_sample: container_bits_per_sample,
|
||||||
extended_format: {
|
extended_format: extformat
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ impl<W> Write for WaveChunkWriter<W> where W: Write + Seek {
|
|||||||
///
|
///
|
||||||
/// // Write a three-sample wave file to a cursor
|
/// // Write a three-sample wave file to a cursor
|
||||||
/// let mut cursor = Cursor::new(vec![0u8;0]);
|
/// 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 w = WaveWriter::new(&mut cursor, format).unwrap();
|
||||||
///
|
///
|
||||||
/// let mut frame_writer = w.audio_frame_writer().unwrap();
|
/// let mut frame_writer = w.audio_frame_writer().unwrap();
|
||||||
@@ -183,16 +183,13 @@ impl<W> WaveWriter<W> where W: Write + Seek {
|
|||||||
Ok( retval )
|
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> {
|
fn chunk(mut self, ident: FourCC) -> Result<WaveChunkWriter<W>,Error> {
|
||||||
self.inner.seek(SeekFrom::End(0))?;
|
self.inner.seek(SeekFrom::End(0))?;
|
||||||
WaveChunkWriter::begin(self, ident)
|
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
|
/// This function will write the metadata chunk immediately; if you have
|
||||||
/// already written and closed the audio data the bext chunk will be
|
/// already written and closed the audio data the bext chunk will be
|
||||||
@@ -244,7 +241,7 @@ fn test_new() {
|
|||||||
use byteorder::ReadBytesExt;
|
use byteorder::ReadBytesExt;
|
||||||
|
|
||||||
let mut cursor = Cursor::new(vec![0u8;0]);
|
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();
|
WaveWriter::new(&mut cursor, format).unwrap();
|
||||||
|
|
||||||
cursor.seek(SeekFrom::Start(0)).unwrap();
|
cursor.seek(SeekFrom::Start(0)).unwrap();
|
||||||
@@ -270,7 +267,7 @@ fn test_write_audio() {
|
|||||||
use byteorder::ReadBytesExt;
|
use byteorder::ReadBytesExt;
|
||||||
|
|
||||||
let mut cursor = Cursor::new(vec![0u8;0]);
|
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 w = WaveWriter::new(&mut cursor, format).unwrap();
|
||||||
|
|
||||||
let mut frame_writer = w.audio_frame_writer().unwrap();
|
let mut frame_writer = w.audio_frame_writer().unwrap();
|
||||||
@@ -316,7 +313,7 @@ fn test_write_bext() {
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
let mut cursor = Cursor::new(vec![0u8;0]);
|
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 w = WaveWriter::new(&mut cursor, format).unwrap();
|
||||||
|
|
||||||
let bext = Bext {
|
let bext = Bext {
|
||||||
|
|||||||
Reference in New Issue
Block a user