FFT implementation boiler
This commit is contained in:
parent
013b06a3e2
commit
1c3dc2abd7
5 changed files with 56 additions and 3 deletions
29
src/audio/fft.rs
Normal file
29
src/audio/fft.rs
Normal 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!()
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)?;
|
||||
Ok(target_dur.saturating_sub(time_since))
|
||||
}
|
||||
|
||||
pub struct FFTResult {}
|
||||
|
|
Loading…
Reference in a new issue