diff --git a/src/audio/fft.rs b/src/audio/fft.rs new file mode 100644 index 0000000..caca333 --- /dev/null +++ b/src/audio/fft.rs @@ -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!() + } +} diff --git a/src/audio/mod.rs b/src/audio/mod.rs index bc0756b..48282aa 100644 --- a/src/audio/mod.rs +++ b/src/audio/mod.rs @@ -1,4 +1,5 @@ use std::{ + collections::VecDeque, sync::{ mpsc::{channel, Sender}, Arc, @@ -9,6 +10,7 @@ use std::{ use std::sync::mpsc::Receiver; use codec::DecoderContext; +use fft::FFTFrame; use crate::{config::Settings, player::PlayerEvent, utils::Error}; @@ -31,6 +33,7 @@ pub struct SoundManager { decoder_context: DecoderContext, playing: bool, volume: f64, + fft_frame: FFTFrame, } pub fn init( @@ -67,5 +70,6 @@ pub fn init( mod codec; mod errors; +mod fft; mod pw; mod sound_mgr; diff --git a/src/audio/sound_mgr.rs b/src/audio/sound_mgr.rs index d34aec3..24b2fdd 100644 --- a/src/audio/sound_mgr.rs +++ b/src/audio/sound_mgr.rs @@ -1,4 +1,5 @@ use std::{ + collections::VecDeque, sync::{ mpsc::{channel, Receiver, Sender, TryRecvError}, Arc, @@ -10,12 +11,12 @@ use std::{ use crate::{ config::Settings, player::PlayerEvent, - utils::{new_pw_pod, time_rem, Error}, + utils::{new_pw_pod, time_rem, Error, FFTResult}, }; 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 { pub fn init( @@ -49,6 +50,7 @@ impl SoundManager { decoder_context, playing: false, volume: 1.0, + fft_frame: FFTFrame::new(), }) } 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> { 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.sample_in.send(frame)?; match fetch_more { diff --git a/src/player/mod.rs b/src/player/mod.rs index fcb34ae..eee2248 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -13,7 +13,7 @@ use crate::{ audio::AudioEvent, config::Settings, ssonic::{response::Song, APIEvent}, - utils::Error, + utils::{Error, FFTResult}, }; pub enum PlayerEvent { @@ -23,6 +23,7 @@ pub enum PlayerEvent { PlayNext, AddAudioChunk(usize), FetchChunk, + FFTBins(FFTResult), } pub struct Player { diff --git a/src/utils.rs b/src/utils.rs index 25b5db2..b3c6f89 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -75,3 +75,5 @@ pub fn time_rem(start_time: SystemTime, target_dur: Duration) -> Result