Я хочу активировать действие (например, дать яркому свету sh), когда во время воспроизведения присутствуют бит или ударные в файле mp3. Я не знаю теоретически процедуры / подхода, который мне следует предпринять.
Сначала я подумал о статическом анализе MP3 на первом этапе. Результатом анализа будет то, в какие отметки времени должно запускаться действие. Затем я запускаю MP3, и другой поток запускает действия в заданное время c. Это должно быть легко, потому что я могу использовать rodio
-crate для воспроизведения. Но stati c анализирует части по-прежнему тяжело.
Алгоритм анализа:
Моя идея заключалась в том, чтобы прочитать необработанные аудиоданные из MP3 с использованием minimp3
- crate и выполните БПФ с помощью rustfft
-crate. Когда у меня есть анализ спектра с помощью БПФ, я могу смотреть, где глубокие частоты находятся на большой громкости, и это должно быть ритм песни.
Я пробовал комбинировать minimp3
и rustfft
, но у меня абсолютно не знаю, что на самом деле означают данные, которые я получаю .. И я тоже не могу написать для этого тест ..
Пока что это мой подход:
use minimp3::{Decoder, Frame, Error};
use std::fs::File;
use std::sync::Arc;
use rustfft::FFTplanner;
use rustfft::num_complex::Complex;
use rustfft::num_traits::{Zero, FromPrimitive, ToPrimitive};
fn main() {
let mut decoder = Decoder::new(File::open("08-In the end.mp3").unwrap());
loop {
match decoder.next_frame() {
Ok(Frame { data, sample_rate, channels, .. }) => {
// we only need mono data; because data is interleaved
// data[0] is first value channel left, data[1] is first channel right, ...
let mut mono_audio = vec![];
for i in 0..data.len() / channels {
let sum = data[i] as i32 + data[i+1] as i32;
let avg = (sum / 2) as i16;
mono_audio.push(avg);
}
// unnormalized spectrum; now check where the beat/drums are
// by checking for high volume in low frequencies
let spectrum = calc_fft(&mono_audio);
},
Err(Error::Eof) => break,
Err(e) => panic!("{:?}", e),
}
}
}
fn calc_fft(raw_mono_audio_data: &Vec<i16>) -> Vec<i16> {
// Perform a forward FFT of size 1234
let len = raw_mono_audio_data.len();
let mut input: Vec<Complex<f32>> = vec![];
//let mut output: Vec<Complex<f32>> = vec![Complex::zero(); 256];
let mut spectrum: Vec<Complex<f32>> = vec![Complex::zero(); len];
// from Vec<i16> to Vec<Complex<f32>>
raw_mono_audio_data.iter().for_each(|val| {
let compl = Complex::from_i16(*val).unwrap();
input.push(compl);
});
let mut planner = FFTplanner::new(false);
let fft = planner.plan_fft(len);
fft.process(&mut input, &mut spectrum);
// to Vec<i16>
let mut output_i16 = vec![];
spectrum.iter().for_each(|val| {
if let Some(val) = val.to_i16() {
output_i16.push(val);
}
});
output_i16
}
Моя проблема также то, что функция БПФ не имеет параметра, где я могу указать sample_rate (что составляет 48,000 кГц). Все, что я получаю от decoder.next_frame()
, - это Vec<i16>
с 2304 элементами ..
Есть идеи, как я могу этого добиться и что на самом деле означают цифры, которые я получаю в настоящее время?