1use std::{
2 ops::Range,
3 path::Path,
4 sync::{mpsc::SyncSender, Arc},
5 time::Duration,
6};
7
8use crossbeam_queue::ArrayQueue;
9
10use super::{common::FileSourceImpl, FilePlaybackMessage, FilePlaybackOptions, FileSource};
11
12use crate::{
13 error::Error,
14 source::{
15 file::{AudioFileBuffer, PlaybackId, PlaybackStatusContext, PlaybackStatusEvent},
16 Source, SourceTime,
17 },
18 utils::{buffer::clear_buffer, fader::FaderState},
19};
20
21pub struct PreloadedFileSource {
30 file_buffer: Arc<AudioFileBuffer>,
31 file_source: FileSourceImpl,
32 playback_repeat: usize,
33 playback_repeat_count: usize,
34 playback_pos: usize,
35 playback_pos_eof: bool,
36 loop_range_override: Option<Range<u64>>,
37}
38
39impl PreloadedFileSource {
40 pub fn from_file<P: AsRef<Path>>(
42 path: P,
43 options: FilePlaybackOptions,
44 output_sample_rate: u32,
45 ) -> Result<Self, Error> {
46 let file_path = path.as_ref().to_string_lossy().to_string();
48 Self::from_shared_buffer(
49 Arc::new(AudioFileBuffer::from_file(path)?),
50 &file_path,
51 options,
52 output_sample_rate,
53 )
54 }
55
56 pub fn from_file_buffer(
58 file_buffer: Vec<u8>,
59 file_path: &str,
60 options: FilePlaybackOptions,
61 output_sample_rate: u32,
62 ) -> Result<Self, Error> {
63 Self::from_shared_buffer(
64 Arc::new(AudioFileBuffer::from_file_buffer(file_buffer)?),
65 file_path,
66 options,
67 output_sample_rate,
68 )
69 }
70
71 pub fn from_shared_buffer(
73 file_buffer: Arc<AudioFileBuffer>,
74 file_path: &str,
75 options: FilePlaybackOptions,
76 output_sample_rate: u32,
77 ) -> Result<Self, Error> {
78 options.validate()?;
80
81 let file_source = FileSourceImpl::new(
83 file_path,
84 options,
85 file_buffer.sample_rate(),
86 file_buffer.channel_count(),
87 output_sample_rate,
88 )?;
89
90 let playback_repeat = options
91 .repeat
92 .unwrap_or(if file_buffer.loop_range().is_some() {
93 usize::MAX
94 } else {
95 0
96 });
97 let playback_repeat_count = playback_repeat;
98 let playback_pos = 0;
99 let playback_pos_eof = false;
100
101 let loop_range_override = options.loop_range.map(|(start, end)| {
102 let frame_count = file_buffer.frame_count() as u64;
103 start.min(frame_count.saturating_sub(1))..end.min(frame_count)
104 });
105
106 Ok(Self {
107 file_buffer,
108 file_source,
109 playback_repeat_count,
110 playback_repeat,
111 playback_pos,
112 playback_pos_eof,
113 loop_range_override,
114 })
115 }
116
117 pub fn clone(
119 &self,
120 options: FilePlaybackOptions,
121 output_sample_rate: u32,
122 ) -> Result<Self, Error> {
123 let file_buffer = Arc::clone(&self.file_buffer);
124 Self::from_shared_buffer(
125 file_buffer,
126 &self.file_source.file_path,
127 options,
128 output_sample_rate,
129 )
130 }
131
132 pub fn file_buffer(&self) -> Arc<AudioFileBuffer> {
134 Arc::clone(&self.file_buffer)
135 }
136
137 pub fn seek(&mut self, position: Duration) {
139 if !self.is_exhausted() {
140 let buffer_pos = position.as_secs_f64()
141 * self.file_buffer.sample_rate() as f64
142 * self.file_buffer.channel_count() as f64;
143 self.playback_pos = (buffer_pos as usize).clamp(0, self.file_buffer.buffer().len());
144 self.file_source.resampler.reset();
145 }
146 }
147
148 pub fn loop_range(&self) -> Option<Range<u64>> {
151 self.loop_range_override.clone().or_else(|| {
152 self.file_buffer
153 .loop_range()
154 .map(|r| r.start as u64..r.end as u64)
155 })
156 }
157
158 pub fn set_loop_range(&mut self, range: Option<Range<u64>>) {
161 let frame_count = self.file_buffer.frame_count() as u64;
162 assert!(
163 range.is_none()
164 || range
165 .as_ref()
166 .is_some_and(|r| r.start < frame_count && r.end <= frame_count),
167 "Invalid loop range: {:?} not in range {:?}",
168 range,
169 0..frame_count
170 );
171 self.loop_range_override = range;
172 }
173
174 pub fn set_repeat(&mut self, repeat_count: usize) {
177 self.playback_repeat = repeat_count;
178 self.playback_repeat_count = self.playback_repeat;
179 }
180
181 pub fn set_speed(&mut self, speed: f64, glide: Option<f32>) {
183 if !self.is_exhausted() {
184 self.file_source.samples_to_next_speed_update = 0;
185 self.file_source.target_speed = speed;
186 self.file_source.speed_glide_rate = glide.unwrap_or(0.0);
187 if self.file_source.speed_glide_rate == 0.0 {
188 self.file_source.current_speed = speed;
189 self.file_source
190 .update_speed(self.file_buffer.sample_rate());
191 }
192 }
193 }
194
195 pub fn stop(&mut self) {
197 if !self.is_exhausted() {
198 match self.file_source.fade_out_duration {
199 Some(duration) if !duration.is_zero() => {
200 self.file_source.volume_fader.start_fade_out(duration);
201 }
202 _ => {
203 self.file_source
204 .send_playback_stopped_status(self.playback_pos_eof);
205 self.file_source.playback_finished = true;
206 }
207 }
208 }
209 }
210
211 pub fn reset(&mut self) {
213 if !self.is_exhausted() {
215 self.kill();
216 }
217 self.playback_pos = 0;
219 self.playback_repeat_count = self.playback_repeat;
220 self.playback_pos_eof = false;
221 self.file_source.playback_started = false;
222 self.file_source.playback_finished = false;
223
224 self.file_source.resampler.reset();
226 self.file_source.resampler_input_buffer.clear_range();
227
228 self.file_source.volume_fader.reset();
230 }
231
232 pub fn kill(&mut self) {
234 if !self.is_exhausted() {
235 self.file_source
236 .send_playback_stopped_status(self.playback_pos_eof);
237 self.file_source.playback_finished = true;
238 }
239 }
240
241 #[allow(unused)]
243 pub(crate) fn file_source_impl(&self) -> &FileSourceImpl {
244 &self.file_source
245 }
246 pub(crate) fn file_source_impl_mut(&mut self) -> &mut FileSourceImpl {
248 &mut self.file_source
249 }
250
251 fn process_messages(&mut self) {
252 while let Some(msg) = self.file_source.playback_message_queue.pop() {
253 match msg {
254 FilePlaybackMessage::Seek(position) => {
255 self.seek(position);
256 }
257 FilePlaybackMessage::SetSpeed(speed, glide) => {
258 self.set_speed(speed, glide);
259 }
260 FilePlaybackMessage::Stop => {
261 self.stop();
262 }
263 FilePlaybackMessage::Kill => {
264 self.kill();
265 }
266 }
267 }
268 }
269
270 fn write_buffer(&mut self, output: &mut [f32]) -> usize {
271 let mut written = 0;
272
273 let loop_range = if self.playback_repeat > 0 {
274 let channel_count = self.file_buffer.channel_count();
275 self.loop_range()
276 .map(|r| r.start as usize * channel_count..r.end as usize * channel_count)
277 .unwrap_or(0..self.file_buffer.buffer().len())
278 } else {
279 0..self.file_buffer.buffer().len()
280 };
281
282 let resampler = &mut self.file_source.resampler;
283 let resampler_input_buffer = &mut self.file_source.resampler_input_buffer;
284
285 let required_input_len = resampler.required_input_buffer_size().unwrap_or(0);
286
287 while written < output.len() {
288 let remaining_input_len = loop_range.end.saturating_sub(self.playback_pos);
290 let remaining_input_buffer = &self.file_buffer.buffer()
291 [self.playback_pos..self.playback_pos + remaining_input_len];
292 let remaining_output = &mut output[written..];
293 let (input_consumed, output_written) = {
294 if remaining_input_buffer.len() < required_input_len {
297 resampler_input_buffer.reset_range();
298 resampler_input_buffer.copy_from(remaining_input_buffer);
299 clear_buffer(&mut resampler_input_buffer.get_mut()[remaining_input_len..]);
300 let (_, output_written) = resampler
301 .process(resampler_input_buffer.get(), remaining_output)
302 .expect("PreloadedFile resampling failed");
303 (remaining_input_len, output_written)
304 } else {
305 resampler
306 .process(remaining_input_buffer, remaining_output)
307 .expect("PreloadedFile resampling failed")
308 }
309 };
310
311 self.playback_pos += input_consumed;
313 written += output_written;
314
315 if self.playback_pos >= loop_range.end {
317 if self.playback_repeat_count > 0 {
318 if self.playback_repeat_count != usize::MAX {
319 self.playback_repeat_count -= 1;
320 }
321 self.playback_pos = loop_range.start;
322 } else {
323 self.playback_pos_eof = true;
324 }
325 }
326 if self.playback_pos_eof && output_written == 0 {
327 break;
329 }
330 }
331 written
332 }
333}
334
335impl FileSource for PreloadedFileSource {
336 fn file_name(&self) -> String {
337 self.file_source.file_path.to_string()
338 }
339
340 fn playback_id(&self) -> PlaybackId {
341 self.file_source.file_id
342 }
343
344 fn playback_options(&self) -> &FilePlaybackOptions {
345 &self.file_source.options
346 }
347
348 fn playback_message_queue(&self) -> Arc<ArrayQueue<FilePlaybackMessage>> {
349 Arc::clone(&self.file_source.playback_message_queue)
350 }
351
352 fn playback_status_sender(&self) -> Option<SyncSender<PlaybackStatusEvent>> {
353 self.file_source.playback_status_send.clone()
354 }
355 fn set_playback_status_sender(&mut self, sender: Option<SyncSender<PlaybackStatusEvent>>) {
356 self.file_source.playback_status_send = sender;
357 }
358
359 fn playback_status_context(&self) -> Option<PlaybackStatusContext> {
360 self.file_source.playback_status_context.clone()
361 }
362 fn set_playback_status_context(&mut self, context: Option<PlaybackStatusContext>) {
363 self.file_source.playback_status_context = context;
364 }
365
366 fn total_frames(&self) -> Option<u64> {
367 Some(self.file_buffer.buffer().len() as u64 / self.file_buffer.channel_count() as u64)
368 }
369
370 fn current_frame_position(&self) -> u64 {
371 self.playback_pos as u64 / self.file_source.output_channel_count as u64
372 }
373
374 fn end_of_track(&self) -> bool {
375 self.file_source.playback_finished
376 }
377}
378
379impl Source for PreloadedFileSource {
380 fn channel_count(&self) -> usize {
381 self.file_source.output_channel_count
382 }
383
384 fn sample_rate(&self) -> u32 {
385 self.file_source.output_sample_rate
386 }
387
388 fn is_exhausted(&self) -> bool {
389 self.file_source.playback_finished
390 }
391
392 fn weight(&self) -> usize {
393 1
394 }
395
396 fn write(&mut self, output: &mut [f32], time: &SourceTime) -> usize {
397 self.process_messages();
399
400 if self.file_source.playback_finished {
402 return 0;
403 }
404
405 if self.file_source.playback_started {
407 self.file_source.playback_started = false;
408 let is_start_event = true;
409 self.file_source.send_playback_position_status(
410 time,
411 is_start_event,
412 self.playback_pos as u64,
413 self.file_buffer.channel_count(),
414 self.file_buffer.sample_rate(),
415 );
416 }
417
418 let mut total_written = 0_usize;
419 if self.file_source.current_speed != self.file_source.target_speed {
420 while total_written < output.len() {
422 if self.file_source.samples_to_next_speed_update == 0 {
423 if self.file_source.current_speed != self.file_source.target_speed {
424 self.file_source
425 .update_speed(self.file_buffer.sample_rate());
426 }
427 self.file_source.samples_to_next_speed_update =
428 FileSourceImpl::SPEED_UPDATE_CHUNK_SIZE
429 * self.file_source.output_channel_count;
430 }
431 let chunk_length = (output.len() - total_written)
432 .min(self.file_source.samples_to_next_speed_update);
433 let output_chunk = &mut output[total_written..total_written + chunk_length];
434 let written = self.write_buffer(output_chunk);
435
436 self.file_source.samples_to_next_speed_update -= written;
437 total_written += written;
438
439 if written < output_chunk.len() {
440 break; }
442 }
443 } else {
444 self.file_source.samples_to_next_speed_update = 0;
446 total_written = self.write_buffer(output);
447 }
448
449 self.file_source
451 .volume_fader
452 .process(&mut output[..total_written]);
453
454 let is_start_event = false;
456 self.file_source.send_playback_position_status(
457 time,
458 is_start_event,
459 self.playback_pos as u64,
460 self.file_buffer.channel_count(),
461 self.file_buffer.sample_rate(),
462 );
463
464 let fade_out_completed = self.file_source.volume_fader.state() == FaderState::Finished
466 && self.file_source.volume_fader.target_volume() == 0.0;
467 if self.playback_pos_eof || fade_out_completed {
468 self.file_source
470 .send_playback_stopped_status(self.playback_pos_eof);
471 self.file_source.playback_finished = true;
472 }
473
474 total_written
475 }
476}
477
478#[cfg(test)]
481mod tests {
482 use super::*;
483
484 use crate::source::resampled::ResamplingQuality;
485
486 #[test]
487 fn resampling() {
488 let source_sample_rate = 44100;
489 let target_sample_rate = 48000;
490
491 let file_buffer = Arc::new(
493 AudioFileBuffer::new(vec![0.2, 1.0, 0.5, 0.0], 1, source_sample_rate, None).unwrap(),
494 );
495
496 let mut preloaded = PreloadedFileSource::from_shared_buffer(
498 Arc::clone(&file_buffer),
499 "buffer",
500 FilePlaybackOptions::default().resampling_quality(ResamplingQuality::Default),
501 target_sample_rate,
502 )
503 .unwrap();
504 let mut output = vec![0.0; 1024];
505 let written = preloaded.write(&mut output, &SourceTime::default());
506 let expected_output =
507 file_buffer.buffer().len() as u32 * source_sample_rate / target_sample_rate;
508 assert!(written as u32 >= expected_output);
509 assert!(
510 (output.iter().sum::<f32>() - file_buffer.buffer().iter().sum::<f32>()).abs() < 0.1
511 );
512
513 let file_buffer =
515 Arc::new(AudioFileBuffer::new(vec![0.2, 1.0, 0.5], 1, 48000, None).unwrap());
516
517 let mut preloaded = PreloadedFileSource::from_shared_buffer(
518 Arc::clone(&file_buffer),
519 "buffer",
520 FilePlaybackOptions::default().resampling_quality(ResamplingQuality::HighQuality),
521 target_sample_rate,
522 )
523 .unwrap();
524 let mut output = vec![0.0; 1024];
525 let written = preloaded.write(&mut output, &SourceTime::default());
526 let expected_output =
527 file_buffer.buffer().len() as u32 * source_sample_rate / target_sample_rate;
528 assert!(written as u32 >= expected_output);
529 assert!(
530 (output.iter().sum::<f32>() - file_buffer.buffer().iter().sum::<f32>()).abs() < 0.2
531 );
532 assert!(output[3..].iter().sum::<f32>() < 0.1);
533 }
534}