Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement AnalyserNode #127

Merged
merged 7 commits into from Sep 14, 2018

Add blackman windowing

  • Loading branch information
Manishearth committed Sep 14, 2018
commit 18d7b52bbac47bddd77e87b083bf05b937142a1a
@@ -2,8 +2,9 @@ use block::{Block, Chunk, FRAMES_PER_BLOCK_USIZE};
use node::AudioNodeEngine;
use node::BlockInfo;
use node::{AudioNodeType, ChannelInfo, ChannelInterpretation};
use std::f32::consts::PI;
use std::sync::mpsc::Sender;

use std::mem;

#[derive(AudioNodeCommon)]
pub(crate) struct AnalyserNode {
@@ -53,6 +54,19 @@ pub struct AnalysisEngine {
current_block: usize,
/// Have we computed the FFT already?
fft_computed: bool,
/// Cached blackman window data
blackman_windows: Vec<f32>,
/// The computed FFT data (in frequency domain)
computed_fft_data: Vec<f32>,

// these two vectors are for temporary buffers
// that we keep around for efficiency

/// The windowed time domain data
/// Used during FFT computation
windowed: Vec<f32>,
/// Scratch space used during the actual FFT computation
tmp_transformed: Vec<f32>
}

impl AnalysisEngine {
@@ -62,6 +76,10 @@ impl AnalysisEngine {
data: Box::new([0.; MAX_FFT_SIZE]),
current_block: MAX_BLOCK_COUNT - 1,
fft_computed: false,
blackman_windows: Vec::with_capacity(fft_size),
computed_fft_data: Vec::with_capacity(fft_size / 2),
windowed: Vec::with_capacity(fft_size),
tmp_transformed: Vec::with_capacity(fft_size / 2),
}
}

@@ -97,11 +115,45 @@ impl AnalysisEngine {
self.fft_computed = false;
}

/// https://webaudio.github.io/web-audio-api/#blackman-window
fn compute_blackman_windows(&mut self) {
if self.blackman_windows.len() == self.fft_size {
return;
}
const ALPHA: f32 = 0.16;
const ALPHA_0: f32 = (1. - ALPHA) / 2.;
const ALPHA_1: f32 = 1. / 2.;
const ALPHA_2: f32 = ALPHA / 2.;
self.blackman_windows.resize(self.fft_size, 0.);
let coeff = PI * 2. / self.fft_size as f32;
for n in 0..self.fft_size {
self.blackman_windows[n] = ALPHA_0 - ALPHA_1 * (coeff * n as f32).cos()
+ ALPHA_2 * (2. * coeff * n as f32).cos();
}
}

fn apply_blackman_window(&mut self) {
self.compute_blackman_windows();
// avoids conflicting borrows with data_mut
let mut windowed = mem::replace(&mut self.windowed, Vec::new());
windowed.resize(self.fft_size, 0.);
let mut n = 0;
for offset in (0..self.fft_size).rev() {
let data = self.block_mut(offset);
for frame in 0..FRAMES_PER_BLOCK_USIZE {
windowed[n] = data[frame];
n += 1;
}
}
self.windowed = windowed;
}

fn compute_fft(&mut self) {
if self.fft_computed {
return;
}
self.fft_computed = true;
self.apply_blackman_window();
// ...
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.