music_timer/lib.rs
1#![allow(dead_code)]
2#![crate_name = "music_timer"]
3
4//!
5//! _Music Timer_ is a crate with music time and counting utilities featuring a callback performance engine to help with triggering events in music time. Written in Rust.
6//!
7//! # Example
8//! ```
9//! use music_timer::{
10//! music_time::MusicTime,
11//! music_timer_engine::MusicTimerState,
12//! };
13//!
14//! struct PerformanceState {
15//! is_playing: bool,
16//! performance_end: MusicTime,
17//! events: Vec<MusicTime>,
18//! event_head: usize,
19//! }
20//!
21//! impl MusicTimerState for PerformanceState {
22//! fn on_beat_interval(&mut self, current_time: &MusicTime) {
23//! let event_triggered =
24//! self.event_head < self.events.len() && *current_time == self.events[self.event_head];
25//!
26//! // Advance the event head
27//! if event_triggered {
28//! self.event_head += 1;
29//! }
30//!
31//! // Print out esoteric data
32//! println!(
33//! "{:02}.{}.{} = {}",
34//! current_time.get_bar(),
35//! current_time.get_beat(),
36//! current_time.get_beat_interval(),
37//! event_triggered
38//! );
39//!
40//! // Check to end the performance
41//! self.is_playing = *current_time < self.performance_end;
42//! }
43//! fn on_beat(&mut self, _current_time: &MusicTime) {
44//! // Do something on the beat
45//! }
46//! fn on_bar(&mut self, _current_time: &MusicTime) {
47//! // Do something on the bar
48//! }
49//! }
50//!
51//! fn main() {
52//! use std::thread;
53//!
54//! // Create the performer_state with bunch of events
55//! let mut performer_state = PerformanceState {
56//! is_playing: true,
57//! performance_end: MusicTime::new(4, 3, 8),
58//! events: vec![
59//! MusicTime::new(1, 1, 1),
60//! MusicTime::new(2, 2, 5),
61//! MusicTime::new(4, 3, 8),
62//! ],
63//! event_head: 0,
64//! };
65//!
66//! // Run our main loop
67//! let mut performer = music_timer::create_performance_engine(3, 4, 155.0);
68//!
69//! // We can set the delay to be half the trigger target. This will give
70//! // us a reasonable cycle speed with enough buffer to keep an accurate time.
71//! // This of course is not needed if the application is managing thread sleeping.
72//! // The shorter the sleep duration of the thread, the more accurate the
73//! // time triggering will be. In most cases setting the sleep to 60fps is recommended for
74//! // < 180bpm @ 4/4.
75//! let sleep_duration = performer.get_beat_interval_duration() / 2;
76//! println!("SLEEP_DURATION: {:?}", sleep_duration);
77//!
78//! while performer_state.is_playing {
79//! // Pass in our performance state to trigger our on event callback functions
80//! performer.pulse(&mut performer_state);
81//! thread::sleep(sleep_duration);
82//! }
83//! }
84//! ```
85
86pub mod music_time;
87pub mod music_time_counter;
88pub mod music_timer_engine;
89pub mod time_signature;
90
91/// Creates a new music timer performance engine.
92///
93/// # Arguments
94///
95/// * `numerator` - The upper part of a time signature. Must be none 0.
96/// * `denominator` - The lower part of a time signature. Only 2, 4, 8, 16, 32 are supported.
97/// * `bpm` - The beats per minute.
98///
99/// # Example
100///
101/// ```
102/// let mut performer = music_timer::create_performance_engine(3, 4, 155.0);
103/// ```
104pub fn create_performance_engine(
105 numerator: u8,
106 denominator: u8,
107 bpm: f32,
108) -> music_timer_engine::MusicTimerEngine {
109 music_timer_engine::MusicTimerEngine::new(
110 time_signature::TimeSignature::new(numerator, denominator),
111 bpm,
112 )
113}