From fba482b5545a6c02bf32d9dc4f261f6fc5556064 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Sat, 26 Nov 2016 09:42:25 +0200 Subject: Updated name of crate everywhere --- src/audio.rs | 6 ++-- src/main.rs | 4 +-- src/transforms.rs | 86 +++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 71 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/audio.rs b/src/audio.rs index e418e94..bcee400 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -24,7 +24,8 @@ pub fn get_device_list(pa: &pa::PortAudio) -> Result, pa::Err Ok(list) } -//#[test] +#[test] +#[ignore] fn get_device_list_returns_devices() { let pa = init().expect("Could not init portaudio"); let devices = get_device_list(&pa).expect("Getting devices had an error"); @@ -61,7 +62,8 @@ pub fn start_listening(pa: &pa::PortAudio, device_index: u32, Ok(stream) } -//#[test] +#[test] +#[ignore] fn start_listening_returns_successfully() { let pa = init().expect("Could not init portaudio"); let devices = get_device_list(&pa).expect("Getting devices had an error"); diff --git a/src/main.rs b/src/main.rs index 0eea7f3..91befca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ -extern crate musician_training; +extern crate rusty_microphone; -use musician_training::*; +use rusty_microphone::*; fn main() { let gui_result = gui::start_gui(); diff --git a/src/transforms.rs b/src/transforms.rs index 371379d..4d0e224 100644 --- a/src/transforms.rs +++ b/src/transforms.rs @@ -7,10 +7,18 @@ pub struct FrequencyBucket { pub intensity: f64 } +impl FrequencyBucket { + pub fn ave_freq(&self) -> f64 { + (self.min_freq + self.max_freq) / 2.0 + } +} + pub fn fft(input: Vec, sample_rate: f64) -> Vec { let frames = input.len(); + let mean_input = input.iter().sum::()/input.len() as f64; + + let mut intensities = input.iter().map(|x|x-mean_input).collect::>(); let plan = dft::Plan::new(dft::Operation::Forward, frames); - let mut intensities = input.clone(); dft::transform(&mut intensities, &plan); let frequency_resolution = sample_rate / 2.0 / frames as f64; @@ -28,35 +36,71 @@ pub fn fft(input: Vec, sample_rate: f64) -> Vec { pub fn find_fundamental_frequency(frequency_domain: &Vec) -> Option { //TODO look at all significant frequencies, find fundamental //TODO return None is none of them are significant + let positive_buckets = frequency_domain.iter().filter(|x| x.intensity > 0.0).cloned().collect::>(); + let average_intensity = positive_buckets.iter().map(|x| x.intensity).sum::() / frequency_domain.len() as f64; + let significant_buckets = positive_buckets.iter().filter(|x| x.intensity > average_intensity).cloned().collect::>(); + for bucket in significant_buckets.iter() { + //println!("{:?}", bucket); + } - let max_frequency = frequency_domain.iter() + let max_bucket = significant_buckets.iter() .fold(None as Option<::transforms::FrequencyBucket>, |max, next| if max.is_none() || max.clone().unwrap().intensity < next.intensity { Some(next.clone()) } else { max } - ).unwrap().max_freq; - - Some(max_frequency) + ).unwrap(); + + Some(max_bucket.ave_freq()) } -#[test] -fn fft_on_sine_wave() { - use std::f64::consts; +#[cfg(test)] +mod tests { + use super::*; + use std::f64::consts::PI; - let sample_rate = 44100.0 as f64; - let amplitude = 1.0 as f64; - let frames = 16384; - let frequency = 10000.0 as f64; //10KHz - let frequency_resolution = sample_rate / 2.0 / frames as f64; + const SAMPLE_RATE: f64 = 44100.0; + const FRAMES: usize = 512; + + fn frequency_resolution() -> f64 { + SAMPLE_RATE / 2.0 / FRAMES as f64 + } + + fn sin_arg(f: f64, t: f64, phase: f64) -> f64 { + 2.0 as f64 * PI * f * t + phase + } + + fn sample_sinusoud(amplitude: f64, frequency: f64, phase: f64) -> Vec { + (0..FRAMES) + .map(|x| { + let t = x as f64 / SAMPLE_RATE; + sin_arg(frequency, t, phase).sin() * amplitude + }).collect() + } - let samples = (0..frames) - .map(|x| { - let t = x as f64 / sample_rate; - (2.0 as f64 * consts::PI * frequency * t).sin() * amplitude - }).collect(); + #[test] + fn fft_on_sine_wave() { + let frequency = 10000.0 as f64; //10KHz + + let samples = sample_sinusoud(1.0, frequency, 0.0); + let frequency_domain = fft(samples, SAMPLE_RATE); + let fundamental = find_fundamental_frequency(&frequency_domain).unwrap(); + + assert!((fundamental-frequency).abs() < frequency_resolution(), "expected={}, actual={}", frequency, fundamental); + } - let result = fft(samples, sample_rate); - let fundamental = find_fundamental_frequency(&result); + #[test] + fn fft_on_two_sine_waves() { + let samples1k = sample_sinusoud(0.5, 1000.0, 0.0); + let samples2k = sample_sinusoud(1.0, 10000.0, 0.0); + let expected_fundamental = 1000.0; + + let samples = samples1k.iter().zip(samples2k.iter()) + .map(|(a, b)| a+b) + .collect(); + let frequency_domain = fft(samples, SAMPLE_RATE); + + let fundamental = find_fundamental_frequency(&frequency_domain).unwrap(); - assert!((fundamental-frequency).abs() < frequency_resolution, "expected={}, actual={}", frequency, fundamental); + assert!((fundamental-expected_fundamental).abs() < frequency_resolution(), "expected_fundamental={}, actual={}", expected_fundamental, fundamental); + } } pub fn hz_to_pitch(hz: f64) -> String { -- cgit v1.2.3