Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "rtmidi"]
path = rtmidi
url = https://github.com/thestk/rtmidi
17 changes: 13 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "rtmidi"
version = "0.2.0"
authors = ["Rob Hardwick <robhardwick@gmail.com>"]
version = "0.3.0"
authors = ["Rob Hardwick <robhardwick@gmail.com>", "Dani Biro <danipro93@gmail.com>"]
edition = "2018"
description = "Safe wrapper for RtMidi, realtime MIDI input/output"
repository = "https://github.com/robhardwick/rtmidi-rs"
Expand All @@ -10,6 +10,15 @@ keywords = ["midi", "audio", "music", "sound"]
categories = ["multimedia::audio", "api-bindings"]
license = "MIT"

[features]
default = ["coremidi", "alsa", "winmm"]
coremidi = []
alsa = []
jack_linux = []
winmm = []

[build-dependencies]
bindgen = "0.57.0"
pkg-config = "0.3.19"
cmake = "0.1"

[target.'cfg(any(target_os="linux"))'.build-dependencies]
pkg-config = "0.3"
155 changes: 113 additions & 42 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,118 @@
use std::env;
use std::path::PathBuf;
extern crate cmake;

#[cfg(any(target_os = "linux"))]
extern crate pkg_config;

fn main() {
println!("cargo:rustc-link-lib=rtmidi");
println!("cargo:rerun-if-changed=wrapper.h");
// Build the static library with CMake.
let mut config = cmake::Config::new("rtmidi");
config.define("BUILD_SHARED_LIBS", "OFF");
config.define("RTMIDI_BUILD_STATIC_LIBS", "ON");

#[cfg(target_os = "linux")]
{
println!("cargo:rustc-link-lib=dylib=stdc++");

#[cfg(feature = "alsa")]
{
config.define("RTMIDI_API_ALSA", "ON");

match pkg_config::Config::new().statik(false).probe("alsa") {
Err(pkg_config::Error::Failure { command, output }) => panic!(
"Pkg-config failed - usually this is because alsa development headers are not installed.\n\n\
For Fedora users:\n# dnf install alsa-lib-devel\n\n\
For Debian/Ubuntu users:\n# apt-get install libasound2-dev\n\n\
pkg_config details:\n{}\n", pkg_config::Error::Failure { command, output }),
Err(e) => panic!("{}", e),
Ok(alsa_library) => {
for lib in alsa_library.libs {
println!("cargo:rustc-link-lib={}", lib);
}
}
};
}
#[cfg(not(feature = "alsa"))]
config.define("RTMIDI_API_ALSA", "OFF");

#[cfg(feature = "jack_linux")]
{
config.define("RTMIDI_API_JACK", "ON");

match pkg_config::Config::new().statik(false).probe("jack") {
Err(pkg_config::Error::Failure { command, output }) => panic!(
"Pkg-config failed - usually this is because jack development headers are not installed.\n\n\
For Debian/Ubuntu users:\n# apt-get install libjack-dev\n\n\
pkg_config details:\n{}\n", pkg_config::Error::Failure { command, output }),
Err(e) => panic!("{}", e),
Ok(jack_library) => {
for lib in jack_library.libs {
println!("cargo:rustc-link-lib={}", lib);
}
}
};
}
#[cfg(not(feature = "jack_linux"))]
config.define("RTMIDI_API_JACK", "OFF");
}

#[cfg(target_os = "macos")]
{
println!("cargo:rustc-link-lib=dylib=c++");

let (version, include_args) = match pkg_config::Config::new()
.statik(false)
.atleast_version("3.0.0")
.probe("rtmidi")
#[cfg(feature = "coremidi")]
{
config.define("RTMIDI_API_CORE", "ON");

println!("cargo:rustc-link-lib=framework=CoreFoundation");
println!("cargo:rustc-link-lib=framework=CoreMidi");
}
#[cfg(not(feature = "coremidi"))]
config.define("RTMIDI_API_CORE", "OFF");

// TODO: Jack support on MacOS
// How do you install and link the Jack library files?
config.define("RTMIDI_API_JACK", "OFF");
/*
#[cfg(feature = "jack_macos")]
config.define("RTMIDI_API_JACK", "ON");
#[cfg(not(feature = "jack_macos"))]
config.define("RTMIDI_API_JACK", "OFF");
*/
}

#[cfg(target_os = "windows")]
{
Err(_) => ("4.0.0".to_string(), vec![]),
Ok(library) => (
library.version,
library
.include_paths
.iter()
.map(|include_path| {
format!(
"-I{}",
include_path.to_str().expect("include path was not UTF-8")
)
})
.collect::<Vec<_>>(),
),
};

let feature = match version.as_ref() {
"4.0.0" => "v4_0_0",
"3.0.0" => "v3_0_0",
version => panic!("Unsupported RtMidi version '{}'", version),
};
println!("cargo:rustc-cfg=rtmidi_version=\"{}\"", feature);

let bindings = bindgen::Builder::default()
.header("wrapper.h")
.clang_args(include_args)
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");

let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
println!("cargo:rustc-link-lib=winmm");
println!("cargo:rustc-link-lib=ole32");
println!("cargo:rustc-link-lib=user32");

#[cfg(feature = "winmm")]
config.define("RTMIDI_API_WINMM", "ON");
#[cfg(not(feature = "winmm"))]
config.define("RTMIDI_API_WINMM", "OFF");

// https://github.com/rust-lang/rust/issues/39016
config.profile("Release");
}

