simple_tones 0.1.0

Easy to use crate to play music notes.
Documentation
/*
 * Copyright (c) 2021, PockelHockel.
 * This software is licensed under the GNU General Public License v3.0
 */

//! `simple_tones` is an easy to use crate which provides abilities to write down and play music compositions easily.
//! Based on [`rodio`](https://crates.io/crates/rodio).
//! # Example
//! ```rust
//! use simple_tones::{Note, NoteDuration, Player};
//!
//! type ND = NoteDuration;
//!
//! let song = vec![
//!         Note::new("C4".parse().unwrap(), ND::Quarter),
//!         Note::new("C4".parse().unwrap(), ND::Quarter),
//!         Note::new("D4".parse().unwrap(), ND::Eighth),
//!         Note::new("Eb4".parse().unwrap(), ND::Eighth),
//!         // |
//!         Note::new("D4".parse().unwrap(), ND::HalfDotted),
//!         // |
//!         Note::new("C4".parse().unwrap(), ND::Eighth),
//!         Note::new("G3".parse().unwrap(), ND::Eighth),
//!         Note::new("Ab4".parse().unwrap(), ND::Quarter),
//!         Note::new("G3".parse().unwrap(), ND::Eighth),
//!         Note::new("F3".parse().unwrap(), ND::Eighth),
//!         // |
//!         Note::new("G3".parse().unwrap(), ND::HalfDotted),
//!         // |
//!         Note::new("C4".parse().unwrap(), ND::Quarter),
//!         Note::new("C4".parse().unwrap(), ND::Quarter),
//!         Note::new("D4".parse().unwrap(), ND::Eighth),
//!         Note::new("Eb4".parse().unwrap(), ND::Eighth),
//!         // |
//!         Note::new("F4".parse().unwrap(), ND::HalfDotted),
//!         // |
//!         Note::new("G4".parse().unwrap(), ND::Eighth),
//!         Note::new("Eb4".parse().unwrap(), ND::Eighth),
//!         Note::new("D4".parse().unwrap(), ND::Eighth),
//!         Note::new("C4".parse().unwrap(), ND::Eighth),
//!         Note::new("Bb4".parse().unwrap(), ND::Quarter),
//!         // |
//!         Note::new("C4".parse().unwrap(), ND::HalfDotted),
//!         // |
//!         Note::new("F3".parse().unwrap(), ND::Half),
//!     ];
//! let np = Player::from_bpm(55);
//! np.play(song.iter());
//! ```

use std::time::Duration;

use rodio::{OutputStream, OutputStreamHandle};

pub use crate::notes::*;

mod notes;

/// The [`Player`](struct.Player.html) is a struct used to play an `Iterator` of types implementing [`Play`](trait.Note.html).
/// # Example
/// ```rust
/// use simple_tones::{Note, NoteDuration, Player};
///
/// let song = vec![
///         Note::new("C4".parse().unwrap(), NoteDuration::Quarter),
///         Note::new("C4".parse().unwrap(), NoteDuration::Quarter),
///         Note::new("D4".parse().unwrap(), NoteDuration::Eighth),
///         Note::new("Eb4".parse().unwrap(), NoteDuration::Eighth),
///         // |
///         Note::new("D4".parse().unwrap(), NoteDuration::HalfDotted),
///         // |
///         Note::new("C4".parse().unwrap(), NoteDuration::Eighth),
///         Note::new("G3".parse().unwrap(), NoteDuration::Eighth),
///         Note::new("Ab4".parse().unwrap(), NoteDuration::Quarter),
///         Note::new("G3".parse().unwrap(), NoteDuration::Eighth),
///         Note::new("F3".parse().unwrap(), NoteDuration::Eighth),
///         // |
///         Note::new("G3".parse().unwrap(), NoteDuration::HalfDotted),
///         // |
///         Note::new("C4".parse().unwrap(), NoteDuration::Quarter),
///         Note::new("C4".parse().unwrap(), NoteDuration::Quarter),
///         Note::new("D4".parse().unwrap(), NoteDuration::Eighth),
///         Note::new("Eb4".parse().unwrap(), NoteDuration::Eighth),
///         // |
///         Note::new("F4".parse().unwrap(), NoteDuration::HalfDotted),
///         // |
///         Note::new("G4".parse().unwrap(), NoteDuration::Eighth),
///         Note::new("Eb4".parse().unwrap(), NoteDuration::Eighth),
///         Note::new("D4".parse().unwrap(), NoteDuration::Eighth),
///         Note::new("C4".parse().unwrap(), NoteDuration::Eighth),
///         Note::new("Bb4".parse().unwrap(), NoteDuration::Quarter),
///         // |
///         Note::new("C4".parse().unwrap(), NoteDuration::HalfDotted),
///         // |
///         Note::new("F3".parse().unwrap(), NoteDuration::Half),
///     ];
/// let np = Player::from_bpm(55);
/// np.play(song.iter());
/// ```
pub struct Player {
    _stream: OutputStream,
    stream_handle: OutputStreamHandle,
    bar_duration: Duration,
}

impl Player {
    /// Constructs a new [`Player`](struct.Player.html) from the given bar duration, which describes how much time one whole note takes to play.
    /// # Example
    /// ```rust
    /// use simple_tones::Player;
    ///
    /// let np = Player::new(std::time::Duration::from_secs_f64(0.5));
    /// ```
    pub fn new(bar_duration: Duration) -> Self {
        let (_stream, stream_handle) = rodio::OutputStream::try_default().unwrap();
        Player {
            _stream,
            stream_handle,
            bar_duration,
        }
    }

    /// Constructs a new [`Player`](struct.Player.html) from the given **beats per minute**. One beat is considered a quarter note.
    /// Therefore, the formula to determine the duration of one bar *d* is:
    /// *d = 60 / bpm * 4*
    /// # Example
    /// ```rust
    /// use simple_tones::Player;
    ///
    /// let np = Player::from_bpm(120);
    /// ```
    pub fn from_bpm(bpm: u32) -> Self {
        Player::new(Duration::from_secs_f64(60.0 / bpm as f64) * 4)
    }

    /// Plays an `Iterator` of types implementing [`Play`](trait.Play.html) on the standard audio device.
    pub fn play<P: Play, N: Iterator<Item=P>>(&self, notes: N) {
        for note in notes {
            note.play(&self.stream_handle, self.bar_duration);
        }
    }
}