Skip to content

Commit 1a1d426

Browse files
authored
Merge pull request #2 from wagnerf42/master
removed intermediate vec and indices
2 parents 5393e70 + 8379ac7 commit 1a1d426

File tree

5 files changed

+261
-216
lines changed

5 files changed

+261
-216
lines changed

src/detector/autocorrelation.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,40 @@
1-
use crate::float::Float;
2-
use crate::detector::PitchDetector;
3-
use crate::detector::internals::DetectorInternals;
4-
use crate::detector::internals::Pitch;
51
use crate::detector::internals::autocorrelation;
62
use crate::detector::internals::get_power_level;
73
use crate::detector::internals::pitch_from_peaks;
4+
use crate::detector::internals::DetectorInternals;
5+
use crate::detector::internals::Pitch;
6+
use crate::detector::PitchDetector;
7+
use crate::float::Float;
88
use crate::utils::peak::PeakCorrection;
99

10-
1110
pub struct AutocorrelationDetector<T>
12-
where T : Float
11+
where
12+
T: Float,
1313
{
14-
internals: DetectorInternals<T>
14+
internals: DetectorInternals<T>,
1515
}
1616

1717
impl<T> AutocorrelationDetector<T>
18-
where T: Float
18+
where
19+
T: Float,
1920
{
2021
pub fn new(size: usize, padding: usize) -> Self {
2122
let internals = DetectorInternals::new(1, 2, size, padding);
22-
AutocorrelationDetector {
23-
internals
24-
}
23+
AutocorrelationDetector { internals }
2524
}
2625
}
2726

