selene_daemon/player/
opened_decoder.rs1use 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}