Skip to content

Commit 6cab8aa

Browse files
committed
WavPack: Stop overwriting custom sample rates
When a custom sample rate (or multiplier) was encountered, it would accidentally be overwritten with 0, causing incorrect duration and bitrate values. This was due to us reading the metadata sub blocks first (when necessary) and then immediately overwriting the sample rate with the value from the block header (which is 0 in the presence of a custom sample rate).
1 parent 5eb032a commit 6cab8aa

File tree

2 files changed

+27
-21
lines changed

2 files changed

+27
-21
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2828
to encounter in the wild. Now we will just tag whichever tag happens to be latest in the stream and
2929
use it, they **will not be merged**.
3030

31+
## Fixed
32+
- **WavPack**: Custom sample rates will no longer be overwritten
33+
- When a custom sample rate (or multiplier) was encountered, it would accidentally be overwritten with 0, causing
34+
incorrect duration and bitrate values.
35+
3136
## [0.15.0] - 2023-07-11
3237

3338
## Added

src/wavpack/properties.rs

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -131,22 +131,24 @@ where
131131
let block_header;
132132
match parse_wv_header(reader) {
133133
Ok(header) => block_header = header,
134+
Err(e) if parse_mode == ParsingMode::Strict => return Err(e),
134135
_ => break,
135136
}
136137

137138
let flags = block_header.flags;
138139
let sample_rate_idx = ((flags >> 23) & 0xF) as usize;
140+
properties.sample_rate = SAMPLE_RATES[sample_rate_idx];
139141

140142
// In the case of non-standard sample rates and DSD audio, we need to actually read the
141143
// block to get the sample rate
142-
if properties.sample_rate == 0 || flags & FLAG_DSD == FLAG_DSD {
144+
if sample_rate_idx == 15 || flags & FLAG_DSD == FLAG_DSD {
143145
let mut block_contents = try_vec![0; (block_header.block_size - 24) as usize];
144146
if reader.read_exact(&mut block_contents).is_err() {
145147
parse_mode_choice!(
146-
parse_mode,
147-
STRICT: decode_err!(@BAIL WavPack, "Block size mismatch"),
148-
DEFAULT: break
149-
);
148+
parse_mode,
149+
STRICT: decode_err!(@BAIL WavPack, "Block size mismatch"),
150+
DEFAULT: break
151+
);
150152
}
151153

152154
if let Err(e) = get_extended_meta_info(parse_mode, &block_contents, &mut properties)
@@ -183,9 +185,6 @@ where
183185
total_samples = block_header.total_samples;
184186
properties.bit_depth = ((((flags & BYTES_PER_SAMPLE_MASK) + 1) * 8) - ((flags & BIT_DEPTH_SHIFT_MASK) >> BIT_DEPTH_SHL)) as u8;
185187

186-
let sample_rate = SAMPLE_RATES[sample_rate_idx];
187-
properties.sample_rate = sample_rate;
188-
189188
properties.version = block_header.version;
190189
properties.lossless = flags & FLAG_HYBRID_COMPRESSION == 0;
191190

@@ -216,20 +215,22 @@ where
216215
offset += u64::from(block_header.block_size + 8);
217216
}
218217

219-
if total_samples > 0 && properties.sample_rate > 0 {
220-
let length = f64::from(total_samples) * 1000. / f64::from(properties.sample_rate);
221-
properties.duration = Duration::from_millis((length + 0.5) as u64);
222-
properties.audio_bitrate = (stream_length as f64 * 8. / length + 0.5) as u32;
223-
224-
let file_length = reader.seek(SeekFrom::End(0))?;
225-
properties.overall_bitrate = (file_length as f64 * 8. / length + 0.5) as u32;
226-
} else {
227-
parse_mode_choice!(
228-
parse_mode,
229-
STRICT: decode_err!(@BAIL WavPack, "Unable to calculate duration (sample count == 0 || sample rate == 0)"),
230-
);
218+
if total_samples == 0 || properties.sample_rate == 0 {
219+
if parse_mode == ParsingMode::Strict {
220+
decode_err!(@BAIL WavPack, "Unable to calculate duration (sample count == 0 || sample rate == 0)")
221+
}
222+
223+
// We aren't able to determine the duration/bitrate, just early return
224+
return Ok(properties);
231225
}
232226

227+
let length = f64::from(total_samples) * 1000. / f64::from(properties.sample_rate);
228+
properties.duration = Duration::from_millis((length + 0.5) as u64);
229+
properties.audio_bitrate = (stream_length as f64 * 8. / length + 0.5) as u32;
230+
231+
let file_length = reader.seek(SeekFrom::End(0))?;
232+
properties.overall_bitrate = (file_length as f64 * 8. / length + 0.5) as u32;
233+
233234
Ok(properties)
234235
}
235236

@@ -245,7 +246,7 @@ struct WVHeader {
245246
flags: u32,
246247
}
247248

248-
// TODO: for now, all errors are just discarded
249+
// NOTE: Any error here is ignored unless using `ParsingMode::Strict`
249250
fn parse_wv_header<R>(reader: &mut R) -> Result<WVHeader>
250251
where
251252
R: Read + Seek,

0 commit comments

Comments
 (0)