iqengine_plugin/server/
samples_b64.rs

1use std::path::Path;
2
3use base64::{engine::general_purpose, Engine as _};
4use num_complex::{Complex, Complex32, ComplexFloat};
5
6use super::error::IQEngineError;
7
8#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
9pub struct SamplesB64 {
10    #[serde(rename = "samples")]
11    pub samples: String,
12    #[serde(rename = "data_type")]
13    pub data_type: crate::server::DataType,
14    #[serde(rename = "sample_rate", skip_serializing_if = "Option::is_none")]
15    pub sample_rate: Option<f32>,
16    #[serde(rename = "center_freq", skip_serializing_if = "Option::is_none")]
17    pub center_freq: Option<f32>,
18}
19
20impl SamplesB64 {
21    pub fn new(samples: String, data_type: crate::server::DataType) -> SamplesB64 {
22        SamplesB64 {
23            samples,
24            data_type,
25            sample_rate: None,
26            center_freq: None,
27        }
28    }
29
30    pub fn raw(self) -> Result<Vec<u8>, IQEngineError> {
31        Ok(general_purpose::STANDARD.decode(self.samples)?)
32    }
33
34    pub fn samples_f32(self) -> Result<Vec<f32>, IQEngineError> {
35        let bytes = general_purpose::STANDARD.decode(self.samples)?;
36        let v: Vec<f32> = bytes
37            .array_chunks::<4>()
38            .map(|a| f32::from_le_bytes(*a))
39            .collect();
40        Ok(v)
41    }
42
43    pub fn samples_cf32(self) -> Result<Vec<Complex32>, IQEngineError> {
44        let bytes = general_purpose::STANDARD.decode(self.samples)?;
45        let v: Vec<Complex32> = bytes
46            .array_chunks::<4>()
47            .map(|a| f32::from_le_bytes(*a))
48            .array_chunks::<2>()
49            .map(|f2| Complex {
50                re: f2[0],
51                im: f2[1],
52            })
53            .collect();
54        Ok(v)
55    }
56
57    pub fn samples_ci16(self) -> Result<Vec<Complex<i16>>, IQEngineError> {
58        let bytes = general_purpose::STANDARD.decode(self.samples)?;
59        let v: Vec<Complex<i16>> = bytes
60            .array_chunks::<2>()
61            .map(|a| i16::from_le_bytes(*a))
62            .array_chunks::<2>()
63            .map(|f2| Complex {
64                re: f2[0],
65                im: f2[1],
66            })
67            .collect();
68        Ok(v)
69    }
70
71    pub fn samples_ci8(self) -> Result<Vec<Complex<i8>>, IQEngineError> {
72        let bytes = general_purpose::STANDARD.decode(self.samples)?;
73        let v: Vec<Complex<i8>> = bytes
74            .array_chunks::<1>()
75            .map(|a| i8::from_le_bytes(*a))
76            .array_chunks::<2>()
77            .map(|f2| Complex {
78                re: f2[0],
79                im: f2[1],
80            })
81            .collect();
82        Ok(v)
83    }
84}
85
86pub struct SamplesB64Builder {
87    samples: Option<String>,
88    data_type: Option<crate::server::DataType>,
89    sample_rate: Option<f32>,
90    center_freq: Option<f32>,
91    error: Option<IQEngineError>,
92}
93
94impl Default for SamplesB64Builder {
95    fn default() -> Self {
96        Self::new()
97    }
98}
99
100impl SamplesB64Builder {
101    pub fn new() -> SamplesB64Builder {
102        SamplesB64Builder {
103            samples: None,
104            data_type: None,
105            sample_rate: None,
106            center_freq: None,
107            error: None,
108        }
109    }
110
111    pub fn same_as(samples: &SamplesB64) -> SamplesB64Builder {
112        SamplesB64Builder {
113            samples: None,
114            data_type: Some(samples.data_type),
115            sample_rate: samples.sample_rate,
116            center_freq: samples.center_freq,
117            error: None,
118        }
119    }
120
121    pub fn with_samples_cf32(mut self, samples: Vec<Complex32>) -> Self {
122        self.data_type = Some(super::DataType::IqSlashCf32Le);
123        let o = samples
124            .iter()
125            .flat_map(|x| [x.re(), x.im()])
126            .flat_map(f32::to_le_bytes);
127        let o: Vec<u8> = o.collect();
128        let o = general_purpose::STANDARD.encode(o);
129        self.samples = Some(o);
130        self
131    }
132
133    pub fn from_wav_file(mut self, filename: &Path) -> Self {
134        let content = std::fs::read(filename);
135        if let Ok(content) = content {
136            let content = general_purpose::STANDARD.encode(content);
137            self.samples = Some(content);
138        } else {
139            self.error = Some(IQEngineError::IOError(content.unwrap_err()));
140        }
141        self.data_type = Some(super::DataType::AudioSlashWav);
142        self
143    }
144
145    pub fn from_wav_data(mut self, samples: impl AsRef<[u8]>) -> Self {
146        let content = general_purpose::STANDARD.encode(samples);
147        self.samples = Some(content);
148        self.data_type = Some(super::DataType::AudioSlashWav);
149        self
150    }
151
152    pub fn build(self) -> Result<SamplesB64, IQEngineError> {
153        if self.error.is_some() {
154            return Err(self.error.unwrap());
155        }
156        Ok(SamplesB64 {
157            samples: self.samples.unwrap(),
158            center_freq: self.center_freq,
159            data_type: self.data_type.unwrap(),
160            sample_rate: self.sample_rate,
161        })
162    }
163}