Skip to content

Commit 8c8b1c4

Browse files
author
dedobbin
committed
wav: support more sample sizes
1 parent ebb5ea4 commit 8c8b1c4

File tree

2 files changed

+21
-17
lines changed

2 files changed

+21
-17
lines changed

symphonia-codec-pcm/src/lib.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ use symphonia_core::io::ReadBytes;
3939
use symphonia_core::sample::{i24, u24, SampleFormat};
4040
use symphonia_core::units::Duration;
4141

42-
use std::mem;
43-
4442
macro_rules! impl_generic_audio_buffer_func {
4543
($generic:expr, $buf:ident, $expr:expr) => {
4644
match $generic {
@@ -124,11 +122,16 @@ macro_rules! read_pcm_signed_be {
124122
// Get buffer of the correct sample format.
125123
match $buf {
126124
GenericAudioBuffer::$fmt(ref mut buf) => {
127-
let sample_size = mem::size_of_val(&$read) * 8;
128-
let mask = !0 << (sample_size as u32 - $coded_width);
129125
buf.fill(|audio_planes, idx| -> Result<()> {
130126
for plane in audio_planes.planes() {
131-
plane[idx] = ($read & mask).into_sample();
127+
// To properly read a a sample with a shorter coded width,
128+
// it should be masked using (1 << ($width - $coded_width)) - 1, masking out rightmost bits.
129+
// ffpmeg seems to not do this, at least in the case for 12bit aiff PCM.
130+
// If the aiff file is offspec, by not setting padded out bits to 0,
131+
// this will fail when verifying with ffmpeg
132+
// To comply with, we will not mask the sample.
133+
// It should not make a hearable difference anyway.
134+
plane[idx] = ($read).into_sample();
132135
}
133136
Ok(())
134137
})
@@ -162,11 +165,16 @@ macro_rules! read_pcm_unsigned_be {
162165
// Get buffer of the correct sample format.
163166
match $buf {
164167
GenericAudioBuffer::$fmt(ref mut buf) => {
165-
let sample_size = mem::size_of_val(&$read) * 8;
166-
let mask = !0 << (sample_size as u32 - $coded_width);
167168
buf.fill(|audio_planes, idx| -> Result<()> {
168169
for plane in audio_planes.planes() {
169-
plane[idx] = ($read & mask).into_sample();
170+
// To properly read a a sample with a shorter coded width,
171+
// it should be masked using (1 << ($width - $coded_width)) - 1, masking out rightmost bits.
172+
// ffpmeg seems to not do this, at least in the case for 12bit aiff PCM.
173+
// If the aiff file is offspec, by not setting padded out bits to 0,
174+
// this will fail when verifying with ffmpeg
175+
// To comply with, we will not mask the sample.
176+
// It should not make a hearable difference anyway.
177+
plane[idx] = ($read).into_sample();
170178
}
171179
Ok(())
172180
})

symphonia-format-riff/src/wave/chunks.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,11 @@ impl WaveFormatChunk {
7878
// Select the appropriate codec using bits per sample. Samples are always interleaved and
7979
// little-endian encoded for the PCM format.
8080
let codec = match bits_per_sample {
81-
8 => CODEC_TYPE_PCM_U8,
82-
16 => CODEC_TYPE_PCM_S16LE,
83-
24 => CODEC_TYPE_PCM_S24LE,
84-
32 => CODEC_TYPE_PCM_S32LE,
85-
_ => {
86-
return decode_error(
87-
"wav: bits per sample for fmt_pcm must be 8, 16, 24 or 32 bits",
88-
)
89-
}
81+
1..=8 => CODEC_TYPE_PCM_U8,
82+
9..=16 => CODEC_TYPE_PCM_S16LE,
83+
17..=24 => CODEC_TYPE_PCM_S24LE,
84+
25..=32 => CODEC_TYPE_PCM_S32LE,
85+
_ => return decode_error("wav: bits per sample unsupported for pcm"),
9086
};
9187

9288
let channels = try_channel_count_to_mask(n_channels)?;

0 commit comments

Comments
 (0)