1use anyhow::{anyhow, Result};
8use std::io::{Read, Seek};
9
10#[derive(Debug, Clone)]
11pub struct Pcm16 {
12 pub channels: u16,
14 pub sample_rate: u32,
16 pub samples: Vec<i16>,
18}
19
20pub fn decode_ogg_vorbis_reader<T: Read + Seek>(rdr: T) -> Result<Pcm16> {
26 use lewton::inside_ogg::OggStreamReader;
27
28 let mut r = OggStreamReader::new(rdr)
29 .map_err(|e| anyhow!("ogg/vorbis: failed to parse headers: {e}"))?;
30
31 let channels = r.ident_hdr.audio_channels as u16;
32 let sample_rate = r.ident_hdr.audio_sample_rate;
33
34 let mut samples = Vec::<i16>::new();
35 while let Some(pkt) = r
36 .read_dec_packet_itl()
37 .map_err(|e| anyhow!("ogg/vorbis: decode error: {e}"))?
38 {
39 samples.extend_from_slice(&pkt);
40 }
41
42 Ok(Pcm16 {
43 channels,
44 sample_rate,
45 samples,
46 })
47}
48
49pub fn decode_ogg_vorbis_bytes(data: &[u8]) -> Result<Pcm16> {
51 decode_ogg_vorbis_reader(std::io::Cursor::new(data))
52}
53
54pub fn pcm16_to_wav_bytes(pcm: &Pcm16) -> Vec<u8> {
58 let num_channels = pcm.channels as u16;
60 let sample_rate = pcm.sample_rate as u32;
61 let bits_per_sample: u16 = 16;
62 let block_align: u16 = num_channels.saturating_mul(bits_per_sample / 8);
63 let byte_rate: u32 = sample_rate.saturating_mul(block_align as u32);
64
65 let data_bytes_len: u32 = (pcm.samples.len() * 2) as u32;
66 let riff_size: u32 = 36u32.saturating_add(data_bytes_len);
67
68 let mut out = Vec::with_capacity(44 + data_bytes_len as usize);
69
70 out.extend_from_slice(b"RIFF");
72 out.extend_from_slice(&riff_size.to_le_bytes());
73 out.extend_from_slice(b"WAVE");
74
75 out.extend_from_slice(b"fmt ");
77 out.extend_from_slice(&16u32.to_le_bytes()); out.extend_from_slice(&1u16.to_le_bytes()); out.extend_from_slice(&num_channels.to_le_bytes());
80 out.extend_from_slice(&sample_rate.to_le_bytes());
81 out.extend_from_slice(&byte_rate.to_le_bytes());
82 out.extend_from_slice(&block_align.to_le_bytes());
83 out.extend_from_slice(&bits_per_sample.to_le_bytes());
84
85 out.extend_from_slice(b"data");
87 out.extend_from_slice(&data_bytes_len.to_le_bytes());
88
89 for s in &pcm.samples {
91 out.extend_from_slice(&s.to_le_bytes());
92 }
93
94 out
95}
96
97pub fn decode_ogg_vorbis_bytes_to_wav(data: &[u8]) -> Result<Vec<u8>> {
99 let pcm = decode_ogg_vorbis_bytes(data)?;
100 Ok(pcm16_to_wav_bytes(&pcm))
101}
102
103pub fn decode_ogg_vorbis_reader_to_wav<T: Read + Seek>(rdr: T) -> Result<Vec<u8>> {
105 let pcm = decode_ogg_vorbis_reader(rdr)?;
106 Ok(pcm16_to_wav_bytes(&pcm))
107}