OxiFFT スペクトラムアナライザ

スペクトログラム(時間経過表示)
モーション低減が有効のため、瞬時スペクトラムのみ表示しています
瞬時スペクトラム表示
入力信号

FFT サイズ
窓関数
oxifftv— (Pure Rust, Apache-2.0)
targetwasm32-unknown-unknown
wasm size179 KB (gzip 74 KB)
fft size2048
frame time
frames computed0
server round-trips0
C / C++ / Fortran0 bytes

実装コード

// crates/oxifft-wasm/src/analyzer.rs:107-139 — verbatim, the code running above
pub fn process_inner(&mut self, samples: &[f32]) -> Result<Vec<f32>, OxiFftWasmError> {
    if samples.len() != self.fft_size {
        return Err(OxiFftWasmError::FrameLength {
            expected: self.fft_size,
            got: samples.len(),
        });
    }

    // 1. Apply the window.
    for ((windowed, &sample), &coefficient) in
        self.scratch.iter_mut().zip(samples).zip(&self.window)
    {
        *windowed = sample * coefficient;
    }

    // 2. Unnormalised forward real FFT -> fft_size/2 + 1 complex bins.
    self.solver.execute(&self.scratch, &mut self.spectrum_scratch);

    // 3. Magnitude -> single-sided amplitude -> dBFS.
    //    Bin 0 is DC and has no mirror partner, so it is not doubled. The
    //    Nyquist bin (fft_size/2) is the other undoubled bin, but it is
    //    dropped here: the contract is a spectrum of length fft_size/2.
    let bins = self.fft_size / 2;
    let mut decibels = Vec::with_capacity(bins);
    for (index, bin) in self.spectrum_scratch.iter().take(bins).enumerate() {
        let fold = if index == 0 { 1.0_f32 } else { 2.0_f32 };
        let amplitude = fold * bin.norm() * self.inv_gain;
        decibels.push(20.0_f32 * amplitude.max(AMPLITUDE_FLOOR).log10());
    }

    self.frames = self.frames.saturating_add(1);
    Ok(decibels)
}

これがいま上で動いているコードです。