1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use crate::strategies::{lpf, spectrum};
use crate::strategies::lpf::LpfBeatDetector;
mod strategies;
#[derive(Debug)]
pub struct BeatInfo {
relative_ms: u32,
}
impl BeatInfo {
pub fn new(relative_ms: u32) -> Self {
Self {
relative_ms,
}
}
}
pub trait Strategy {
fn is_beat(&self, samples: &[i16]) -> Option<BeatInfo>;
}
#[derive(Debug)]
pub enum StrategyKind {
LPF,
Spectrum,
}
impl StrategyKind {
fn detector(&self, sampling_rate: u32, window_length: u16) -> impl Strategy {
match self {
StrategyKind::LPF => LpfBeatDetector::new(sampling_rate, window_length),
StrategyKind::Spectrum => todo!(),
_ => panic!("Unknown Strategy")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use minimp3::{Decoder as Mp3Decoder, Error as Mp3Error, Frame as Mp3Frame};
use std::fs::File;
#[test]
fn test_sample_1_print_beats() {
let (mut sample_1_audio_data, sampling_rate) = read_mp3_to_mono("res/sample_1.mp3");
assert_eq!(sampling_rate, 44100, "The sampling rate of the MP3 examples must be 44100Hz.");
let window_length = 2048;
let remainder = sample_1_audio_data.len() % window_length;
if remainder != 0 {
sample_1_audio_data.extend_from_slice(
&vec![0; remainder]
)
}
let window_count = sample_1_audio_data.len() / window_length;
let strategies = vec![
StrategyKind::LPF,
];
for strategy in strategies {
let detector = strategy.detector(44100, window_length as u16);
let mut beats = Vec::new();
for i in 0..window_count {
let window = &sample_1_audio_data[i * window_length..(i+1) * window_length];
beats.push(
detector.is_beat(window)
);
}
println!("{:#?}", beats.iter().filter(|x| x.is_some()).collect::<Vec<&Option<BeatInfo>>>());
}
}
fn read_mp3_to_mono(file: &str) -> (Vec<i16>, u32) {
let mut decoder = Mp3Decoder::new(File::open(file).unwrap());
let mut sampling_rate = 0;
let mut mono_samples = vec![];
loop {
match decoder.next_frame() {
Ok(Mp3Frame {
data: samples_of_frame,
sample_rate,
channels,
..
}) => {
sampling_rate = sample_rate;
if channels == 2 {
for (i, sample) in samples_of_frame.iter().enumerate().step_by(2) {
let sample = *sample as i32;
let next_sample = samples_of_frame[i + 1] as i32;
mono_samples.push(
((sample + next_sample) as f32 / 2.0) as i16
);
}
} else if channels == 1 {
mono_samples.extend_from_slice(&samples_of_frame);
} else {
panic!("Unsupported number of channels={}", channels);
}
}
Err(Mp3Error::Eof) => break,
Err(e) => panic!("{:?}", e),
}
}
(mono_samples, sampling_rate as u32)
}
}