Skip to main content

lavende_core/
pipeline.rs

1pub mod decoder {
2    use super::resample::LinearResampler;
3    use std::io::ErrorKind;
4    use symphonia::core::audio::SampleBuffer;
5    use symphonia::core::codecs::{CODEC_TYPE_NULL, Decoder, DecoderOptions};
6    use symphonia::core::errors::Error;
7    use symphonia::core::formats::{FormatOptions, FormatReader};
8    use symphonia::core::io::{MediaSource, MediaSourceStream};
9    use symphonia::core::meta::MetadataOptions;
10    use symphonia::core::probe::Hint;
11    pub struct AudioDecoder {
12        format: Box<dyn FormatReader>,
13        decoder: Box<dyn Decoder>,
14        track_id: u32,
15        resampler: LinearResampler,
16        sample_buf: Option<SampleBuffer<i16>>,
17        raw_buffer: Vec<i16>,
18        downmix_buf: Vec<i16>,
19    }
20    impl AudioDecoder {
21        pub fn new(source: Box<dyn MediaSource>, ext_hint: Option<&str>) -> Result<Self, String> {
22            let mss = MediaSourceStream::new(source, Default::default());
23            let mut hint = Hint::new();
24            if let Some(ext) = ext_hint {
25                hint.with_extension(ext);
26            }
27            let probed = symphonia::default::get_probe()
28                .format(
29                    &hint,
30                    mss,
31                    &FormatOptions::default(),
32                    &MetadataOptions::default(),
33                )
34                .map_err(|e| format!("Failed to probe format: {e}"))?;
35            let format = probed.format;
36            let track = format
37                .tracks()
38                .iter()
39                .find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
40                .ok_or_else(|| "No audio track found in media source".to_string())?;
41            let track_id = track.id;
42            let sample_rate = track.codec_params.sample_rate.unwrap_or(48000);
43            let decoder = symphonia::default::get_codecs()
44                .make(&track.codec_params, &DecoderOptions::default())
45                .map_err(|e| format!("Failed to create decoder: {e}"))?;
46            let resampler = LinearResampler::new(sample_rate, 48000, 2);
47            Ok(Self {
48                format,
49                decoder,
50                track_id,
51                resampler,
52                sample_buf: None,
53                raw_buffer: Vec::with_capacity(48000 * 2),
54                downmix_buf: Vec::new(),
55            })
56        }
57        pub fn read_frame(&mut self) -> Result<Option<Vec<i16>>, String> {
58            const TARGET_FRAME_SAMPLES: usize = 960 * 2;
59            while self.raw_buffer.len() < TARGET_FRAME_SAMPLES {
60                let packet = match self.format.next_packet() {
61                    Ok(p) => p,
62                    Err(Error::IoError(ref e)) if e.kind() == ErrorKind::UnexpectedEof => {
63                        break;
64                    }
65                    Err(e) => return Err(format!("Format read error: {e}")),
66                };
67                if packet.track_id() != self.track_id {
68                    continue;
69                }
70                match self.decoder.decode(&packet) {
71                    Ok(decoded) => {
72                        let spec = *decoded.spec();
73                        let mut buf = self.sample_buf.take().unwrap_or_else(|| {
74                            SampleBuffer::<i16>::new(decoded.capacity() as u64, spec)
75                        });
76                        buf.copy_interleaved_ref(decoded);
77                        let samples = buf.samples();
78                        if !samples.is_empty() {
79                            let frame_channels = spec.channels.count();
80                            let stereo_pcm = if frame_channels == 2 {
81                                samples
82                            } else {
83                                self.downmix_buf.clear();
84                                let num_frames = samples.len() / frame_channels;
85                                for i in 0..num_frames {
86                                    let frame =
87                                        &samples[i * frame_channels..(i + 1) * frame_channels];
88                                    let mut l = 0i32;
89                                    let mut r = 0i32;
90                                    for (ch, &sample) in frame.iter().enumerate() {
91                                        if ch % 2 == 0 {
92                                            l += sample as i32;
93                                        } else {
94                                            r += sample as i32;
95                                        }
96                                    }
97                                    let left_count = frame_channels.div_ceil(2);
98                                    let right_count = frame_channels / 2;
99                                    self.downmix_buf.push((l / left_count as i32) as i16);
100                                    if right_count > 0 {
101                                        self.downmix_buf.push((r / right_count as i32) as i16);
102                                    } else {
103                                        self.downmix_buf.push((l / left_count as i32) as i16);
104                                    }
105                                }
106                                &self.downmix_buf[..]
107                            };
108                            if self.resampler.is_passthrough() {
109                                self.raw_buffer.extend_from_slice(stereo_pcm);
110                            } else {
111                                self.resampler.process(stereo_pcm, &mut self.raw_buffer);
112                            }
113                        }
114                        self.sample_buf = Some(buf);
115                    }
116                    Err(Error::IoError(ref e)) if e.kind() == ErrorKind::UnexpectedEof => {
117                        break;
118                    }
119                    Err(Error::ResetRequired) => {
120                        self.decoder.reset();
121                        self.resampler.reset();
122                        self.sample_buf = None;
123                    }
124                    Err(e) => return Err(format!("Decode error: {e}")),
125                }
126            }
127            if self.raw_buffer.len() >= TARGET_FRAME_SAMPLES {
128                let frame = self.raw_buffer.drain(0..TARGET_FRAME_SAMPLES).collect();
129                Ok(Some(frame))
130            } else if !self.raw_buffer.is_empty() {
131                let mut frame = std::mem::take(&mut self.raw_buffer);
132                frame.resize(TARGET_FRAME_SAMPLES, 0);
133                Ok(Some(frame))
134            } else {
135                Ok(None)
136            }
137        }
138        pub fn seek(&mut self, position_ms: u64) -> Result<(), String> {
139            use symphonia::core::formats::{SeekMode, SeekTo};
140            use symphonia::core::units::Time;
141            let time = Time::from(position_ms as f64 / 1000.0);
142            self.format
143                .seek(
144                    SeekMode::Coarse,
145                    SeekTo::Time {
146                        time,
147                        track_id: Some(self.track_id),
148                    },
149                )
150                .map_err(|e| format!("Symphonia seek error: {e}"))?;
151            self.decoder.reset();
152            self.resampler.reset();
153            self.sample_buf = None;
154            self.raw_buffer.clear();
155            Ok(())
156        }
157    }
158}
159pub mod encoder {
160    use audiopus::{Application, Bitrate, Channels, SampleRate, coder::Encoder as OpusEncoder};
161    pub struct AudioEncoder {
162        encoder: OpusEncoder,
163    }
164    impl AudioEncoder {
165        pub fn new() -> Result<Self, String> {
166            let mut encoder =
167                OpusEncoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio)
168                    .map_err(|e| format!("Failed to create Opus encoder: {e:?}"))?;
169            encoder
170                .set_bitrate(Bitrate::Auto)
171                .map_err(|e| format!("Failed to set Opus bitrate: {e:?}"))?;
172            Ok(Self { encoder })
173        }
174        pub fn encode(&mut self, pcm: &[i16], out: &mut [u8]) -> Result<usize, String> {
175            self.encoder
176                .encode(pcm, out)
177                .map_err(|e| format!("Opus encoding failed: {e:?}"))
178        }
179    }
180}
181pub mod resample {
182    pub struct LinearResampler {
183        ratio: f32,
184        index: f32,
185        last_samples: Vec<i16>,
186        channels: usize,
187    }
188    impl LinearResampler {
189        pub fn new(source_rate: u32, target_rate: u32, channels: usize) -> Self {
190            Self {
191                ratio: source_rate as f32 / target_rate as f32,
192                index: 0.0,
193                last_samples: vec![0; channels],
194                channels,
195            }
196        }
197        pub fn process(&mut self, input: &[i16], output: &mut Vec<i16>) {
198            let num_frames = input.len() / self.channels;
199            while self.index < num_frames as f32 {
200                let idx = self.index as usize;
201                let fract = self.index.fract();
202                for c in 0..self.channels {
203                    let s1 = if idx == 0 {
204                        self.last_samples[c]
205                    } else {
206                        input[(idx - 1) * self.channels + c]
207                    } as f32;
208                    let s2 = if idx < num_frames {
209                        input[idx * self.channels + c]
210                    } else {
211                        input[(num_frames - 1) * self.channels + c]
212                    } as f32;
213                    output.push((s1 * (1.0 - fract) + s2 * fract) as i16);
214                }
215                self.index += self.ratio;
216            }
217            self.index -= num_frames as f32;
218            if num_frames > 0 {
219                for c in 0..self.channels {
220                    self.last_samples[c] = input[(num_frames - 1) * self.channels + c];
221                }
222            }
223        }
224        pub fn reset(&mut self) {
225            self.index = 0.0;
226            self.last_samples.fill(0);
227        }
228        pub fn is_passthrough(&self) -> bool {
229            (self.ratio - 1.0).abs() < f32::EPSILON
230        }
231    }
232}