OxiFFT スペクトラムアナライザ
モーション低減が有効のため、瞬時スペクトラムのみ表示しています
| oxifft | v— (Pure Rust, Apache-2.0) |
|---|---|
| target | wasm32-unknown-unknown |
| wasm size | 179 KB (gzip 74 KB) |
| fft size | 2048 |
| frame time | — |
| frames computed | 0 |
| server round-trips | 0 |
| C / C++ / Fortran | 0 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)
} これがいま上で動いているコードです。