1#![recursion_limit = "2048"]
2#![allow(clippy::should_implement_trait, clippy::unnecessary_to_owned)]
3use cpal::{
4 traits::{HostTrait, StreamTrait},
5 BuildStreamError, Stream, StreamConfig,
6};
7use gonk_database::{Index, Song};
8use std::{
9 fs::File,
10 io::ErrorKind,
11 sync::{Arc, RwLock},
12 time::Duration,
13 vec::IntoIter,
14};
15use symphonia::{
16 core::{
17 audio::SampleBuffer,
18 codecs::{Decoder, DecoderOptions},
19 errors::{Error, SeekErrorKind},
20 formats::{FormatOptions, SeekMode, SeekTo},
21 io::MediaSourceStream,
22 meta::MetadataOptions,
23 probe::{Hint, ProbeResult},
24 units::{Time, TimeBase},
25 },
26 default::get_probe,
27};
28
29pub use cpal::{traits::DeviceTrait, Device};
30
31mod cpal;
32
33#[inline]
34const fn gcd(a: usize, b: usize) -> usize {
35 if b == 0 {
36 a
37 } else {
38 gcd(b, a % b)
39 }
40}
41
42#[inline]
43fn lerp(a: f32, b: f32, t: f32) -> f32 {
44 a + t * (b - a)
45}
46
47const VOLUME_STEP: u8 = 5;
48const VOLUME_REDUCTION: f32 = 500.0;
49const MAX_DECODE_ERRORS: usize = 3;
50
51pub struct Resampler {
52 probed: ProbeResult,
53 decoder: Box<dyn Decoder>,
54
55 input_real: usize,
56 input: usize,
57 output: usize,
58
59 buffer: IntoIter<f32>,
60
61 current_frame: Vec<f32>,
62 current_frame_pos: usize,
63
64 next_frame: Vec<f32>,
65 next_frame_pos: usize,
66
67 output_buffer: Option<f32>,
68
69 time_base: TimeBase,
70
71 gain: f32,
72
73 pub volume: f32,
74 pub duration: Duration,
75 pub finished: bool,
76 pub elapsed: Duration,
77}
78
79impl Resampler {
80 pub fn new(output: usize, file: File, volume: u8, gain: f32) -> Self {
81 let mss = MediaSourceStream::new(Box::new(file), Default::default());
82
83 let mut probed = get_probe()
84 .format(
85 &Hint::default(),
86 mss,
87 &FormatOptions {
88 prebuild_seek_index: true,
89 seek_index_fill_rate: 1,
90 enable_gapless: false,
91 },
92 &MetadataOptions::default(),
93 )
94 .unwrap();
95
96 let track = probed.format.default_track().unwrap();
97 let input = track.codec_params.sample_rate.unwrap() as usize;
98 let time_base = track.codec_params.time_base.unwrap();
99
100 let n_frames = track.codec_params.n_frames.unwrap();
101 let time = track.codec_params.time_base.unwrap().calc_time(n_frames);
102 let duration = Duration::from_secs(time.seconds) + Duration::from_secs_f64(time.frac);
103
104 let mut decoder = symphonia::default::get_codecs()
105 .make(&track.codec_params, &DecoderOptions::default())
106 .unwrap();
107
108 let next_packet = probed.format.next_packet().unwrap();
109 let decoded = decoder.decode(&next_packet).unwrap();
110 let mut buffer = SampleBuffer::<f32>::new(decoded.capacity() as u64, *decoded.spec());
111 buffer.copy_interleaved_ref(decoded);
112 let mut buffer = buffer.samples().to_vec().into_iter();
113
114 let ts = next_packet.ts();
115 let t = time_base.calc_time(ts);
116 let elapsed = Duration::from_secs(t.seconds) + Duration::from_secs_f64(t.frac);
117
118 let gcd = gcd(input, output);
119
120 let (current_frame, next_frame) = if input == output {
121 (Vec::new(), Vec::new())
122 } else {
123 (
124 vec![buffer.next().unwrap(), buffer.next().unwrap()],
125 vec![buffer.next().unwrap(), buffer.next().unwrap()],
126 )
127 };
128
129 Self {
130 probed,
131 decoder,
132 buffer,
133 input_real: input,
134 input: input / gcd,
135 output: output / gcd,
136 current_frame_pos: 0,
137 next_frame_pos: 0,
138 current_frame,
139 next_frame,
140 output_buffer: None,
141 volume: volume as f32 / VOLUME_REDUCTION,
142 duration,
143 elapsed,
144 time_base,
145 finished: false,
146 gain,
147 }
148 }
149
150 pub fn update_sample_rate(&mut self, output: usize) {
151 let gcd = gcd(self.input_real, output);
152 self.input = self.input_real / gcd;
153 self.output = output / gcd;
154
155 self.output_buffer = None;
158 }
159
160 pub fn next(&mut self) -> f32 {
161 if self.finished {
162 0.0
163 } else if let Some(smp) = self.next_sample() {
164 if self.gain == 0.0 {
165 smp * self.volume * 0.75
168 } else {
169 smp * self.volume * self.gain
170 }
171 } else {
172 let mut decode_errors: usize = 0;
173 loop {
174 if self.finished {
175 return 0.0;
176 }
177
178 match self.probed.format.next_packet() {
179 Ok(next_packet) => {
180 let decoded = self.decoder.decode(&next_packet).unwrap();
181 let mut buffer =
182 SampleBuffer::<f32>::new(decoded.capacity() as u64, *decoded.spec());
183 buffer.copy_interleaved_ref(decoded);
184 self.buffer = buffer.samples().to_vec().into_iter();
185
186 let ts = next_packet.ts();
187 let t = self.time_base.calc_time(ts);
188 self.elapsed =
189 Duration::from_secs(t.seconds) + Duration::from_secs_f64(t.frac);
190
191 if self.input == self.output {
192 self.current_frame = Vec::new();
193 self.next_frame = Vec::new();
194 } else {
195 self.current_frame =
196 vec![self.buffer.next().unwrap(), self.buffer.next().unwrap()];
197 self.next_frame =
198 vec![self.buffer.next().unwrap(), self.buffer.next().unwrap()];
199 }
200
201 self.current_frame_pos = 0;
202 self.next_frame_pos = 0;
203
204 debug_assert!(self.output_buffer.is_none());
205
206 return self.next();
207 }
208 Err(err) => match err {
209 Error::IoError(err) => match err.kind() {
210 ErrorKind::UnexpectedEof => {
211 self.finished = true;
212 return 0.0;
213 }
214 _ => continue,
215 },
216 Error::DecodeError(_) => {
217 decode_errors += 1;
218 if decode_errors > MAX_DECODE_ERRORS {
219 panic!("{:?}", err);
220 }
221 continue;
222 }
223 _ => panic!("{}", err),
224 },
225 }
226 }
227 }
228 }
229
230 fn next_input_frame(&mut self) {
231 self.current_frame = std::mem::take(&mut self.next_frame);
232
233 if let Some(sample) = self.buffer.next() {
234 self.next_frame.push(sample);
235 }
236
237 if let Some(sample) = self.buffer.next() {
238 self.next_frame.push(sample);
239 }
240
241 self.current_frame_pos += 1;
242 }
243
244 fn next_sample(&mut self) -> Option<f32> {
245 if self.input == self.output {
246 return self.buffer.next();
247 } else if let Some(sample) = self.output_buffer.take() {
248 return Some(sample);
249 }
250
251 if self.next_frame_pos == self.output {
252 self.next_frame_pos = 0;
253
254 self.next_input_frame();
255 while self.current_frame_pos != self.input {
256 self.next_input_frame();
257 }
258 self.current_frame_pos = 0;
259 } else {
260 let req_left_sample = (self.input * self.next_frame_pos / self.output) % self.input;
261
262 while self.current_frame_pos != req_left_sample {
263 self.next_input_frame();
264 debug_assert!(self.current_frame_pos < self.input);
265 }
266 }
267
268 let numerator = (self.input * self.next_frame_pos) % self.output;
269
270 self.next_frame_pos += 1;
271
272 if self.current_frame.is_empty() && self.next_frame.is_empty() {
273 return None;
274 }
275
276 if self.next_frame.is_empty() {
277 let r = self.current_frame.remove(0);
278 self.output_buffer = self.current_frame.first().cloned();
279 self.current_frame.clear();
280 Some(r)
281 } else {
282 let ratio = numerator as f32 / self.output as f32;
283 self.output_buffer = Some(lerp(self.current_frame[1], self.next_frame[1], ratio));
284 Some(lerp(self.current_frame[0], self.next_frame[0], ratio))
285 }
286 }
287
288 pub fn set_volume(&mut self, volume: u8) {
289 self.volume = volume as f32 / VOLUME_REDUCTION;
290 }
291 pub fn seek(&mut self, time: Duration) -> Result<(), String> {
292 match self.probed.format.seek(
293 SeekMode::Coarse,
294 SeekTo::Time {
295 time: Time::new(time.as_secs(), time.subsec_nanos() as f64 / 1_000_000_000.0),
296 track_id: None,
297 },
298 ) {
299 Ok(_) => Ok(()),
300 Err(e) => match e {
301 Error::SeekError(e) => match e {
302 SeekErrorKind::OutOfRange => Err(String::from("Seek out of range!")),
303 _ => panic!("{:?}", e),
304 },
305 _ => panic!("{}", e),
306 },
307 }
308 }
309}
310
311#[derive(Debug, PartialEq, Eq)]
312pub enum State {
313 Playing,
314 Paused,
315 Stopped,
316}
317
318pub struct Player {
319 pub stream: Stream,
320 pub resampler: Arc<RwLock<Option<Resampler>>>,
321 pub sample_rate: usize,
322 pub state: State,
323 pub songs: Index<Song>,
324 pub volume: u8,
325}
326
327impl Player {
328 pub fn new(wanted_device: &str, volume: u8, songs: Index<Song>, elapsed: f32) -> Self {
329 #[cfg(unix)]
330 let _gag = gag::Gag::stderr().unwrap();
331
332 let mut device = None;
333
334 for d in audio_devices() {
335 if d.name().unwrap() == wanted_device {
336 device = Some(d);
337 }
338 }
339
340 let device = if let Some(device) = device {
341 device
342 } else {
343 default_device()
344 };
345
346 let config = device.default_output_config().unwrap().config();
347 if config.channels != 2 {
348 panic!("TODO: Support downmixing multiple channels")
349 }
350
351 let resampler = Arc::new(RwLock::new(None));
352 let stream = create_output_stream(&device, &config, resampler.clone()).unwrap();
353
354 let mut state = State::Stopped;
355 let sample_rate = config.sample_rate.0 as usize;
356
357 if let Some(song) = songs.selected() {
359 let file = match File::open(&song.path) {
360 Ok(file) => file,
361 Err(_) => {
362 return Self {
363 stream,
364 resampler,
365 sample_rate,
366 state,
367 songs,
368 volume,
369 }
370 }
371 };
372 let elapsed = Duration::from_secs_f32(elapsed);
373 let mut r = Resampler::new(sample_rate, file, volume, song.gain as f32);
374 r.elapsed = elapsed;
376 r.seek(elapsed).unwrap();
377 state = State::Paused;
378 *resampler.write().unwrap() = Some(r);
379 };
380
381 Self {
382 resampler,
383 sample_rate: config.sample_rate.0 as usize,
384 stream,
385 volume,
386 state,
387 songs,
388 }
389 }
390
391 pub fn set_output_device(&mut self, device: &Device) -> Result<(), String> {
392 match device.default_output_config() {
399 Ok(supported_stream) => {
400 match create_output_stream(
401 device,
402 &supported_stream.config(),
403 self.resampler.clone(),
404 ) {
405 Ok(stream) => {
406 self.stream = stream;
407 self.sample_rate = supported_stream.sample_rate().0 as usize;
408
409 if let Some(resampler) = self.resampler.write().unwrap().as_mut() {
410 resampler.update_sample_rate(self.sample_rate);
411 }
412
413 self.stream.play().unwrap();
414 Ok(())
415 }
416 Err(e) => match e {
417 BuildStreamError::BackendSpecific { err } => Err(err.description),
418 _ => Err(format!("{}", e)),
419 },
420 }
421 }
422 Err(e) => Err(format!("{}", e)),
423 }
424 }
425
426 pub fn update(&mut self) -> Result<(), String> {
427 let mut next = false;
428 if let Some(resampler) = self.resampler.read().unwrap().as_ref() {
429 if resampler.finished {
430 next = true;
431 }
432 }
433
434 if next {
435 self.next()?;
436 }
437
438 Ok(())
439 }
440
441 pub fn add_songs(&mut self, songs: &[Song]) -> Result<(), String> {
442 self.songs.data.extend(songs.to_vec());
443 if self.songs.selected().is_none() {
444 self.songs.select(Some(0));
445 self.play_selected()
446 } else {
447 Ok(())
448 }
449 }
450
451 pub fn previous(&mut self) -> Result<(), String> {
452 self.songs.up();
453 self.play_selected()
454 }
455
456 pub fn next(&mut self) -> Result<(), String> {
457 self.songs.down();
458 self.play_selected()
459 }
460
461 fn play_selected(&mut self) -> Result<(), String> {
462 if let Some(song) = self.songs.selected() {
463 let file = match File::open(&song.path) {
464 Ok(file) => file,
465 Err(_) => return Err(format!("Could not open file: {:?}", song.path)),
467 };
468 if let Some(resampler) = self.resampler.write().unwrap().as_mut() {
469 resampler.finished = true;
470 }
471 *self.resampler.write().unwrap() = Some(Resampler::new(
472 self.sample_rate,
473 file,
474 self.volume,
475 song.gain as f32,
476 ));
477 self.play();
478 }
479 Ok(())
480 }
481
482 pub fn play_index(&mut self, i: usize) -> Result<(), String> {
483 self.songs.select(Some(i));
484 self.play_selected()
485 }
486
487 pub fn delete_index(&mut self, i: usize) -> Result<(), String> {
488 if self.songs.is_empty() {
489 return Ok(());
490 }
491 self.songs.data.remove(i);
492
493 if let Some(playing) = self.songs.index() {
494 let len = self.songs.len();
495
496 if len == 0 {
497 self.clear();
498 } else if i == playing && i == 0 {
499 if i == 0 {
500 self.songs.select(Some(0));
501 }
502 return self.play_selected();
503 } else if i == playing && i == len {
504 self.songs.select(Some(len - 1));
505 } else if i < playing {
506 self.songs.select(Some(playing - 1));
507 }
508 };
509 Ok(())
510 }
511
512 pub fn clear(&mut self) {
513 self.songs = Index::default();
514 self.state = State::Stopped;
515 *self.resampler.write().unwrap() = None;
516 }
517
518 pub fn clear_except_playing(&mut self) {
519 if let Some(index) = self.songs.index() {
520 let playing = self.songs.data.remove(index);
521 self.songs = Index::new(vec![playing], Some(0));
522 }
523 }
524
525 pub fn volume_up(&mut self) {
526 self.volume += VOLUME_STEP;
527 if self.volume > 100 {
528 self.volume = 100;
529 }
530
531 if let Some(resampler) = self.resampler.write().unwrap().as_mut() {
532 resampler.set_volume(self.volume);
533 }
534 }
535
536 pub fn volume_down(&mut self) {
537 if self.volume != 0 {
538 self.volume -= VOLUME_STEP;
539 }
540
541 if let Some(resampler) = self.resampler.write().unwrap().as_mut() {
542 resampler.set_volume(self.volume);
543 }
544 }
545
546 pub fn duration(&self) -> Duration {
547 if let Some(resampler) = self.resampler.read().unwrap().as_ref() {
548 resampler.duration
549 } else {
550 Duration::default()
551 }
552 }
553
554 pub fn elapsed(&self) -> Duration {
555 if let Some(resampler) = self.resampler.read().unwrap().as_ref() {
556 resampler.elapsed
557 } else {
558 Duration::default()
559 }
560 }
561
562 pub fn toggle_playback(&mut self) -> Result<(), String> {
563 if self.resampler.read().unwrap().is_none() {
564 self.play_selected()
565 } else {
566 match self.state {
567 State::Playing => self.pause(),
568 State::Paused => self.play(),
569 State::Stopped => (),
570 };
571 Ok(())
572 }
573 }
574
575 pub fn play(&mut self) {
576 self.stream.play().unwrap();
577 self.state = State::Playing;
578 }
579
580 pub fn pause(&mut self) {
581 self.stream.pause().unwrap();
582 self.state = State::Paused;
583 }
584
585 pub fn seek_by(&mut self, time: f32) -> Result<(), String> {
586 let time = if let Some(resampler) = self.resampler.read().unwrap().as_ref() {
587 resampler.elapsed.as_secs_f32() + time
588 } else {
589 return Ok(());
590 };
591
592 if time > self.duration().as_secs_f32() {
593 self.next()?;
594 } else {
595 self.seek_to(time)?;
596 self.play();
597 }
598
599 Ok(())
600 }
601
602 pub fn seek_to(&mut self, time: f32) -> Result<(), String> {
603 let time = Duration::from_secs_f32(time.clamp(0.5, f32::MAX));
606 if time > self.duration() {
607 self.next()?;
608 } else {
609 if let Some(resampler) = self.resampler.write().unwrap().as_mut() {
610 resampler.seek(time)?;
611 }
612 self.play();
613 }
614 Ok(())
615 }
616
617 pub fn is_playing(&self) -> bool {
618 State::Playing == self.state
619 }
620}
621
622unsafe impl Send for Player {}
623
624fn create_output_stream(
625 device: &Device,
626 config: &StreamConfig,
627 resampler: Arc<RwLock<Option<Resampler>>>,
628) -> Result<Stream, BuildStreamError> {
629 device.build_output_stream(
630 config,
631 move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
632 for frame in data.chunks_mut(2) {
633 for sample in frame.iter_mut() {
634 let smp = if let Some(resampler) = resampler.write().unwrap().as_mut() {
635 resampler.next()
636 } else {
637 0.0
638 };
639 *sample = smp;
640 }
641 }
642 },
643 |err| panic!("{}", err),
644 )
645}
646
647pub fn audio_devices() -> Vec<Device> {
648 let host_id = cpal::default_host().id();
649 let host = cpal::host_from_id(host_id).unwrap();
650
651 host.devices().unwrap().collect()
654}
655
656pub fn default_device() -> Device {
657 cpal::default_host().default_output_device().unwrap()
658}