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::{
|
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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
Loading…
Reference in a new issue