music-timer

Crates.iomusic-timer
lib.rsmusic-timer
version0.1.6
sourcesrc
created_at2019-12-09 01:17:01.500678
updated_at2020-03-15 20:00:47.882228
descriptionmusic-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.
homepage
repositoryhttps://github.com/unsignedbytebite/music-timer
max_upload_size
id187415
size43,592
cj (unsignedbytebite)

documentation

https://docs.rs/music-timer

README

Music-Timer

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.

Its aims are to allow for an easy interface to trigger events in music time. This crate does not feature any threading.

Performance engine

To create a performance engine with a time signature and bpm call music_timer::create_performance_engine.

let mut performer = music_timer::create_performance_engine(3, 4, 155.0);

Create a struct with the trait MusicTimerState and pass it into the engine's pulse. The callbacks will be triggered in music time.

struct PerformanceState;
impl MusicTimerState for PerformanceState {
    fn on_beat_interval(&mut self, current_time: &MusicTime) {
      // Do something on the beat interval
    }
    fn on_beat(&mut self, current_time: &MusicTime) {
        // Do something on the beat
    }
    fn on_bar(&mut self, current_time: &MusicTime) {
        // Do something on the bar
    }
}

let mut performer_state = PerformanceState{};
let mut performer = music_timer::create_performance_engine(3, 4, 155.0);
performer.pulse(&mut performer_state);

Future work

  • Support un orthodox time signatures e.g 3/5.
  • Explore the need for higher resolution beat intervals.

Example

use music_timer::{
    music_time::MusicTime,
    music_timer_engine::MusicTimerState,
};

struct PerformanceState {
    is_playing: bool,
    performance_end: MusicTime,
    events: Vec<MusicTime>,
    event_head: usize,
}

impl MusicTimerState for PerformanceState {
    fn on_beat_interval(&mut self, current_time: &MusicTime) {
        let event_triggered =
            self.event_head < self.events.len() && *current_time == self.events[self.event_head];

        // Advance the event head
        if event_triggered {
            self.event_head += 1;
        }

        // Print out esoteric data
        println!(
            "{:02}.{}.{} = {}",
            current_time.get_bar(),
            current_time.get_beat(),
            current_time.get_beat_interval(),
            event_triggered
        );

        // Check to end the performance
        self.is_playing = *current_time < self.performance_end;
    }
    fn on_beat(&mut self, _current_time: &MusicTime) {
        // Do something on the beat
    }
    fn on_bar(&mut self, _current_time: &MusicTime) {
        // Do something on the bar
    }
}

fn main() {
    use std::thread;

    // Create the performer_state with bunch of events
    let mut performer_state = PerformanceState {
        is_playing: true,
        performance_end: MusicTime::new(4, 3, 8),
        events: vec![
            MusicTime::new(1, 1, 1),
            MusicTime::new(2, 2, 5),
            MusicTime::new(4, 3, 8),
        ],
        event_head: 0,
    };

    // Run our main loop
    let mut performer = music_timer::create_performance_engine(3, 4, 155.0);

    // We can set the delay to be half the trigger target. This will give
    // us a reasonable cycle speed with enough buffer to keep an accurate time.
    // This of course is not needed if the application is managing thread sleeping.
    // The shorter the sleep duration of the thread, the more accurate the
    // time triggering will be. In most cases setting the sleep to 60fps is recommended for
    // < 180bpm @ 4/4.
    let sleep_duration = performer.get_beat_interval_duration() / 2;
    println!("SLEEP_DURATION: {:?}", sleep_duration);

    while performer_state.is_playing {
        // Pass in our performance state to trigger our on event callback functions
        performer.pulse(&mut performer_state);
        thread::sleep(sleep_duration);
    }
}
Commit count: 17

cargo fmt