iqengine_plugin/server/
samples_b64.rs1use 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}