let dst = config.build();

// Sometimes the path can be called lib64
let libdir_path = ["lib", "lib64"]
.iter()
.map(|dir| dst.clone().join(dir))
.find(|path| path.exists())
.unwrap_or_else(|| {
panic!(
"Could not find rtmidi static lib path. Check `target/debug/build/rtmidi-sys-*/out` for a lib or lib64 folder."
);
});

// Tell cargo to link to the compiled library.
println!(
"cargo:rustc-link-search=native={}",
libdir_path.to_str().unwrap()
);

println!("cargo:rustc-link-lib=static=rtmidi");
}
1 change: 1 addition & 0 deletions rtmidi
Submodule rtmidi added at 24b3a3
32 changes: 16 additions & 16 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,34 @@ use std::fmt;
use crate::ffi;

/// MIDI API specifier
#[repr(u32)]
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RtMidiApi {
Unspecified = ffi::RtMidiApi_RTMIDI_API_UNSPECIFIED,
MacOSXCore = ffi::RtMidiApi_RTMIDI_API_MACOSX_CORE,
LinuxALSA = ffi::RtMidiApi_RTMIDI_API_LINUX_ALSA,
UnixJack = ffi::RtMidiApi_RTMIDI_API_UNIX_JACK,
WindowsMM = ffi::RtMidiApi_RTMIDI_API_WINDOWS_MM,
RtMidiDummy = ffi::RtMidiApi_RTMIDI_API_RTMIDI_DUMMY,
Unspecified = ffi::RTMIDI_API_UNSPECIFIED,
MacOSXCore = ffi::RTMIDI_API_MACOSX_CORE,
LinuxALSA = ffi::RTMIDI_API_LINUX_ALSA,
UnixJack = ffi::RTMIDI_API_UNIX_JACK,
WindowsMM = ffi::RTMIDI_API_WINDOWS_MM,
RtMidiDummy = ffi::RTMIDI_API_RTMIDI_DUMMY,
}

impl From<u32> for RtMidiApi {
fn from(api: u32) -> Self {
impl From<i32> for RtMidiApi {
fn from(api: i32) -> Self {
match api {
ffi::RtMidiApi_RTMIDI_API_UNSPECIFIED => RtMidiApi::Unspecified,
ffi::RtMidiApi_RTMIDI_API_MACOSX_CORE => RtMidiApi::MacOSXCore,
ffi::RtMidiApi_RTMIDI_API_LINUX_ALSA => RtMidiApi::LinuxALSA,
ffi::RtMidiApi_RTMIDI_API_UNIX_JACK => RtMidiApi::UnixJack,
ffi::RtMidiApi_RTMIDI_API_WINDOWS_MM => RtMidiApi::WindowsMM,
ffi::RtMidiApi_RTMIDI_API_RTMIDI_DUMMY => RtMidiApi::RtMidiDummy,
ffi::RTMIDI_API_UNSPECIFIED => RtMidiApi::Unspecified,
ffi::RTMIDI_API_MACOSX_CORE => RtMidiApi::MacOSXCore,
ffi::RTMIDI_API_LINUX_ALSA => RtMidiApi::LinuxALSA,
ffi::RTMIDI_API_UNIX_JACK => RtMidiApi::UnixJack,
ffi::RTMIDI_API_WINDOWS_MM => RtMidiApi::WindowsMM,
ffi::RTMIDI_API_RTMIDI_DUMMY => RtMidiApi::RtMidiDummy,
_ => panic!("Invalid API value"),
}
}
}

impl fmt::Display for RtMidiApi {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let display_name = unsafe { CStr::from_ptr(ffi::rtmidi_api_display_name(*self as u32)) };
let display_name = unsafe { CStr::from_ptr(ffi::rtmidi_api_display_name(*self as i32)) };
write!(f, "{}", display_name.to_str().map_err(|_| fmt::Error)?)
}
}
Loading