Skip to main content

audioadapter_sample/
readwrite.rs

1use crate::sample::*;
2use num_traits::{ToPrimitive, float::FloatCore};
3use std::io;
4
5/// A trait that extends [std::io::Read] with methods for reading samples directly.
6pub trait ReadSamples: io::Read {
7    /// Read a single sample from the underlying reader.
8    ///
9    /// This method reads a chunk of bytes from the underlying reader,
10    /// and interprets it as a sample of type `T`.
11    ///
12    /// # Type Parameters
13    ///
14    /// * `T`: A type implementing the `BytesSample` trait, defining the format of the sample to read.
15    ///
16    /// # Returns
17    ///
18    /// * `io::Result<T>`: The read sample, or an error if reading failed.
19    ///
20    /// # Errors
21    ///
22    /// This function will return an error if:
23    ///
24    /// * The underlying reader returns an error.
25    /// * The number of bytes read is not sufficient to represent a complete sample.
26    fn read_sample<T: BytesSample>(&mut self) -> io::Result<T> {
27        let mut sample: T = unsafe { std::mem::zeroed() };
28        self.read_exact(sample.as_mut_slice())?;
29        Ok(sample)
30    }
31
32    /// Read a single sample and return it as a numeric type.
33    ///
34    /// This method reads a chunk of bytes from the underlying reader,
35    /// interprets it as a sample of type `T`, and returns the sample
36    /// converted to its associated `NumericType`.
37    ///
38    /// # Type Parameters
39    ///
40    /// * `T`: A type implementing the `BytesSample` trait, defining the format of the sample to read.
41    ///
42    /// # Returns
43    ///
44    /// * `io::Result<T::NumericType>`: The sample as a number, or an error if reading failed.
45    ///
46    /// # Errors
47    ///
48    /// This function will return an error if:
49    ///
50    /// * The underlying reader returns an error.
51    /// * The number of bytes read is not sufficient to represent a complete sample.
52    fn read_number<T: BytesSample>(&mut self) -> io::Result<T::NumericType> {
53        let sample = self.read_sample::<T>()?;
54        Ok(sample.to_number())
55    }
56
57    /// Read a single sample and convert it to a floating-point number.
58    ///
59    /// This method reads a chunk of bytes from the underlying reader,
60    /// interprets it as a sample of type `T`, and returns the sample
61    /// converted to a floating-point number of type `U`. The conversion
62    /// uses the `to_scaled_float` method from the `RawSample` trait,
63    /// ensuring that the float is scaled between -1.0 and 1.0.
64    ///
65    /// # Type Parameters
66    ///
67    /// * `T`: A type implementing both `RawSample` and `BytesSample`, defining the format of the sample to read.
68    /// * `U`: A floating-point type implementing `FloatCore` and `ToPrimitive`, representing the desired output format.
69    ///
70    /// # Returns
71    ///
72    /// * `io::Result<U>`: The converted sample as a float, or an error if reading failed.
73    ///
74    /// # Errors
75    ///
76    /// This function will return an error if:
77    ///
78    /// * The underlying reader returns an error.
79    /// * The number of bytes read is not sufficient to represent a complete sample.
80    fn read_converted<T: RawSample + BytesSample, U: FloatCore + ToPrimitive>(
81        &mut self,
82    ) -> io::Result<U> {
83        let sample = self.read_sample::<T>()?;
84        Ok(sample.to_scaled_float::<U>())
85    }
86
87    /// Read multiple samples into a slice.
88    ///
89    /// This method attempts to read enough bytes from the underlying reader to
90    /// fill the buffer `buf` with samples of type `T`. It reads samples one at a time,
91    /// populating the buffer in order.
92    ///
93    /// # Type Parameters
94    ///
95    /// * `T`: A type implementing the `BytesSample` trait, defining the format of the samples to read.
96    ///
97    /// # Arguments
98    ///
99    /// * `buf`: A mutable slice where the samples will be stored.
100    ///
101    /// # Errors
102    ///
103    /// This function will return an error if:
104    ///
105    /// * The underlying reader returns an error.
106    /// * The number of bytes read is not sufficient to represent a complete sample.
107    /// * The end of the reader is reached before all samples have been read.
108    fn read_samples_exact<T: BytesSample>(&mut self, buf: &mut [T]) -> io::Result<()> {
109        for sample in buf.iter_mut() {
110            *sample = self.read_sample()?;
111        }
112        Ok(())
113    }
114
115    /// Read multiple samples and store them as numeric types in a provided buffer.
116    ///
117    /// This method reads a sequence of samples from the underlying reader and
118    /// stores them in the provided buffer `buf`. Each sample is read and
119    /// interpreted as a type `T`, then converted to its associated `NumericType`
120    /// before being stored in the buffer.
121    ///
122    /// # Type Parameters
123    ///
124    /// * `T`: A type implementing the `BytesSample` trait, defining the format of the samples to read.
125    ///
126    /// # Arguments
127    ///
128    /// * `buf`: A mutable slice where the samples will be stored. The length of the slice determines how many samples are read.
129    ///
130    /// # Returns
131    ///
132    /// * `io::Result<()>`: Ok(()) if all samples were read successfully.
133    ///
134    /// # Errors
135    ///
136    /// This function will return an error if:
137    ///
138    /// * The underlying reader returns an error.
139    /// * The number of bytes read is not sufficient to represent a complete sample.
140    /// * The end of the reader is reached before all samples have been read.
141    fn read_numbers_exact<T: BytesSample>(&mut self, buf: &mut [T::NumericType]) -> io::Result<()> {
142        for sample in buf.iter_mut() {
143            *sample = self.read_number::<T>()?;
144        }
145        Ok(())
146    }
147
148    /// Read multiple samples, convert them to floats, and store them in a provided buffer.
149    ///
150    /// This method reads a sequence of samples from the underlying reader,
151    /// converts each sample to a floating-point number of type `U`, and
152    /// stores the results in the provided buffer `buf`.
153    ///
154    /// # Type Parameters
155    ///
156    /// * `T`: A type implementing both `RawSample` and `BytesSample`, defining the format of the samples to read.
157    /// * `U`: A floating-point type implementing `FloatCore` and `ToPrimitive`, representing the desired output format.
158    ///
159    /// # Arguments
160    ///
161    /// * `buf`: A mutable slice where the converted samples will be stored. The length of the slice determines how many samples are read.
162    ///
163    /// # Returns
164    ///
165    /// * `io::Result<()>`: Ok(()) if all samples were read and converted successfully.
166    ///
167    /// # Errors
168    ///
169    /// This function will return an error if:
170    ///
171    /// * The underlying reader returns an error.
172    /// * The number of bytes read is not sufficient to represent a complete sample.
173    /// * The end of the reader is reached before all samples have been read.
174    fn read_converted_exact<T: RawSample + BytesSample, U: FloatCore + ToPrimitive>(
175        &mut self,
176        buf: &mut [U],
177    ) -> io::Result<()> {
178        for sample in buf.iter_mut() {
179            *sample = self.read_converted::<T, U>()?;
180        }
181        Ok(())
182    }
183
184    /// Read samples until the end of the stream, storing them in a vector.
185    ///
186    /// This method reads samples from the underlying reader until reaching
187    /// the end of the stream, the optional limit, or encountering an error.
188    /// Each sample is read and interpreted as a type `T`
189    /// before being appended to the provided vector `buf`.
190    ///
191    /// Only complete samples are read. If the last bytes at the end of the stream
192    /// are too few to make up a complete sample, then they are ignored.
193    ///
194    /// # Type Parameters
195    ///
196    /// * `T`: A type implementing the `BytesSample` trait, defining the format of the samples to read.
197    ///
198    /// # Arguments
199    ///
200    /// * `buf`: A mutable vector where the samples will be appended.
201    /// * `limit`: An optional limit for how many samples to read.
202    ///
203    /// # Returns
204    /// The number of samples read.
205    ///
206    /// # Errors
207    ///
208    /// * The underlying reader returns an error (except for EOF).
209    fn read_samples_to_limit_or_end<T: BytesSample>(
210        &mut self,
211        buf: &mut Vec<T>,
212        limit: Option<usize>,
213    ) -> io::Result<usize> {
214        let mut count = 0;
215        loop {
216            match self.read_sample::<T>() {
217                Ok(sample) => {
218                    buf.push(sample);
219                    count += 1;
220                }
221                Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => {
222                    break;
223                }
224                Err(e) => return Err(e),
225            }
226            if let Some(limit) = limit {
227                if count >= limit {
228                    break;
229                }
230            }
231        }
232        Ok(count)
233    }
234
235    /// Read samples until the end of the stream, storing them as numeric types in a vector.
236    ///
237    /// This method reads samples from the underlying reader until reaching
238    /// the end of the stream, the optional limit, or encountering an error.
239    /// Each sample is read and interpreted as
240    /// a type `T`, then converted to its associated `NumericType` before being
241    /// appended to the provided vector `buf`.
242    ///
243    /// Only complete samples are read. If the last bytes at the end of the stream
244    /// are too few to make up a complete sample, then they are ignored.
245    ///
246    /// # Type Parameters
247    ///
248    /// * `T`: A type implementing the `BytesSample` trait, defining the format of the samples to read.
249    ///
250    /// # Arguments
251    ///
252    /// * `buf`: A mutable vector where the samples will be appended.
253    /// * `limit`: An optional limit for how many samples to read.
254    ///
255    /// # Returns
256    ///
257    /// * `io::Result<usize>`: The number of samples read, or an error if reading failed.
258    ///
259    /// # Errors
260    ///
261    /// This function will return an error if:
262    ///
263    /// * The underlying reader returns an error (except for EOF).
264    fn read_numbers_to_limit_or_end<T: BytesSample>(
265        &mut self,
266        buf: &mut Vec<T::NumericType>,
267        limit: Option<usize>,
268    ) -> io::Result<usize> {
269        let mut count = 0;
270        loop {
271            match self.read_number::<T>() {
272                Ok(sample) => {
273                    buf.push(sample);
274                    count += 1;
275                }
276                Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => {
277                    break;
278                }
279                Err(e) => return Err(e),
280            }
281            if let Some(limit) = limit {
282                if count >= limit {
283                    break;
284                }
285            }
286        }
287        Ok(count)
288    }
289
290    /// Read samples until the end of the stream, converting them to floats, and store in a vector.
291    ///
292    /// This method reads samples from the underlying reader until reaching
293    /// the end of the stream, the optional limit, or encountering an error.
294    /// Each sample is read, converted to a
295    /// floating-point number of type `U`, and appended to the provided vector `buf`.
296    ///
297    /// Only complete samples are read. If the last bytes at the end of the stream
298    /// are too few to make up a complete sample, then they are ignored.
299    ///
300    /// # Type Parameters
301    ///
302    /// * `T`: A type implementing both `RawSample` and `BytesSample`, defining the format of the samples to read.
303    /// * `U`: A floating-point type implementing `FloatCore` and `ToPrimitive`, representing the desired output format.
304    ///
305    /// # Arguments
306    ///
307    /// * `buf`: A mutable vector where the converted samples will be appended.
308    /// * `limit`: An optional limit for how many samples to read.
309    ///
310    /// # Returns
311    ///
312    /// * `io::Result<usize>`: The number of samples read and converted, or an error if reading failed.
313    ///
314    /// # Errors
315    ///
316    /// This function will return an error if:
317    ///
318    /// * The underlying reader returns an error (except for EOF).
319    fn read_converted_to_limit_or_end<T: RawSample + BytesSample, U: FloatCore + ToPrimitive>(
320        &mut self,
321        buf: &mut Vec<U>,
322        limit: Option<usize>,
323    ) -> io::Result<usize> {
324        let mut count = 0;
325        loop {
326            match self.read_converted::<T, U>() {
327                Ok(sample) => {
328                    buf.push(sample);
329                    count += 1;
330                }
331                Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => {
332                    break;
333                }
334                Err(e) => return Err(e),
335            }
336            if let Some(limit) = limit {
337                if count >= limit {
338                    break;
339                }
340            }
341        }
342        Ok(count)
343    }
344}
345
346impl<R: io::Read + ?Sized> ReadSamples for R {}
347
348/// A trait that extends [std::io::Write] with methods for writing samples directly.
349pub trait WriteSamples: io::Write {
350    /// Write a single sample to the underlying writer.
351    ///
352    /// This method takes a reference to a sample of type `T`,
353    /// gets its raw byte representation using the `as_slice` method,
354    /// and writes it to the underlying writer.
355    ///
356    /// # Type Parameters
357    ///
358    /// * `T`: A type implementing the `BytesSample` trait, defining the format of the sample to write.
359    /// # Returns
360    ///
361    /// * `io::Result<()>`: Ok(()) if the sample was written successfully.
362    /// # Errors
363    ///
364    /// This function will return an error if:
365    ///
366    /// * The underlying writer returns an error.
367    fn write_sample<T: BytesSample>(&mut self, sample: &T) -> io::Result<()> {
368        self.write_all(sample.as_slice())
369    }
370
371    /// Write a single sample from a numeric type to the underlying writer.
372    ///
373    /// This method takes a sample represented by its `NumericType`,
374    /// converts it to a raw byte representation using the provided `T`,
375    /// and writes it to the underlying writer.
376    ///
377    /// # Type Parameters
378    ///
379    /// * `T`: A type implementing the `BytesSample` trait, defining the format of the sample to write.
380    ///
381    /// # Arguments
382    ///
383    /// * `value`: The sample to write.
384    ///
385    /// # Returns
386    ///
387    /// * `io::Result<()>`: Ok(()) if the sample was written successfully.
388    ///
389    /// # Errors
390    ///
391    /// This function will return an error if:
392    ///
393    /// * The underlying writer returns an error.
394    fn write_number<T: BytesSample>(&mut self, value: T::NumericType) -> io::Result<()> {
395        self.write_all(T::from_number(value).as_slice())
396    }
397
398    /// Write a single converted sample to the underlying writer.
399    ///
400    /// This method takes a floating-point sample of type `U`, converts it to
401    /// the raw byte representation of type `T` and then writes it to the underlying writer.
402    ///
403    /// # Type Parameters
404    ///
405    /// * `T`: A type implementing both `RawSample` and `BytesSample`, defining the format of the sample to write.
406    /// * `U`: A floating-point type implementing `FloatCore` and `ToPrimitive`, representing the sample to write.
407    ///
408    /// # Arguments
409    ///
410    /// * `value`: The sample to write.
411    ///
412    /// # Returns
413    ///
414    /// * `io::Result<bool>`: Ok(true) if the value was clipped during conversion, Ok(false) otherwise.
415    ///
416    /// # Errors
417    ///
418    /// This function will return an error if:
419    ///
420    /// * The underlying writer returns an error.
421    fn write_converted<T: RawSample + BytesSample, U: FloatCore + ToPrimitive>(
422        &mut self,
423        value: U,
424    ) -> io::Result<bool> {
425        let converted = T::from_scaled_float(value);
426        self.write_all(converted.value.as_slice())?;
427        Ok(converted.clipped)
428    }
429
430    /// Write multiple samples to the underlying writer.
431    ///
432    /// This method takes a slice of samples, gets the raw byte representation of each sample,
433    /// and then writes it to the underlying writer.
434    ///
435    /// # Type Parameters
436    ///
437    /// * `T`: A type implementing the `BytesSample` trait, defining the format of the samples to write.
438    /// # Arguments
439    ///
440    /// * `samples`: The samples to write.
441    /// # Returns
442    ///
443    /// * `io::Result<()>`: Ok(()) if all samples were written successfully.
444    /// # Errors
445    ///
446    /// This function will return an error if:
447    ///
448    /// * The underlying writer returns an error.
449    fn write_all_samples<T: BytesSample>(&mut self, samples: &[T]) -> io::Result<()> {
450        for sample in samples {
451            self.write_sample::<T>(sample)?;
452        }
453        Ok(())
454    }
455
456    /// Write multiple samples from a numeric slice to the underlying writer.
457    ///
458    /// This method takes a slice of samples represented by their `NumericType`,
459    /// converts each sample to its raw byte representation using the provided `T`,
460    /// and writes them to the underlying writer.
461    ///
462    /// # Type Parameters
463    ///
464    /// * `T`: A type implementing the `BytesSample` trait, defining the format of the samples to write.
465    ///
466    /// # Arguments
467    ///
468    /// * `values`: The samples to write.
469    ///
470    /// # Returns
471    ///
472    /// * `io::Result<()>`: Ok(()) if all samples were written successfully.
473    ///
474    /// # Errors
475    ///
476    /// This function will return an error if:
477    ///
478    /// * The underlying writer returns an error.
479    fn write_all_numbers<T: BytesSample>(&mut self, values: &[T::NumericType]) -> io::Result<()> {
480        for value in values {
481            self.write_number::<T>(*value)?;
482        }
483        Ok(())
484    }
485
486    /// Write multiple converted samples from a float slice to the underlying writer.
487    ///
488    /// This method takes a slice of floating-point samples of type `U`, converts each sample
489    /// to its raw byte representation of type `T`, and then writes them to the underlying writer.
490    ///
491    /// # Type Parameters
492    ///
493    /// * `T`: A type implementing both `RawSample` and `BytesSample`, defining the format of the samples to write.
494    /// * `U`: A floating-point type implementing `FloatCore` and `ToPrimitive`, representing the samples to write.
495    ///
496    /// # Arguments
497    ///
498    /// * `values`: The samples to write.
499    ///
500    /// # Returns
501    ///
502    /// * `io::Result<usize>`: The number of samples that were clipped during conversion.
503    ///
504    /// # Errors
505    ///
506    /// This function will return an error if:
507    ///
508    /// * The underlying writer returns an error.
509    fn write_all_converted<T: RawSample + BytesSample, U: FloatCore + ToPrimitive>(
510        &mut self,
511        values: &[U],
512    ) -> io::Result<usize> {
513        let mut nbr_clipped = 0;
514        for value in values {
515            let clipped = self.write_converted::<T, U>(*value)?;
516            if clipped {
517                nbr_clipped += 1;
518            }
519        }
520        Ok(nbr_clipped)
521    }
522}
523
524impl<W: io::Write + ?Sized> WriteSamples for W {}
525
526#[cfg(test)]
527mod tests {
528    extern crate alloc;
529
530    use super::*;
531    use crate::readwrite::ReadSamples;
532    use crate::readwrite::WriteSamples;
533
534    #[test]
535    fn test_read_number_i16() {
536        let data: Vec<u8> = vec![0, 1, 2, 3];
537        let mut slice = &data[..];
538        assert_eq!(slice.read_number::<I16_LE>().unwrap(), 256);
539        assert_eq!(slice.read_number::<I16_LE>().unwrap(), 3 * 256 + 2);
540        assert!(slice.read_number::<I16_LE>().is_err());
541    }
542
543    #[test]
544    fn test_read_converted_i16() {
545        let data: Vec<u8> = vec![0, 64, 0, 32];
546        let mut slice = &data[..];
547        assert_eq!(slice.read_converted::<I16_LE, f32>().unwrap(), 0.5);
548        assert_eq!(slice.read_converted::<I16_LE, f32>().unwrap(), 0.25);
549        assert!(slice.read_converted::<I16_LE, f32>().is_err());
550    }
551
552    #[test]
553    fn test_read_number_exact_i16() {
554        let data: Vec<u8> = vec![0, 1, 2, 3];
555        let mut slice = &data[..];
556        let mut buf = [0; 2];
557        slice.read_numbers_exact::<I16_LE>(&mut buf).unwrap();
558        assert_eq!(buf, [256, 3 * 256 + 2]);
559        assert!(slice.read_numbers_exact::<I16_LE>(&mut buf).is_err());
560    }
561
562    #[test]
563    fn test_read_converted_exact_i16() {
564        let data: Vec<u8> = vec![0, 64, 0, 32];
565        let mut slice = &data[..];
566        let mut buf = [0.0; 2];
567        slice.read_converted_exact::<I16_LE, f32>(&mut buf).unwrap();
568        assert_eq!(buf, [0.5, 0.25]);
569        assert!(slice.read_converted_exact::<I16_LE, f32>(&mut buf).is_err());
570    }
571
572    #[test]
573    fn test_read_numbers_to_end_i16() {
574        // four complete samples, and one extra byte at the end
575        let data: Vec<u8> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
576        let mut slice = &data[..];
577        let mut buf = Vec::new();
578        slice
579            .read_numbers_to_limit_or_end::<I16_LE>(&mut buf, None)
580            .unwrap();
581        assert_eq!(buf, [256, 3 * 256 + 2, 5 * 256 + 4, 7 * 256 + 6]);
582        let mut slice2 = &data[..];
583        let mut buf2 = Vec::new();
584        slice2
585            .read_numbers_to_limit_or_end::<I16_LE>(&mut buf2, Some(2))
586            .unwrap();
587        assert_eq!(buf2, [256, 3 * 256 + 2]);
588    }
589
590    #[test]
591    fn test_read_converted_to_end_i16() {
592        // four complete samples, and one extra byte at the end
593        let data: Vec<u8> = vec![0, 64, 0, 32, 0, 16, 0, 8, 0];
594        let mut slice = &data[..];
595        let mut buf = Vec::new();
596        slice
597            .read_converted_to_limit_or_end::<I16_LE, f32>(&mut buf, None)
598            .unwrap();
599        assert_eq!(buf, [0.5, 0.25, 0.125, 0.0625]);
600        let mut slice2 = &data[..];
601        let mut buf2 = Vec::new();
602        slice2
603            .read_converted_to_limit_or_end::<I16_LE, f32>(&mut buf2, Some(2))
604            .unwrap();
605        assert_eq!(buf2, [0.5, 0.25]);
606    }
607
608    #[test]
609    fn test_write_number_i16() {
610        let mut buf = Vec::new();
611        buf.write_number::<I16_LE>(256).unwrap();
612        buf.write_number::<I16_LE>(3 * 256 + 2).unwrap();
613        assert_eq!(buf, [0, 1, 2, 3]);
614    }
615
616    #[test]
617    fn test_write_converted_i16() {
618        let mut buf = Vec::new();
619        buf.write_converted::<I16_LE, f32>(0.5).unwrap();
620        buf.write_converted::<I16_LE, f32>(0.25).unwrap();
621        assert_eq!(buf, [0, 64, 0, 32]);
622    }
623
624    #[test]
625    fn test_write_all_numbers_i16() {
626        let mut buf = Vec::new();
627        buf.write_all_numbers::<I16_LE>(&[256, 3 * 256 + 2])
628            .unwrap();
629        assert_eq!(buf, [0, 1, 2, 3]);
630    }
631
632    #[test]
633    fn test_write_all_converted_i16() {
634        let mut buf = Vec::new();
635        buf.write_all_converted::<I16_LE, f32>(&[0.5, 0.25])
636            .unwrap();
637        assert_eq!(buf, [0, 64, 0, 32]);
638    }
639}