use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
pub struct AudioData {
pub samples: Vec<f32>,
pub sample_rate: u32,
pub channels: u32,
pub duration_secs: f64,
}
impl AudioData {
pub fn new(samples: Vec<f32>, sample_rate: u32) -> Self {
let duration_secs = samples.len() as f64 / sample_rate as f64;
Self {
samples,
sample_rate,
channels: 1,
duration_secs,
}
}
pub fn slice(&self, start_secs: f64, end_secs: f64) -> &[f32] {
let start_idx = (start_secs * self.sample_rate as f64) as usize;
let end_idx = (end_secs * self.sample_rate as f64) as usize;
&self.samples[start_idx.min(self.samples.len())..end_idx.min(self.samples.len())]
}
pub fn len(&self) -> usize {
self.samples.len()
}
pub fn is_empty(&self) -> bool {
self.samples.is_empty()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DominantFrequency {
pub frequency_hz: f32,
pub magnitude: f32,
pub rank: usize,
}
#[derive(Debug, Clone)]
pub struct FrequencyAnalysis {
pub spectrum: Vec<f32>,
pub frequencies: Vec<f32>,
pub spectral_centroid: f32,
pub spectral_rolloff: f32,
pub spectral_flatness: f32,
pub band_energies: BandEnergies,
pub zero_crossing_rate: f32,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct BandEnergies {
pub sub_bass: f32,
pub bass: f32,
pub low_mid: f32,
pub mid: f32,
pub high_mid: f32,
pub high: f32,
}
impl BandEnergies {
pub fn from_spectrum(spectrum: &[f32], frequencies: &[f32]) -> Self {
let bands = [
(20.0, 60.0), (60.0, 250.0), (250.0, 500.0), (500.0, 2000.0), (2000.0, 4000.0), (4000.0, 20000.0), ];
let mut energies = [0.0f32; 6];
for (i, (low, high)) in bands.iter().enumerate() {
for (j, &freq) in frequencies.iter().enumerate() {
if freq >= *low && freq < *high {
energies[i] += spectrum[j];
}
}
}
let total: f32 = energies.iter().sum();
if total > 0.0 {
for e in &mut energies {
*e /= total;
}
}
Self {
sub_bass: energies[0],
bass: energies[1],
low_mid: energies[2],
mid: energies[3],
high_mid: energies[4],
high: energies[5],
}
}
pub fn to_vec(&self) -> Vec<f32> {
vec![
self.sub_bass,
self.bass,
self.low_mid,
self.mid,
self.high_mid,
self.high,
]
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FrequencySignature {
pub features: Vec<f32>,
pub band_energies: BandEnergies,
pub centroid: f32,
pub flatness: f32,
}
impl FrequencySignature {
pub fn similarity(&self, other: &FrequencySignature) -> f32 {
if self.features.len() != other.features.len() {
return 0.0;
}
let dot: f32 = self.features.iter()
.zip(other.features.iter())
.map(|(a, b)| a * b)
.sum();
let norm_a: f32 = self.features.iter().map(|x| x * x).sum::<f32>().sqrt();
let norm_b: f32 = other.features.iter().map(|x| x * x).sum::<f32>().sqrt();
if norm_a == 0.0 || norm_b == 0.0 {
return 0.0;
}
dot / (norm_a * norm_b)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AudioFingerprint {
pub hash: String,
pub version: u32,
pub points: Vec<FingerprintPoint>,
pub duration_secs: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FingerprintPoint {
pub time_offset: u32,
pub freq_bin: u32,
pub amplitude: u8,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContentTag {
pub label: String,
pub confidence: f32,
}
#[derive(Debug, Clone)]
pub struct ProcessingConfig {
pub sample_rate: u32,
pub enable_fingerprint: bool,
pub enable_tagging: bool,
pub enable_thumbnail: bool,
pub enable_signature: bool,
}
impl Default for ProcessingConfig {
fn default() -> Self {
Self {
sample_rate: 44100,
enable_fingerprint: true,
enable_tagging: true,
enable_thumbnail: true,
enable_signature: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProcessingResult {
pub content_id: String,
pub fingerprint: Option<AudioFingerprint>,
pub tags: Vec<ContentTag>,
pub thumbnail_timestamp: Option<f64>,
pub signature: Option<FrequencySignature>,
pub dominant_frequencies: Vec<DominantFrequency>,
}
#[derive(Debug, Clone)]
pub struct FrameQuality {
pub timestamp: f64,
pub sharpness: f32,
pub contrast: f32,
pub face_count: u32,
pub score: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Recommendation {
pub content_id: String,
pub similarity: f32,
pub matching_features: Vec<String>,
}