Skip to content

Commit

Permalink
Merge branch 'dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
phip1611 committed Sep 12, 2021
2 parents 1d4938f + 6e6c043 commit ad00de5
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 104 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ before_install:
# alsa header files, required for rust build
- sudo apt update && sudo apt install libasound2-dev
rust:
- 1.52.1
- stable
- nightly
cache: cargo
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description = """
Audio beat detection library, that supports different audio input devices as source.
You can pass a callback for each found beat to the library.
"""
version = "0.1.0"
version = "0.1.2"
authors = ["Philipp Schuster <[email protected]>"]
edition = "2018"
license = "MIT"
Expand All @@ -17,8 +17,9 @@ documentation = "https://docs.rs/beat-detector"

[dependencies]
lowpass-filter = "0.2.4"
spectrum-analyzer = "0.5.2"
spectrum-analyzer = "1.1.0"
cpal = "0.13.3"
ringbuffer = "0.7.1"

[dev-dependencies]
minimp3 = "0.5.1"
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,6 @@ fn select_strategy() -> StrategyKind {
StrategyKind::Spectrum
}
```

## MSRV (Minimal Supported Rust Version)
1.52.1 stable
49 changes: 31 additions & 18 deletions examples/audio_input_beat_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
use beat_detector::StrategyKind;
use cpal::Device;
use std::collections::{BTreeMap};
use std::collections::BTreeMap;
use std::io::stdin;
use beat_detector::StrategyKind;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

Expand All @@ -34,21 +34,24 @@ fn main() {
ctrlc::set_handler(move || {
eprintln!("Stopping recording");
recording_cpy.store(false, Ordering::SeqCst);
}).expect("Ctrl-C handler doesn't work");
})
.expect("Ctrl-C handler doesn't work");

let devs = beat_detector::record::audio_input_device_list();
if devs.is_empty() { panic!("No audio input devices found!") }
let dev = if devs.len() > 1 { select_input_device(devs) } else { devs.into_iter().next().unwrap().1 };
if devs.is_empty() {
panic!("No audio input devices found!")
}
let dev = if devs.len() > 1 {
select_input_device(devs)
} else {
devs.into_iter().next().unwrap().1
};
let strategy = select_strategy();
let on_beat = |info| {
println!("Found beat at {:?}ms", info);
};
let handle = beat_detector::record::start_listening(
on_beat,
Some(dev),
strategy,
recording,
).unwrap();
let handle =
beat_detector::record::start_listening(on_beat, Some(dev), strategy, recording).unwrap();

handle.join().unwrap();
}
Expand All @@ -61,8 +64,12 @@ fn select_input_device(devs: BTreeMap<String, Device>) -> Device {
println!("Select audio device: input device number and enter:");
let mut input = String::new();
while stdin().read_line(&mut input).unwrap() == 0 {}
let input = input.trim().parse::<u8>().expect("Input must be a valid number!");
devs.into_iter().enumerate()
let input = input
.trim()
.parse::<u8>()
.expect("Input must be a valid number!");
devs.into_iter()
.enumerate()
.filter(|(i, _)| *i == input as usize)
.map(|(_i, (_name, dev))| dev)
.take(1)
Expand All @@ -72,16 +79,22 @@ fn select_input_device(devs: BTreeMap<String, Device>) -> Device {

fn select_strategy() -> StrategyKind {
println!("Available beat detection strategies:");
StrategyKind::values().into_iter().enumerate().for_each(|(i, s)| {
println!(" [{}] {} - {}", i, s.name(), s.description());
});
StrategyKind::values()
.into_iter()
.enumerate()
.for_each(|(i, s)| {
println!(" [{}] {} - {}", i, s.name(), s.description());
});
println!("Select strategy: input id and enter:");
let mut input = String::new();
while stdin().read_line(&mut input).unwrap() == 0 {}
let input = input.trim().parse::<u8>().expect("Input must be a valid number!");
let input = input
.trim()
.parse::<u8>()
.expect("Input must be a valid number!");
match input {
0 => StrategyKind::LPF,
1 => StrategyKind::Spectrum,
_ => panic!("Invalid strategy!"),
}
}
}
21 changes: 11 additions & 10 deletions examples/minimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ SOFTWARE.
*/
//! Minimum example on how to use this library. Sets up the "callback loop".

use cpal::Device;
use beat_detector::StrategyKind;
use cpal::Device;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

Expand All @@ -36,30 +36,31 @@ fn main() {
ctrlc::set_handler(move || {
eprintln!("Stopping recording");
recording_cpy.store(false, Ordering::SeqCst);
}).unwrap();
})
.unwrap();

let dev = select_input_device();
let strategy = select_strategy();
let on_beat = |info| {
println!("Found beat at {:?}ms", info);
};
// actually start listening in thread
let handle = beat_detector::record::start_listening(
on_beat,
Some(dev),
strategy,
recording,
).unwrap();
let handle =
beat_detector::record::start_listening(on_beat, Some(dev), strategy, recording).unwrap();

handle.join().unwrap();
}

fn select_input_device() -> Device {
// todo implement user selection
beat_detector::record::audio_input_device_list().into_iter().next().expect("At least one audio input device must be available.").1
beat_detector::record::audio_input_device_list()
.into_iter()
.next()
.expect("At least one audio input device must be available.")
.1
}

fn select_strategy() -> StrategyKind {
// todo implement user selection
StrategyKind::Spectrum
}
}
60 changes: 38 additions & 22 deletions examples/ws2812_spi_light_on_beat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,16 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
use beat_detector::StrategyKind;
use cpal::Device;
use std::collections::{BTreeMap};
use std::collections::BTreeMap;
use std::io::stdin;
use beat_detector::StrategyKind;
use std::ops::Add;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::time::{Instant, Duration};
use std::ops::Add;
use ws2818_rgb_led_spi_driver::adapter_spi::WS28xxSpiAdapter;
use std::time::{Duration, Instant};
use ws2818_rgb_led_spi_driver::adapter_gen::WS28xxAdapter;

use ws2818_rgb_led_spi_driver::adapter_spi::WS28xxSpiAdapter;

// LED steps per second
pub const ANIMATION_FREQUENCY: u64 = 90; // in Hz
Expand All @@ -52,23 +51,27 @@ fn main() {
ctrlc::set_handler(move || {
eprintln!("Stopping recording");
recording_cpy.store(false, Ordering::SeqCst);
}).expect("Ctrl-C handler doesn't work");
})
.expect("Ctrl-C handler doesn't work");

let devs = beat_detector::record::audio_input_device_list();
if devs.is_empty() { panic!("No audio input devices found!") }
let dev = if devs.len() > 1 { select_input_device(devs) } else { devs.into_iter().next().unwrap().1 };
if devs.is_empty() {
panic!("No audio input devices found!")
}
let dev = if devs.len() > 1 {
select_input_device(devs)
} else {
devs.into_iter().next().unwrap().1
};
let strategy = select_strategy();
let anim_t = anim.clone();
let on_beat = move |info| {
println!("Found beat at {:?}ms", info);
anim_t.lock().unwrap().add_next_light_impulse();
};
let handle = beat_detector::record::start_listening(
on_beat,
Some(dev),
strategy,
recording.clone(),
).unwrap();
let handle =
beat_detector::record::start_listening(on_beat, Some(dev), strategy, recording.clone())
.unwrap();

while recording.load(Ordering::SeqCst) {
let next_timestamp = Instant::now().add(Duration::from_millis(ANIMATION_FREQUENCY_MS));
Expand All @@ -93,8 +96,12 @@ fn select_input_device(devs: BTreeMap<String, Device>) -> Device {
println!("Select audio device: input device number and enter:");
let mut input = String::new();
while stdin().read_line(&mut input).unwrap() == 0 {}
let input = input.trim().parse::<u8>().expect("Input must be a valid number!");
devs.into_iter().enumerate()
let input = input
.trim()
.parse::<u8>()
.expect("Input must be a valid number!");
devs.into_iter()
.enumerate()
.filter(|(i, _)| *i == input as usize)
.map(|(_i, (_name, dev))| dev)
.take(1)
Expand All @@ -104,13 +111,19 @@ fn select_input_device(devs: BTreeMap<String, Device>) -> Device {

fn select_strategy() -> StrategyKind {
println!("Available beat detection strategies:");
StrategyKind::values().into_iter().enumerate().for_each(|(i, s)| {
println!(" [{}] {} - {}", i, s.name(), s.description());
});
StrategyKind::values()
.into_iter()
.enumerate()
.for_each(|(i, s)| {
println!(" [{}] {} - {}", i, s.name(), s.description());
});
println!("Select strategy: input id and enter:");
let mut input = String::new();
while stdin().read_line(&mut input).unwrap() == 0 {}
let input = input.trim().parse::<u8>().expect("Input must be a valid number!");
let input = input
.trim()
.parse::<u8>()
.expect("Input must be a valid number!");
match input {
0 => StrategyKind::LPF,
1 => StrategyKind::Spectrum,
Expand All @@ -123,7 +136,10 @@ pub fn select_num_leds() -> u16 {
println!("Input and enter how many LEDs are connected to your device (64, 150, ..):");
let mut input = String::new();
while stdin().read_line(&mut input).unwrap() == 0 {}
let input = input.trim().parse::<u16>().expect("Input must be a valid number!");
let input = input
.trim()
.parse::<u16>()
.expect("Input must be a valid number!");
input
}

Expand Down
30 changes: 24 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#![deny(
clippy::all,
clippy::cargo,
clippy::nursery,
// clippy::restriction,
// clippy::pedantic
)]
// now allow a few rules which are denied by the above statement
// --> they are ridiculous and not necessary
#![allow(
clippy::suboptimal_flops,
clippy::redundant_pub_crate,
clippy::fallible_impl_from
)]
#![deny(missing_debug_implementations)]
#![deny(rustdoc::all)]

use crate::strategies::lpf::LpfBeatDetector;
use crate::strategies::spectrum::SABeatDetector;
use crate::strategies::window_stats::WindowStats;
Expand All @@ -37,12 +55,12 @@ pub struct BeatInfo {
}
impl BeatInfo {
#[inline(always)]
pub fn new(relative_ms: u32) -> Self {
pub const fn new(relative_ms: u32) -> Self {
Self { relative_ms }
}

#[inline(always)]
pub fn relative_ms(&self) -> u32 {
pub const fn relative_ms(&self) -> u32 {
self.relative_ms
}
}
Expand Down Expand Up @@ -138,7 +156,7 @@ impl StrategyKind {
match self {
StrategyKind::LPF => Box::new(LpfBeatDetector::new(sampling_rate)),
StrategyKind::Spectrum => Box::new(SABeatDetector::new(sampling_rate)),
_ => panic!("Unknown Strategy"),
// _ => panic!("Unknown Strategy"),
}
}

Expand All @@ -147,7 +165,7 @@ impl StrategyKind {
match self {
StrategyKind::LPF => LpfBeatDetector::name(),
StrategyKind::Spectrum => SABeatDetector::name(),
_ => panic!("Unknown Strategy"),
// _ => panic!("Unknown Strategy"),
}
}

Expand All @@ -156,12 +174,12 @@ impl StrategyKind {
match self {
StrategyKind::LPF => LpfBeatDetector::description(),
StrategyKind::Spectrum => SABeatDetector::description(),
_ => panic!("Unknown Strategy"),
// _ => panic!("Unknown Strategy"),
}
}

/// Returns a vector with all strategy kinds to iterate over them.
pub fn values() -> Vec<StrategyKind> {
pub fn values() -> Vec<Self> {
vec![Self::LPF, Self::Spectrum]
}
}
Expand Down
Loading

0 comments on commit ad00de5

Please sign in to comment.