///|
pub(all) struct MonoPcm {
sample_rate : Int32
samples : Array[Double]
}
///|
fn read_le(data : Bytes, at : Int32, width : Int32) -> Int64 {
let mut value = 0L
for i in 0.. Bool {
for i in 0..<4 {
if data[at + i] != tag[i] {
return false
}
}
true
}
///|
/// Decode bounded RIFF/WAVE PCM16 mono data. Unknown chunks are skipped with padding.
pub fn decode_mono_wav(data : Bytes) -> MonoPcm raise AudioError {
if data.length() < 12 ||
data.length() > 8000000 ||
!fourcc(data, 0, b"RIFF") ||
!fourcc(data, 8, b"WAVE") ||
read_le(data, 4, 4) != (data.length() - 8).to_int64() {
raise InvalidAudio
}
let mut rate = 0
let mut sample_start = -1
let mut sample_bytes = 0
let mut position = 12
while position < data.length() {
if data.length() - position < 8 {
raise InvalidAudio
}
let size = read_le(data, position + 4, 4)
let body = position + 8
let end = body.to_int64() + size + (size & 1L)
if end > data.length().to_int64() {
raise InvalidAudio
}
if fourcc(data, position, b"fmt ") {
if rate != 0 ||
size < 16L ||
read_le(data, body, 2) != 1L ||
read_le(data, body + 2, 2) != 1L ||
read_le(data, body + 12, 2) != 2L ||
read_le(data, body + 14, 2) != 16L {
raise InvalidAudio
}
let hz = read_le(data, body + 4, 4)
if hz < 1L || hz > 192000L || read_le(data, body + 8, 4) != hz * 2L {
raise InvalidAudio
}
rate = hz.to_int()
} else if fourcc(data, position, b"data") {
if sample_start != -1 ||
size == 0L ||
(size & 1L) != 0L ||
size / 2L > offline_frame_limit.to_int64() {
raise InvalidAudio
}
sample_start = body
sample_bytes = size.to_int()
}
position = end.to_int()
}
if rate == 0 || sample_start < 0 {
raise InvalidAudio
}
let samples = Array::makei(sample_bytes / 2, fn(i) {
let value = read_le(data, sample_start + 2 * i, 2).to_int()
(if value >= 32768 { value - 65536 } else { value }).to_double() / 32768.0
})
{ sample_rate: rate, samples, }
}