2827
impl<T> PitchDetector<T> for AutocorrelationDetector<T>
29-
where T : Float
28+
where
29+
T: Float + std::iter::Sum,
3030
{
31-
fn get_pitch(&mut self, signal: &[T], sample_rate: usize, power_threshold: T, clarity_threshold: T) -> Option<Pitch<T>> {
31+
fn get_pitch(
32+
&mut self,
33+
signal: &[T],
34+
sample_rate: usize,
35+
power_threshold: T,
36+
clarity_threshold: T,
37+
) -> Option<Pitch<T>> {
3238
assert_eq!(signal.len(), self.internals.size);
3339

3440
if get_power_level(signal) < power_threshold {
@@ -42,6 +48,11 @@ impl<T> PitchDetector<T> for AutocorrelationDetector<T>
4248
autocorrelation(signal, signal_complex, scratch, autocorr);
4349
let clarity_threshold = clarity_threshold * autocorr[0];
4450

45-
pitch_from_peaks(autocorr, sample_rate, clarity_threshold, PeakCorrection::None)
51+
pitch_from_peaks(
52+
autocorr,
53+
sample_rate,
54+
clarity_threshold,
55+
PeakCorrection::None,
56+
)
4657
}
4758
}

src/detector/internals.rs

Lines changed: 72 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,45 @@
1-
use rustfft::FFTplanner;
21
use num_complex::Complex;
2+
use rustfft::FFTplanner;
33

44
use crate::float::Float;
5-
use crate::utils::buffer::ComplexComponent;
6-
use crate::utils::buffer::copy_real_to_complex;
75
use crate::utils::buffer::copy_complex_to_real;
8-
use crate::utils::buffer::new_real_buffer;
6+
use crate::utils::buffer::copy_real_to_complex;
97
use crate::utils::buffer::new_complex_buffer;
10-
use crate::utils::peak::PeakCorrection;
11-
use crate::utils::peak::detect_peaks;
8+
use crate::utils::buffer::new_real_buffer;
9+
use crate::utils::buffer::ComplexComponent;
1210
use crate::utils::peak::choose_peak;
1311
use crate::utils::peak::correct_peak;
12+
use crate::utils::peak::detect_peaks;
13+
use crate::utils::peak::PeakCorrection;
1414

1515
pub struct Pitch<T>
16-
where T: Float
16+
where
17+
T: Float,
1718
{
1819
pub frequency: T,
19-
pub clarity: T
20+
pub clarity: T,
2021
}
2122

2223
pub struct DetectorInternals<T>
23-
where T: Float
24+
where
25+
T: Float,
2426
{
2527
pub size: usize,
2628
pub padding: usize,
2729
pub real_buffers: Vec<Vec<T>>,
28-
pub complex_buffers: Vec<Vec<Complex<T>>>
30+
pub complex_buffers: Vec<Vec<Complex<T>>>,
2931
}
3032

3133
impl<T> DetectorInternals<T>
32-
where T : Float
34+
where
35+
T: Float,
3336
{
34-
pub fn new(n_real_buffers: usize, n_complex_buffers: usize, size: usize, padding: usize) -> Self {
37+
pub fn new(
38+
n_real_buffers: usize,
39+
n_complex_buffers: usize,
40+
size: usize,
41+
padding: usize,
42+
) -> Self {
3543
let mut real_buffers: Vec<Vec<T>> = Vec::new();
3644
let mut complex_buffers: Vec<Vec<Complex<T>>> = Vec::new();
3745

@@ -49,98 +57,92 @@ impl<T> DetectorInternals<T>
4957
size,
5058
padding,
5159
real_buffers,
52-
complex_buffers
60+
complex_buffers,
5361
}
5462
}
5563
}
5664

57-
pub fn autocorrelation<T>(signal: &[T], signal_complex: &mut [Complex<T>], scratch: &mut [Complex<T>], result: &mut [T])
58-
where T : Float
65+
pub fn autocorrelation<T>(
66+
signal: &[T],
67+
signal_complex: &mut [Complex<T>],
68+
scratch: &mut [Complex<T>],
69+
result: &mut [T],
70+
) where
71+
T: Float,
5972
{
6073
copy_real_to_complex(signal, signal_complex, ComplexComponent::Re);
6174
let mut planner = FFTplanner::new(false);
6275
let fft = planner.plan_fft(signal_complex.len());
6376
fft.process(signal_complex, scratch);
64-
for i in 0..scratch.len() {
65-
scratch[i].re = scratch[i].re * scratch[i].re + scratch[i].im * scratch[i].im;
66-
scratch[i].im = T::zero();
67-
}
77+
scratch.iter_mut().for_each(|s| {
78+
s.re = s.re * s.re + s.im * s.im;
79+
s.im = T::zero();
80+
});
6881
let mut planner = FFTplanner::new(true);
6982
let inv_fft = planner.plan_fft(signal_complex.len());
7083
inv_fft.process(scratch, signal_complex);
7184
copy_complex_to_real(signal_complex, result, ComplexComponent::Re);
7285
}
7386

74-
pub fn pitch_from_peaks<T>(input: &[T], sample_rate: usize, clarity_threshold: T, correction: PeakCorrection) -> Option<Pitch<T>>
75-
where T: Float
87+
pub fn pitch_from_peaks<T>(
88+
input: &[T],
89+
sample_rate: usize,
90+
clarity_threshold: T,
91+
correction: PeakCorrection,
92+
) -> Option<Pitch<T>>
93+
where
94+
T: Float,
7695
{
7796
let peaks = detect_peaks(input);
78-
let chosen_peak = choose_peak(&peaks, clarity_threshold);
79-
let chosen_peak = match chosen_peak {
80-
Some(peak) => {
81-
Some(correct_peak(peak, input, correction))
82-
},
83-
None => {
84-
None
85-
}
86-
};
87-
88-
let pitch = match chosen_peak {
89-
Some(peak) => {
97+
choose_peak(peaks, clarity_threshold)
98+
.map(|peak| correct_peak(peak, input, correction))
99+
.map(|peak| {
90100
let frequency = T::from_usize(sample_rate).unwrap() / peak.0;
91101
let clarity = peak.1 / input[0];
92-
Some(Pitch { frequency, clarity })
93-
},
94-
None => {
95-
None
96-
}
97-
};
98-
pitch
102+
Pitch { frequency, clarity }
103+
})
99104
}
100105

101106
pub fn get_power_level<T>(signal: &[T]) -> T
102-
where T : Float
107+
where
108+
T: Float + std::iter::Sum,
103109
{
104-
let mut power = T::zero();
105-
for i in 0..signal.len() {
106-
power = power + signal[i] * signal[i];
107-
}
108-
power
110+
signal.iter().map(|s| *s * *s).sum::<T>()
109111
}
110112

111113
fn m_of_tau<T>(signal: &[T], signal_square_sum: Option<T>, result: &mut [T])
112-
where T : Float
114+
where
115+
T: Float + std::iter::Sum,
113116
{
114117
assert!(result.len() >= signal.len());
115118

116-
let signal_square_sum = match signal_square_sum {
117-
Some(val) => val,
118-
None => {
119-
let mut val = T::zero();
120-
for i in 0..signal.len() {
121-
val = val + signal[i] * signal[i];
122-
}
123-
val
124-
}
125-
};
119+
let signal_square_sum =
120+
signal_square_sum.unwrap_or_else(|| signal.iter().map(|s| *s * *s).sum::<T>());
126121

127122
result[0] = T::from_usize(2).unwrap() * signal_square_sum;
128-
for i in 1..signal.len() {
129-
result[i] = result[i - 1] - signal[i - 1] * signal[i - 1];
130-
}
131-
132-
// Signal has no padding, but result does
133-
for i in signal.len()..result.len() {
134-
result[i] = result[i - 1];
135-
}
123+
let last = result[1..].iter_mut().zip(signal).fold(
124+
T::from_usize(2).unwrap() * signal_square_sum,
125+
|old, (r, s)| {
126+
*r = old - *s * *s;
127+
*r
128+
},
129+
);
130+
result[signal.len()..].iter_mut().for_each(|r| *r = last);
136131
}
137132

138-
pub fn normalized_square_difference<T>(signal: &[T], scratch0: &mut [Complex<T>], scratch1: &mut [Complex<T>], scratch2: &mut [T], result: &mut [T])
139-
where T : Float
133+
pub fn normalized_square_difference<T>(
134+
signal: &[T],
135+
scratch0: &mut [Complex<T>],
136+
scratch1: &mut [Complex<T>],
137+
scratch2: &mut [T],
138+
result: &mut [T],
139+
) where
140+
T: Float + std::iter::Sum,
140141
{
141142
autocorrelation(signal, scratch0, scratch1, result);
142143
m_of_tau(signal, Some(result[0]), scratch2);
143-
for i in 0..result.len() {
144-
result[i] = T::from_usize(2).unwrap() * result[i] / scratch2[i];
145-
}
144+
result
145+
.iter_mut()
146+
.zip(scratch2)
147+
.for_each(|(r, s)| *r = T::from_usize(2).unwrap() * *r / *s)
146148
}

src/detector/mcleod.rs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,40 @@
1-
use crate::float::Float;
2-
use crate::detector::PitchDetector;
3-
use crate::detector::internals::DetectorInternals;
4-
use crate::detector::internals::Pitch;
5-
use crate::detector::internals::normalized_square_difference;
61
use crate::detector::internals::get_power_level;
2+
use crate::detector::internals::normalized_square_difference;
73
use crate::detector::internals::pitch_from_peaks;
4+
use crate::detector::internals::DetectorInternals;
5+
use crate::detector::internals::Pitch;
6+
use crate::detector::PitchDetector;
7+
use crate::float::Float;
88
use crate::utils::peak::PeakCorrection;
99

1010
pub struct McLeodDetector<T>
11-
where T : Float
11+
where
12+
T: Float + std::iter::Sum,
1213
{
13-
internals: DetectorInternals<T>
14+
internals: DetectorInternals<T>,
1415
}
1516

1617
impl<T> McLeodDetector<T>
17-
where T: Float
18+
where
19+
T: Float + std::iter::Sum,
1820
{
1921
pub fn new(size: usize, padding: usize) -> Self {
2022
let internals = DetectorInternals::new(2, 2, size, padding);
21-
McLeodDetector {
22-
internals
23-
}
23+
McLeodDetector { internals }
2424
}
2525
}
2626

2727
impl<T> PitchDetector<T> for McLeodDetector<T>
28-
where T : Float
28+
where
29+
T: Float + std::iter::Sum,
2930
{
30-
fn get_pitch(&mut self, signal: &[T], sample_rate: usize, power_threshold: T, clarity_threshold: T) -> Option<Pitch<T>> {
31+
fn get_pitch(
32+
&mut self,
33+
signal: &[T],
34+
sample_rate: usize,
35+
power_threshold: T,
36+
clarity_threshold: T,
37+
) -> Option<Pitch<T>> {
3138
assert_eq!(signal.len(), self.internals.size);
3239

3340
if get_power_level(signal) < power_threshold {
@@ -36,11 +43,17 @@ impl<T> PitchDetector<T> for McLeodDetector<T>
3643

3744
let (signal_complex, rest) = self.internals.complex_buffers.split_first_mut().unwrap();
3845
let (scratch0, _) = rest.split_first_mut().unwrap();
46+
3947
let (scratch1, rest) = self.internals.real_buffers.split_first_mut().unwrap();
4048
let (nsdf, _) = rest.split_first_mut().unwrap();
4149

4250
normalized_square_difference(signal, signal_complex, scratch0, scratch1, nsdf);
4351

44-
pitch_from_peaks(nsdf, sample_rate, clarity_threshold, PeakCorrection::Quadratic)
52+
pitch_from_peaks(
53+
nsdf,
54+
sample_rate,
55+
clarity_threshold,
56+
PeakCorrection::Quadratic,
57+
)
4558
}
4659
}

0 commit comments

Comments
 (0)