ez_audi/cpal_abstraction/samples/
samples.rs

1use cpal::{self, Sample as CpalSampleTrait};
2
3use crate::{traits::AudioMetadataTrait, audio_codecs::AudioCodec};
4
5use super::{SampleType, Sample, IntermediateSampleType};
6
7#[derive(Debug, Clone)]
8/// A sample container of LPcm samples ready to be send to audio streams
9pub struct Samples<T: Sample> {
10    /// A an ordered vector of all the samples,
11    /// if there are multiple channels, each channel will have their own sample
12    /// 
13    /// ex: 1 channel: \[s1, s2, s3]
14    ///
15    /// 2 channels: \[s-left1, s-right1, s-left-2, s-right-2, s-left-3, s-right-3]
16    pub samples: Vec<T>,
17    /// The metadata of the Samples, dictates how they are consumed and modified.
18    /// There is no guarenty that the metadata reflects the actual intended metadata.
19    pub metadata: SamplesMetadata,
20}
21
22impl<T: Sample> Samples<T> {
23    /// Creates a new Samples struct
24    pub fn new(samples: Vec<T>, metadata: SamplesMetadata) -> Samples<T> {
25        Samples {
26            samples,
27            metadata,
28        }
29    }
30
31    /// Updates the sample in the metadata based on the real generic sample type
32    fn update_sample_type(&mut self) {
33        self.metadata.sample_type = match self.samples.get(0) {
34            Some(t) => (*t).into(),
35            None => self.metadata.sample_type.clone(),
36        }
37    }
38}
39
40impl Samples<IntermediateSampleType> {
41    /// Turns the samples into the desired sample type, does not clone
42    pub fn into_t_samples<T: Sample + cpal::FromSample<IntermediateSampleType>>(self) -> Samples<T> {
43        let samples = self.samples.into_iter()
44            .map(|s| s.to_sample::<T>())
45            .collect();
46
47        let metadata = self.metadata.clone();
48        let mut samples = Samples::new(samples, metadata);
49        
50        samples.update_sample_type();
51
52        samples
53    }
54}
55
56/// This is used to be able to store `Samples` Struct of multiple generic type in `Box`
57pub trait SamplesTrait {
58    /// Transforms the samples into `IntermediateSampleType`, does not clone
59    fn into_generic_representation_samples(self) -> Samples<IntermediateSampleType>;
60
61    /// Makes a clone of the samples in the `IntermediateSampleType`
62    fn generic_representation_samples(&self) -> Samples<IntermediateSampleType>;
63
64    /// Gets the metadata of the samples
65    fn metadata(&self) -> Box<dyn AudioMetadataTrait>;
66}
67
68impl<T: Sample> SamplesTrait for Samples<T>
69where IntermediateSampleType: cpal::FromSample<T> {
70    fn into_generic_representation_samples(self) -> Samples<IntermediateSampleType> {
71        let f32_samples = self.samples.into_iter().map(|s| s.to_sample()).collect();
72
73        let mut samples = Samples::new(f32_samples, self.metadata.clone());
74        samples.update_sample_type();
75
76        samples
77    }
78
79    fn generic_representation_samples(&self) -> Samples<IntermediateSampleType> {
80        let f32_samples = self.samples.clone().into_iter().map(|s| s.to_sample()).collect();
81
82        let mut samples = Samples::new(f32_samples, self.metadata.clone());
83        samples.update_sample_type();
84
85        samples
86    }
87
88    fn metadata(&self) -> Box<dyn AudioMetadataTrait> {
89        Box::new(self.metadata.clone())
90    }
91}
92
93#[derive(Debug, Clone)]
94/// Metadata about audio samples, normally used with the `Samples` struct
95pub struct SamplesMetadata {
96    /// Numbers of channels: mono = 1, Stereo = 2, etc...
97    pub channels: u16,
98    /// The number of samples per a mount of time
99    pub sample_rate: u32,
100    /// The type of the samples
101    pub sample_type: SampleType,
102}
103
104impl SamplesMetadata {
105    pub fn new(channels: u16, sample_rate: u32, sample_type: SampleType) -> SamplesMetadata {
106        SamplesMetadata { 
107            channels,
108            sample_rate,
109            sample_type,
110        }
111    }
112}
113
114impl AudioMetadataTrait for SamplesMetadata {
115    fn file_path(&self) -> Option<String> {
116        None
117    }
118
119    // TODO: Is it right to say that the samples are in LPcm since don't have to got through any other codec? 
120    fn audio_codec(&self) -> crate::audio_codecs::AudioCodec {
121        AudioCodec::LPcm
122    }
123
124    fn channels(&self) -> u32 {
125        self.channels as u32
126    }
127
128    fn sample_rate(&self) -> u32 {
129        self.sample_rate
130    }
131
132    fn sample_type(&self) -> Option<SampleType> {
133        Some(self.sample_type.clone())
134    }
135}
136
137impl From<&SamplesMetadata> for cpal::SupportedStreamConfig {
138    fn from(value: &SamplesMetadata) -> Self {
139        let channels = value.channels;
140        let sample_rate = cpal::SampleRate(value.sample_rate);
141        let sample_type = value.sample_type.clone().into();
142
143        cpal::SupportedStreamConfig::new(channels, sample_rate, cpal::SupportedBufferSize::Unknown, sample_type)
144    }
145}