Skip to main content

selene_daemon/player/
opened_decoder.rs

1use std::{collections::VecDeque, num::NonZero};
2
3use audioadapter_buffers::direct::InterleavedSlice;
4use lunar_lib::trace;
5use rubato::{Fft, FixedSync, Resampler, ResamplerConstructionError};
6use selene_core::{config::common::common_config, symphonia_helpers::raw_decoder::RawDecoder};
7
8use symphonia::core::{
9    audio::{Audio, AudioBuffer},
10    errors::Error as SymphoniaError,
11    formats::{SeekMode, SeekTo},
12    units::{Time, TimeBase},
13};
14
15use crate::{player::PlayerError, playlist::ResolvedTrack};
16
17pub struct OpenedDecoder {
18    pub decoded_from: ResolvedTrack,
19    gain: f64,
20
21    inner: RawDecoder,
22
23    resampler: Fft<f32>,
24    resample_buffer: VecDeque<f32>,
25
26    pub current_frame: usize,
27
28    pub at_eof: bool,
29}
30
31impl OpenedDecoder {
32    #[must_use]
33    pub fn time(&self) -> f64 {
34        let sample_rate = f64::from(self.inner.stream.codec_params.sample_rate);
35        self.current_frame as f64 / sample_rate
36    }
37
38    pub fn decode_next_packet(&mut self) -> Result<VecDeque<f32>, PlayerError> {
39        let channel_count = self.resampler.nbr_channels();
40
41        loop {
42            let next_frame_size = self.resampler.input_frames_next();
43            let Some(packet) = self.inner.decode_next_packet()? else {
44                let mut samples = self.resample_buffer.drain(..).collect::<Vec<_>>();
45
46                let needed_samples = next_frame_size * channel_count;
47                samples.resize(needed_samples, 0.0);
48
49                let buffer_in = InterleavedSlice::new(&samples, channel_count, next_frame_size)
50                    .expect("Sampler buffer contained less capacity then expected");
51
52                let resampled = self.resampler.process(&buffer_in, 0, None).expect(
53                    "Resampler expects input and output to have the same number of channels",
54                );
55
56                self.at_eof = true;
57
58                let mut data = resampled.take_data();
59                for sample in &mut data {
60                    *sample *= self.gain as f32;
61                }
62                return Ok(data.into());
63            };
64
65            let mut audio_buffer = AudioBuffer::<f32>::new(packet.spec().clone(), packet.frames());
66            audio_buffer.render_silence(Some(packet.frames()));
67            packet.copy_to(&mut audio_buffer);
68
69            self.current_frame += packet.frames();
70
71            self.resample_buffer.extend(audio_buffer.iter_interleaved());
72            let mut output = Vec::new();
73
74            while self.resample_buffer.len() >= next_frame_size * channel_count {
75                let samples: Vec<f32> = self
76                    .resample_buffer
77                    .drain(..next_frame_size * channel_count)
78                    .collect();
79
80                let buffer_in = InterleavedSlice::new(&samples, channel_count, next_frame_size)
81                    .expect("Sampler buffer contained less capacity then expected");
82
83                let resampled = self.resampler.process(&buffer_in, 0, None).expect(
84                    "Resampler expects input and output to have the same number of channels",
85                );
86
87                output.extend(resampled.take_data());
88            }
89
90            if !output.is_empty() {
91                for sample in &mut output {
92                    *sample *= self.gain as f32;
93                }
94                return Ok(output.into());
95            }
96        }
97    }
98
99    pub fn seek(&mut self, seconds: f64, increment: bool) -> Result<f64, SymphoniaError> {
100        let seconds = if increment {
101            (self.time() + seconds).max(0.0)
102        } else {
103            seconds
104        };
105
106        let timestamp = Time::try_from_secs_f64(seconds).unwrap();
107
108        let seeked_to = self.inner.format_reader.seek(
109            SeekMode::Accurate,
110            SeekTo::Time {
111                time: timestamp,
112                track_id: Some(self.inner.stream.id),
113            },
114        )?;
115
116        self.inner.decoder.reset();
117
118        let time_base = self
119            .inner
120            .stream
121            .time_base
122            .map(|(n, d)| TimeBase {
123                numer: NonZero::new(n).unwrap(),
124                denom: NonZero::new(d).unwrap(),
125            })
126            .unwrap();
127
128        let raw_time = time_base.calc_time(seeked_to.actual_ts).unwrap();
129        let time = raw_time.as_secs_f64();
130
131        let sample_rate = self.inner.stream.codec_params.sample_rate;
132        self.current_frame = (time * f64::from(sample_rate)) as usize;
133
134        Ok(time)
135    }
136}
137
138impl OpenedDecoder {
139    pub fn new(playable: ResolvedTrack, output_sample_rate: usize) -> Result<Self, PlayerError> {
140        let container = playable.track.container();
141
142        trace!(
143            "Opening a new decoder from track: '{}'",
144            container.path().display()
145        );
146
147        let inner = RawDecoder::from_container(container, 64 * 1024)?;
148
149        let resampler = new_resampler(
150            inner.stream.codec_params.sample_rate as usize,
151            output_sample_rate,
152            inner.stream.codec_params.channels,
153        )?;
154
155        let gain = playable
156            .track
157            .loudnorm_analysis()
158            .map_or(1.0, |loudnorm_analysis| {
159                let config = common_config().loudnorm;
160                let gain_db =
161                    (config.target_i - loudnorm_analysis.measured_i() - config.target_offset)
162                        .min(config.target_tp - loudnorm_analysis.measured_tp());
163                10f64.powf(gain_db / 20.0)
164            });
165
166        Ok(OpenedDecoder {
167            inner,
168            gain,
169            current_frame: 0,
170            decoded_from: playable,
171            resampler,
172            resample_buffer: VecDeque::with_capacity(1024),
173            at_eof: false,
174        })
175    }
176}
177
178fn new_resampler(
179    input_sample_rate: usize,
180    output_sample_rate: usize,
181    channel_count: usize,
182) -> Result<Fft<f32>, ResamplerConstructionError> {
183    Fft::new(
184        input_sample_rate,
185        output_sample_rate,
186        1024,
187        1,
188        channel_count,
189        FixedSync::Both,
190    )
191}