1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone)]
7pub struct AudioData {
8 pub samples: Vec<f32>,
10 pub sample_rate: u32,
12 pub channels: u32,
14 pub duration_secs: f64,
16}
17
18impl AudioData {
19 pub fn new(samples: Vec<f32>, sample_rate: u32) -> Self {
21 let duration_secs = samples.len() as f64 / sample_rate as f64;
22 Self {
23 samples,
24 sample_rate,
25 channels: 1,
26 duration_secs,
27 }
28 }
29
30 pub fn slice(&self, start_secs: f64, end_secs: f64) -> &[f32] {
32 let start_idx = (start_secs * self.sample_rate as f64) as usize;
33 let end_idx = (end_secs * self.sample_rate as f64) as usize;
34 &self.samples[start_idx.min(self.samples.len())..end_idx.min(self.samples.len())]
35 }
36
37 pub fn len(&self) -> usize {
39 self.samples.len()
40 }
41
42 pub fn is_empty(&self) -> bool {
44 self.samples.is_empty()
45 }
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct DominantFrequency {
51 pub frequency_hz: f32,
53 pub magnitude: f32,
55 pub rank: usize,
57}
58
59#[derive(Debug, Clone)]
61pub struct FrequencyAnalysis {
62 pub spectrum: Vec<f32>,
64 pub frequencies: Vec<f32>,
66 pub spectral_centroid: f32,
68 pub spectral_rolloff: f32,
70 pub spectral_flatness: f32,
72 pub band_energies: BandEnergies,
74 pub zero_crossing_rate: f32,
76}
77
78#[derive(Debug, Clone, Default, Serialize, Deserialize)]
80pub struct BandEnergies {
81 pub sub_bass: f32,
83 pub bass: f32,
85 pub low_mid: f32,
87 pub mid: f32,
89 pub high_mid: f32,
91 pub high: f32,
93}
94
95impl BandEnergies {
96 pub fn from_spectrum(spectrum: &[f32], frequencies: &[f32]) -> Self {
98 let bands = [
99 (20.0, 60.0), (60.0, 250.0), (250.0, 500.0), (500.0, 2000.0), (2000.0, 4000.0), (4000.0, 20000.0), ];
106
107 let mut energies = [0.0f32; 6];
108
109 for (i, (low, high)) in bands.iter().enumerate() {
110 for (j, &freq) in frequencies.iter().enumerate() {
111 if freq >= *low && freq < *high {
112 energies[i] += spectrum[j];
113 }
114 }
115 }
116
117 let total: f32 = energies.iter().sum();
119 if total > 0.0 {
120 for e in &mut energies {
121 *e /= total;
122 }
123 }
124
125 Self {
126 sub_bass: energies[0],
127 bass: energies[1],
128 low_mid: energies[2],
129 mid: energies[3],
130 high_mid: energies[4],
131 high: energies[5],
132 }
133 }
134
135 pub fn to_vec(&self) -> Vec<f32> {
137 vec![
138 self.sub_bass,
139 self.bass,
140 self.low_mid,
141 self.mid,
142 self.high_mid,
143 self.high,
144 ]
145 }
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct FrequencySignature {
151 pub features: Vec<f32>,
153 pub band_energies: BandEnergies,
155 pub centroid: f32,
157 pub flatness: f32,
159}
160
161impl FrequencySignature {
162 pub fn similarity(&self, other: &FrequencySignature) -> f32 {
164 if self.features.len() != other.features.len() {
165 return 0.0;
166 }
167
168 let dot: f32 = self.features.iter()
169 .zip(other.features.iter())
170 .map(|(a, b)| a * b)
171 .sum();
172
173 let norm_a: f32 = self.features.iter().map(|x| x * x).sum::<f32>().sqrt();
174 let norm_b: f32 = other.features.iter().map(|x| x * x).sum::<f32>().sqrt();
175
176 if norm_a == 0.0 || norm_b == 0.0 {
177 return 0.0;
178 }
179
180 dot / (norm_a * norm_b)
181 }
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct AudioFingerprint {
187 pub hash: String,
189 pub version: u32,
191 pub points: Vec<FingerprintPoint>,
193 pub duration_secs: f64,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct FingerprintPoint {
200 pub time_offset: u32,
202 pub freq_bin: u32,
204 pub amplitude: u8,
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct ContentTag {
211 pub label: String,
213 pub confidence: f32,
215}
216
217#[derive(Debug, Clone)]
219pub struct ProcessingConfig {
220 pub sample_rate: u32,
222 pub enable_fingerprint: bool,
224 pub enable_tagging: bool,
226 pub enable_thumbnail: bool,
228 pub enable_signature: bool,
230}
231
232impl Default for ProcessingConfig {
233 fn default() -> Self {
234 Self {
235 sample_rate: 44100,
236 enable_fingerprint: true,
237 enable_tagging: true,
238 enable_thumbnail: true,
239 enable_signature: true,
240 }
241 }
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct ProcessingResult {
247 pub content_id: String,
249 pub fingerprint: Option<AudioFingerprint>,
251 pub tags: Vec<ContentTag>,
253 pub thumbnail_timestamp: Option<f64>,
255 pub signature: Option<FrequencySignature>,
257 pub dominant_frequencies: Vec<DominantFrequency>,
259}
260
261#[derive(Debug, Clone)]
263pub struct FrameQuality {
264 pub timestamp: f64,
266 pub sharpness: f32,
268 pub contrast: f32,
270 pub face_count: u32,
272 pub score: f32,
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct Recommendation {
279 pub content_id: String,
281 pub similarity: f32,
283 pub matching_features: Vec<String>,
285}