FFT implementation boiler

This commit is contained in:
Muaz Ahmad 2024-12-10 15:10:37 +05:00
parent 013b06a3e2
commit 1c3dc2abd7
5 changed files with 56 additions and 3 deletions

29
src/audio/fft.rs Normal file
View file

@ -0,0 +1,29 @@
use crate::utils::FFTResult;
use std::collections::VecDeque;
pub struct FFTFrame {
buffer: VecDeque<[[i16; 480]; 2]>,
}
impl FFTFrame {
pub fn new() -> FFTFrame {
let mut frame = FFTFrame {
buffer: VecDeque::new(),
};
for _ in 0..5 {
frame.push([[0; 480]; 2]);
}
frame
}
pub fn push(&mut self, new_samples: [[i16; 480]; 2]) {
if self.buffer.len() == 5 {
self.buffer.pop_front();
}
self.buffer.push_back(new_samples);
}
pub fn compute(&self) -> FFTResult {
unimplemented!()
}
}

View file

@ -1,4 +1,5 @@
use std::{ use std::{
collections::VecDeque,
sync::{ sync::{
mpsc::{channel, Sender}, mpsc::{channel, Sender},
Arc, Arc,
@ -9,6 +10,7 @@ use std::{
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use codec::DecoderContext; use codec::DecoderContext;
use fft::FFTFrame;
use crate::{config::Settings, player::PlayerEvent, utils::Error}; use crate::{config::Settings, player::PlayerEvent, utils::Error};
@ -31,6 +33,7 @@ pub struct SoundManager {
decoder_context: DecoderContext, decoder_context: DecoderContext,
playing: bool, playing: bool,
volume: f64, volume: f64,
fft_frame: FFTFrame,
} }
pub fn init( pub fn init(
@ -67,5 +70,6 @@ pub fn init(
mod codec; mod codec;
mod errors; mod errors;
mod fft;
mod pw; mod pw;
mod sound_mgr; mod sound_mgr;

View file

@ -1,4 +1,5 @@
use std::{ use std::{
collections::VecDeque,
sync::{ sync::{
mpsc::{channel, Receiver, Sender, TryRecvError}, mpsc::{channel, Receiver, Sender, TryRecvError},
Arc, Arc,
@ -10,12 +11,12 @@ use std::{
use crate::{ use crate::{
config::Settings, config::Settings,
player::PlayerEvent, player::PlayerEvent,
utils::{new_pw_pod, time_rem, Error}, utils::{new_pw_pod, time_rem, Error, FFTResult},
}; };
const VOLUME_CHANGE_INTERVAL: f64 = 0.05; const VOLUME_CHANGE_INTERVAL: f64 = 0.05;
use super::{codec, errors::AudioError, pw, AudioEvent, SoundManager}; use super::{codec, errors::AudioError, fft::FFTFrame, pw, AudioEvent, SoundManager};
impl SoundManager { impl SoundManager {
pub fn init( pub fn init(
@ -49,6 +50,7 @@ impl SoundManager {
decoder_context, decoder_context,
playing: false, playing: false,
volume: 1.0, volume: 1.0,
fft_frame: FFTFrame::new(),
}) })
} }
pub fn begin(&mut self) -> Result<(), Error> { pub fn begin(&mut self) -> Result<(), Error> {
@ -81,8 +83,23 @@ impl SoundManager {
} }
} }
fn fft_compute(&mut self, frame: &[u8]) -> FFTResult {
let mut samples = [[0; 480]; 2];
for i in 0..frame.len() / 4 {
for j in 0..2 {
let mut val_buff = [0; 2];
val_buff.copy_from_slice(&frame[4 * i + 2 * j..4 * i + 2 * j + 2]);
samples[i][j] = i16::from_le_bytes(val_buff);
}
}
self.fft_frame.push(samples);
self.fft_frame.compute()
}
fn push_samples(&mut self) -> Result<(), Error> { fn push_samples(&mut self) -> Result<(), Error> {
let (mut frame, fetch_more) = self.decoder_context.next_sample(); let (mut frame, fetch_more) = self.decoder_context.next_sample();
let bins = self.fft_compute(frame.as_slice());
self.player_chan.send(PlayerEvent::FFTBins(bins))?;
self.adjust_volume(frame.as_mut_slice()); self.adjust_volume(frame.as_mut_slice());
self.sample_in.send(frame)?; self.sample_in.send(frame)?;
match fetch_more { match fetch_more {

View file

@ -13,7 +13,7 @@ use crate::{
audio::AudioEvent, audio::AudioEvent,
config::Settings, config::Settings,
ssonic::{response::Song, APIEvent}, ssonic::{response::Song, APIEvent},
utils::Error, utils::{Error, FFTResult},
}; };
pub enum PlayerEvent { pub enum PlayerEvent {
@ -23,6 +23,7 @@ pub enum PlayerEvent {
PlayNext, PlayNext,
AddAudioChunk(usize), AddAudioChunk(usize),
FetchChunk, FetchChunk,
FFTBins(FFTResult),
} }
pub struct Player { pub struct Player {

View file

@ -75,3 +75,5 @@ pub fn time_rem(start_time: SystemTime, target_dur: Duration) -> Result<Duration
let time_since = SystemTime::now().duration_since(start_time)?; let time_since = SystemTime::now().duration_since(start_time)?;
Ok(target_dur.saturating_sub(time_since)) Ok(target_dur.saturating_sub(time_since))
} }
pub struct FFTResult {}