audio_processor_file/audio_file_processor/
mod.rs1use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
24use std::time::Instant;
25
26use symphonia::core::probe::ProbeResult;
27
28use audio_garbage_collector::{Handle, Shared};
29use audio_processor_traits::{AudioBuffer, AudioContext, AudioProcessor, AudioProcessorSettings};
30use file_io::{AudioFileError, FileContentsStream};
31
32pub mod file_io;
33
34pub struct InMemoryAudioFile {
35 audio_file: ProbeResult,
36}
37
38impl InMemoryAudioFile {
39 pub fn new(audio_file: ProbeResult) -> Self {
40 InMemoryAudioFile { audio_file }
41 }
42
43 pub fn from_path(path: &str) -> Result<Self, AudioFileError> {
44 Ok(Self::new(file_io::default_read_audio_file(path)?))
45 }
46
47 #[cfg(feature = "samplerate")]
50 pub fn read_into_vec_audio_buffer(
51 &mut self,
52 settings: &AudioProcessorSettings,
53 ) -> Result<AudioBuffer<f32>, AudioFileError> {
54 use rayon::prelude::*;
55
56 let output_rate = settings.sample_rate();
57 let contents = file_io::read_file_contents(&mut self.audio_file)?;
58 let converted_channels: Vec<Vec<f32>> = (0..contents.spec().channels.count())
59 .into_par_iter()
60 .map(|channel_number| {
61 file_io::convert_audio_file_sample_rate(&contents, output_rate, channel_number)
62 })
63 .collect();
64
65 let mut output_buffer = AudioBuffer::empty();
66 output_buffer.resize(settings.output_channels(), converted_channels[0].len());
67 for (channel_index, channel) in converted_channels.iter().enumerate() {
68 for (sample_index, sample) in channel.iter().enumerate() {
69 output_buffer.set(channel_index, sample_index, *sample);
70 }
71 }
72
73 Ok(output_buffer)
74 }
75}
76
77pub struct AudioFileProcessorHandle {
78 audio_file_cursor: AtomicUsize,
79 is_playing: AtomicBool,
80 should_loop: AtomicBool,
81}
82
83impl AudioFileProcessorHandle {
84 pub fn play(&self) {
86 self.is_playing.store(true, Ordering::Relaxed);
87 }
88
89 pub fn pause(&self) {
91 self.is_playing.store(false, Ordering::Relaxed);
92 }
93
94 pub fn stop(&self) {
96 self.is_playing.store(false, Ordering::Relaxed);
97 self.audio_file_cursor.store(0, Ordering::Relaxed);
98 }
99
100 pub fn is_playing(&self) -> bool {
102 self.is_playing.load(Ordering::Relaxed)
103 }
104
105 pub fn set_should_loop(&self, should_loop: bool) {
106 self.should_loop.store(should_loop, Ordering::Relaxed);
107 }
108
109 pub fn should_loop(&self) -> bool {
110 self.should_loop.load(Ordering::Relaxed)
111 }
112}
113
114pub struct AudioFileProcessor {
116 audio_file_settings: InMemoryAudioFile,
117 audio_settings: AudioProcessorSettings,
118 buffer: Vec<Vec<f32>>,
119 handle: Shared<AudioFileProcessorHandle>,
120}
121
122impl AudioFileProcessor {
123 pub fn from_path(
124 handle: &Handle,
125 audio_settings: AudioProcessorSettings,
126 path: &str,
127 ) -> Result<Self, AudioFileError> {
128 let audio_file_settings = InMemoryAudioFile::new(file_io::default_read_audio_file(path)?);
129 Ok(Self::new(handle, audio_file_settings, audio_settings))
130 }
131
132 pub fn new(
133 gc_handle: &Handle,
134 audio_file_settings: InMemoryAudioFile,
135 audio_settings: AudioProcessorSettings,
136 ) -> Self {
137 let handle = Shared::new(
138 gc_handle,
139 AudioFileProcessorHandle {
140 audio_file_cursor: AtomicUsize::new(0),
141 is_playing: AtomicBool::new(true),
142 should_loop: AtomicBool::new(true),
143 },
144 );
145
146 AudioFileProcessor {
147 audio_file_settings,
148 audio_settings,
149 buffer: Vec::new(),
150 handle,
151 }
152 }
153
154 pub fn num_samples(&self) -> usize {
156 if self.buffer.is_empty() {
157 0
158 } else {
159 self.buffer[0].len()
160 }
161 }
162
163 pub fn buffer(&self) -> &Vec<Vec<f32>> {
165 &self.buffer
166 }
167
168 pub fn handle(&self) -> &Shared<AudioFileProcessorHandle> {
169 &self.handle
170 }
171
172 pub fn play(&self) {
174 self.handle.play()
175 }
176
177 pub fn pause(&self) {
179 self.handle.pause()
180 }
181
182 pub fn stop(&self) {
184 self.handle.stop()
185 }
186
187 pub fn is_playing(&self) -> bool {
189 self.handle.is_playing()
190 }
191
192 pub fn process_single(&self) -> impl Iterator<Item = f32> + '_ {
193 let handle = &self.handle;
194 let audio_file_cursor = handle.audio_file_cursor.load(Ordering::Relaxed);
195 let iterator = self
196 .buffer
197 .iter()
198 .map(move |channel| channel[audio_file_cursor]);
199
200 let mut audio_file_cursor: usize = audio_file_cursor;
201 audio_file_cursor += 1;
202 if audio_file_cursor >= self.buffer[0].len() {
203 audio_file_cursor = 0;
204 }
205 handle
206 .audio_file_cursor
207 .store(audio_file_cursor, Ordering::Relaxed);
208
209 iterator
210 }
211}
212
213impl AudioProcessor for AudioFileProcessor {
214 type SampleType = f32;
215
216 fn prepare(&mut self, context: &mut AudioContext) {
221 let audio_settings = context.settings;
222 log::info!("Preparing for audio file playback");
223 self.audio_settings = audio_settings;
224
225 self.buffer.clear();
226 self.buffer.reserve(self.audio_settings.output_channels());
227
228 let start = Instant::now();
229 log::info!("Reading audio file onto memory");
230
231 let mut run = || -> Result<(), file_io::AudioFileError> {
232 let input_stream = FileContentsStream::new(&mut self.audio_file_settings.audio_file)?;
233 let converted_stream = file_io::convert_audio_file_stream_sample_rate(
234 input_stream,
235 audio_settings.sample_rate(),
236 );
237
238 for buffer in converted_stream {
239 self.buffer.resize(buffer.num_channels(), vec![]);
240
241 for (channel, source) in self.buffer.iter_mut().zip(buffer.channels()) {
242 for sample in source {
243 channel.push(*sample)
244 }
245 }
246 }
247
248 #[cfg(feature = "rubato")]
251 for channel in self.buffer.iter_mut() {
252 *channel = channel.iter().skip(256).cloned().collect();
253 }
254
255 Ok(())
256 };
257
258 match run() {
259 Ok(_) => {
260 log::info!("Read input file duration={}ms", start.elapsed().as_millis());
261 }
262 Err(err) => {
263 log::error!("Failed to read input file {}", err);
264 }
265 }
266 }
267
268 fn process(&mut self, _context: &mut AudioContext, data: &mut AudioBuffer<Self::SampleType>) {
269 let is_playing = self.handle.is_playing.load(Ordering::Relaxed);
270
271 if !is_playing {
272 return;
273 }
274
275 let should_loop = self.handle.should_loop();
276 let start_cursor = self.handle.audio_file_cursor.load(Ordering::Relaxed);
277 let mut audio_file_cursor = start_cursor;
278
279 for sample_num in 0..data.num_samples() {
280 for channel_index in 0..data.num_channels() {
281 let audio_input = self.buffer[channel_index][audio_file_cursor];
282 let value = audio_input;
283 data.channel_mut(channel_index)[sample_num] += value;
284 }
285
286 audio_file_cursor += 1;
287 if audio_file_cursor >= self.buffer[0].len() {
288 audio_file_cursor = 0;
289
290 if !should_loop {
291 self.handle.stop();
292 break;
293 }
294 }
295 }
296
297 let _ = self.handle.audio_file_cursor.compare_exchange(
298 start_cursor,
299 audio_file_cursor,
300 Ordering::Relaxed,
301 Ordering::Relaxed,
302 );
303 }
304}
305
306#[cfg(test)]
307mod test {
308 use audio_garbage_collector::GarbageCollector;
309
310 use super::*;
311
312 fn setup() -> (GarbageCollector, InMemoryAudioFile) {
313 wisual_logger::init_from_env();
314
315 let garbage_collector = GarbageCollector::default();
316 let path = format!(
317 "{}{}",
318 env!("CARGO_MANIFEST_DIR"),
319 "/../../../../input-files/1sec-sine.mp3"
320 );
321 let audio_file_settings = InMemoryAudioFile::from_path(&path).unwrap();
322 (garbage_collector, audio_file_settings)
323 }
324
325 #[test]
326 fn test_in_memory_audio_file_can_be_created_from_probe() {
327 let path = format!(
328 "{}{}",
329 env!("CARGO_MANIFEST_DIR"),
330 "/../../../../input-files/1sec-sine.mp3"
331 );
332 let probe_result = file_io::default_read_audio_file(&path).unwrap();
333 let _audio_file = InMemoryAudioFile::new(probe_result);
334 }
335
336 #[test]
340 fn test_audio_file_processor_stopped_is_silent() {
341 let (garbage_collector, audio_file_settings) = setup();
342
343 let mut audio_file_processor = AudioFileProcessor::new(
344 garbage_collector.handle(),
345 audio_file_settings,
346 Default::default(),
347 );
348 let mut context = AudioContext::default();
349 audio_file_processor.prepare(&mut context);
350
351 audio_file_processor.stop();
352 let mut sample_buffer = AudioBuffer::empty();
353 sample_buffer.resize(2, 44100);
354 audio_file_processor.process(&mut context, &mut sample_buffer);
355
356 assert!(
357 audio_processor_testing_helpers::rms_level(sample_buffer.channel(0)) < f32::EPSILON
358 );
359 }
360
361 #[test]
365 fn test_audio_file_processor_playing_is_not_silent() {
366 let (garbage_collector, audio_file_settings) = setup();
367
368 let mut audio_file_processor = AudioFileProcessor::new(
369 garbage_collector.handle(),
370 audio_file_settings,
371 Default::default(),
372 );
373 let mut context = AudioContext::default();
374 audio_file_processor.prepare(&mut context);
375
376 let mut sample_buffer = AudioBuffer::empty();
377 sample_buffer.resize(2, 44100);
378 audio_file_processor.play();
379 audio_file_processor.process(&mut context, &mut sample_buffer);
380
381 assert!(
382 audio_processor_testing_helpers::rms_level(sample_buffer.channel(0)) > f32::EPSILON
383 );
384 }
385}