1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//! # RtMidi
//!
//! A safe wrapper around [RtMidi](https://www.music.mcgill.ca/~gary/rtmidi/) that provides a
//! common API (Application Programming Interface) for realtime MIDI input/output across Linux
//! (ALSA & JACK), macOS (CoreMIDI & JACK), and Windows (Multimedia Library) operating systems.
//!
//! Where applicable, multiple API support can be compiled and a particular API specified when
//! creating an RtMidi instance.
//!
//! MIDI input and output functionality are separated into two structs, [`RtMidiIn`] and
//! [`RtMidiOut`]. Each instance supports only a single MIDI connection. RtMidi does not provide
//! timing functionality (i.e., output messages are sent immediately). Input messages are
//! timestamped with delta times in seconds (via an [`f64`] type). MIDI data is passed to the user as
//! raw bytes using a `&[u8]`.
//!
//! ## Probing Ports / Devices
//!
//! A client generally must query the available MIDI ports before deciding which to use. The
//! following example outlines how this can be done.
//!
//! ```
//! use rtmidi::{RtMidiIn, RtMidiOut, RtMidiError};
//!
//! fn main() -> Result<(), RtMidiError> {
//!     // Initialise MIDI input
//!     let input = RtMidiIn::new(Default::default())?;
//!
//!     // Get number of input ports
//!     let input_ports = input.port_count()?;
//!     println!("There are {} MIDI input sources available.", input_ports);
//!
//!     // List input ports
//!     for port in 0..input_ports {
//!         println!("\tInput Port #{}: {}", port+1, input.port_name(port)?);
//!     }
//!
//!     // Initialise MIDI output
//!     let output = RtMidiOut::new(Default::default())?;
//!
//!     // Get number of output ports
//!     let output_ports = output.port_count()?;
//!     println!("There are {} MIDI output ports available.", output_ports);
//!
//!     // List output ports
//!     for port in 0..output_ports {
//!         println!("\tOutput Port #{}: {}", port+1, output.port_name(port)?);
//!     }
//!
//!     Ok(())
//! }
//! ```
//!
//! Note that the port enumeration is system specific and will change if any devices are unplugged
//! or plugged (or a new virtual port opened or closed) by the user. Thus, the port numbers should
//! be verified immediately before opening a port. As well, if a user unplugs a device (or closes
//! a virtual port) while a port connection exists to that device/port, a MIDI system error will be
//! generated.
//!
//! ## MIDI Output
//!
//! RtMidiOut provides simple functionality to immediately send messages over a MIDI connection. No
//! timing functionality is provided.
//!
//! ```
//! use std::thread::sleep;
//! use std::time::Duration;
//! use rtmidi::{RtMidiOut, RtMidiError};
//!
//! fn main() -> Result<(), RtMidiError> {
//!     // Initialise MIDI output
//!     let output = RtMidiOut::new(Default::default())?;
//!
//!     // Check available ports
//!     let ports = output.port_count()?;
//!     if ports < 1 {
//!         eprintln!("No ports available!");
//!         return Ok(());
//!     }
//!
//!     // Open first available port
//!     output.open_port(0, "RtMidi Output")?;
//!
//!     // Program change: 192, 5
//!     output.message(&[192, 5])?;
//!
//!     // Control Change: 176, 7, 100 (volume)
//!     output.message(&[176, 7, 100])?;
//!
//!     // Note On: 144, 64, 90
//!     output.message(&[144, 64, 90])?;
//!
//!     sleep(Duration::from_millis(500));
//!
//!     // Note Off: 128, 64, 40
//!     output.message(&[128, 64, 40])?;
//!
//!     Ok(())
//! }
//! ```
//!
//! ## MIDI Input
//!
//! [`RtMidiIn`] uses an internal callback function or thread to receive incoming MIDI messages
//! from a port or device. These messages are then either queued and read by the user via calls to
//! [`RtMidiIn::message`] or immediately passed to a user-specified callback function (which must
//! be "registered" using [`RtMidiIn::set_callback`]). Note that if you have multiple instances of
//! [`RtMidiIn`], each may have its own thread.
//!
//! [`RtMidiIn`] provides [`RtMidiIn::ignore_types`] to specify that certain MIDI message types be
//! ignored. By default, system exclusive, timing, and active sensing messages are ignored.
//!
//! It is necessary to set the callback immediately after opening the port to avoid having incoming
//! messages written to the queue (which is not emptied when a callback function is set). If you
//! are worried about this happening, you can check the queue using [`RtMidiIn::message`] to verify
//! it is empty (after the callback is set).
//!
//! ```
//! use std::io::{stdin, Read};
//! use rtmidi::{RtMidiIn, RtMidiError};
//!
//! fn main() -> Result<(), RtMidiError> {
//!     // Initialise MIDI input
//!     let input = RtMidiIn::new(Default::default())?;
//!
//!     // Check available ports
//!     let ports = input.port_count()?;
//!     if ports < 1 {
//!         eprintln!("No ports available!");
//!         return Ok(());
//!     }
//!
//!     // Open first available port
//!     input.open_port(0, "RtMidi Input")?;
//!
//!     // Set our callback function.  This should be done immediately after
//!     // opening the port to avoid having incoming messages written to the
//!     // queue.
//!     input.set_callback(|timestamp, message| {
//!         for (index, byte) in message.iter().enumerate() {
//!             println!("Byte {} = 0x{:02x}, ", index, byte);
//!         }
//!     })?;
//!
//!     // Don't ignore sysex, timing, or active sensing messages.
//!     input.ignore_types(false, false, false)?;
//!
//!     println!("Reading MIDI input ...");
//!     stdin().read(&mut [0]).unwrap();
//!
//!     Ok(())
//! }
//! ```

mod api;
mod error;
mod ffi;
mod midi;
mod midi_in;
mod midi_out;

/// A MIDI input/output port identifier
pub type RtMidiPort = u32;

pub use api::RtMidiApi;
pub use error::RtMidiError;
pub use midi_in::{RtMidiIn, RtMidiInArgs};
pub use midi_out::{RtMidiOut, RtMidiOutArgs};