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: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ license = "MIT"
default = []
avoid_timestamping = []
jack = ["jack-sys", "libc"]
winjack = ["jack"]

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you create a new feature and didn't reuse the jack feature directly? On Windows it has no meaning so far.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it this way to avoid surprises/breaks for any downstream crates that have the jack feature enabled, but expect/handle a non-jack backend on Windows. With only jack enabled, Windows will still use the winmm backend. I'm open to just reusing jack if this isn't a concern (I think it would clean up some of the cfg guards)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be even better if midir could pick between backends at runtime. Of course, that's a lot more work.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is already tracked in #4 (but yes, a lot of work).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that a semver breaking release is already being prepared, should we go ahead just use the jack feature for windows?

winrt = [
"windows/Foundation",
"windows/Foundation_Collections",
Expand All @@ -31,7 +32,7 @@ winrt = [
[dependencies]
bitflags = "1.2"
memalloc = "0.1.0"
jack-sys = { version = "0.2", optional = true }
jack-sys = { version = "0.2.3", optional = true }

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this upgrade have any incompatible changes that may affect downstream crates?

@calvinkosmatka calvinkosmatka Jan 26, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes themselves shouldn't break anything, just formatting, replacing some libc types with primitive equivalents, add a few other jack fns, and Windows support (though it does require a 2018 edition-compatible compiler). I can loosen this to ~0.2.1

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I assume from your comment that 0.2.1 does not require a 2018 edition compiler?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.2.3 is the first version of jack-sys that builds with pipewire-jack.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for the delay, haven't had a chance to work on this lately. 0.2.1 still requires 2018 edition (as does 0.2), but it buys a few extra versions of compatibility with, for instance CPAL I see 0.2 is now in the master branch for midir 0.8-pre, so bumping this to 0.2.3 for Pipewire and Windows shouldn't be an issue?

libc = { version = "0.2.21", optional = true }

[target.'cfg(target_os = "linux")'.dependencies]
Expand Down
14 changes: 14 additions & 0 deletions azure-pipelines-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,22 @@ jobs:
stable-winrt:
rustup_toolchain: stable-${{ parameters.target }}
features: "winrt"
stable-winjack:
rustup_toolchain: stable-${{ parameters.target }}
features: "winjack"
${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master') }}:
beta-winrt:
rustup_toolchain: beta-${{ parameters.target }}
features: "winrt"
nightly-winrt:
rustup_toolchain: nightly-${{ parameters.target }}
features: "winrt"
beta-winjack:
rustup_toolchain: beta-${{ parameters.target }}
features: "winjack"
nightly-winjack:
rustup_toolchain: nightly-${{ parameters.target }}
features: "winjack"
${{ if and(not(startsWith(parameters.name, 'Windows')), not(endsWith(parameters.name, 'WASM'))) }}:
stable-jack:
rustup_toolchain: stable-${{ parameters.target }}
Expand Down Expand Up @@ -69,6 +78,11 @@ jobs:
set PATH=%PATH%;%USERPROFILE%\.cargo\bin
echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin"
displayName: Install Rust (Windows)
# Jack on Windows only
- powershell: |
choco install jack
displayName: Install Windows Jack dependency
condition: eq(variables.features, 'winjack')
# All platforms
- script: |
rustc -Vv
Expand Down
4 changes: 4 additions & 0 deletions examples/test_forward.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
extern crate midir;

#[cfg(all(windows, feature = "winjack"))]
#[link(name = "C:/Program Files/JACK2/lib/libjack64")]
extern "C" {}

use std::io::{stdin, stdout, Write};
use std::error::Error;

Expand Down
4 changes: 4 additions & 0 deletions examples/test_list_ports.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
extern crate midir;

#[cfg(all(windows, feature = "winjack"))]
#[link(name = "C:/Program Files/JACK2/lib/libjack64")]
extern "C" {}

use std::io::{stdin, stdout, Write};
use std::error::Error;

Expand Down
4 changes: 4 additions & 0 deletions examples/test_play.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
extern crate midir;

#[cfg(all(windows, feature = "winjack"))]
#[link(name = "C:/Program Files/JACK2/lib/libjack64")]
extern "C" {}

use std::thread::sleep;
use std::time::Duration;
use std::io::{stdin, stdout, Write};
Expand Down
4 changes: 4 additions & 0 deletions examples/test_read_input.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
extern crate midir;

#[cfg(all(windows, feature = "winjack"))]
#[link(name = "C:/Program Files/JACK2/lib/libjack64")]
extern "C" {}

use std::io::{stdin, stdout, Write};
use std::error::Error;

Expand Down
4 changes: 4 additions & 0 deletions examples/test_reuse.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
extern crate midir;

#[cfg(all(windows, feature = "winjack"))]
#[link(name = "C:/Program Files/JACK2/lib/libjack64")]
extern "C" {}

use std::thread::sleep;
use std::time::Duration;
use std::io::{stdin, stdout, Write};
Expand Down
10 changes: 7 additions & 3 deletions examples/test_sysex.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
extern crate midir;

#[cfg(all(windows, feature = "winjack"))]
#[link(name = "C:/Program Files/JACK2/lib/libjack64")]
extern "C" {}

fn main() {
match example::run() {
Ok(_) => (),
Err(err) => println!("Error: {}", err)
}
}

#[cfg(not(any(windows, target_arch = "wasm32")))] // virtual ports are not supported on Windows nor on Web MIDI
#[cfg(not(any(all(windows,not(feature = "winjack")), target_arch = "wasm32")))] // virtual ports are not supported on Windows nor on Web MIDI
mod example {

use std::thread::sleep;
use std::time::Duration;
use std::error::Error;

use midir::{MidiInput, MidiOutput, Ignore};
use midir::os::unix::VirtualInput;
use midir::ext::VirtualInput;

const LARGE_SYSEX_SIZE: usize = 5572; // This is the maximum that worked for me

Expand Down Expand Up @@ -73,7 +77,7 @@ pub fn run() -> Result<(), Box<dyn Error>> {
}

// needed to compile successfully
#[cfg(any(windows, target_arch = "wasm32"))] mod example {
#[cfg(any(all(windows, not(feature = "winjack")), target_arch = "wasm32"))] mod example {
use std::error::Error;
pub fn run() -> Result<(), Box<dyn Error>> { Ok(()) }
}
8 changes: 4 additions & 4 deletions src/backend/jack/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{ptr, slice, str};
use std::ffi::{CStr, CString};
use std::ops::Index;

use super::libc::{c_void, size_t};
use super::libc::{c_void, size_t, c_ulong};

use super::jack_sys::{
jack_get_time,
Expand Down Expand Up @@ -83,7 +83,7 @@ impl Client {
}

pub fn get_midi_ports(&self, flags: PortFlags) -> PortInfos {
let ports_ptr = unsafe { jack_get_ports(self.p, ptr::null_mut(), JACK_DEFAULT_MIDI_TYPE.as_ptr() as *const i8, flags.bits() as u64) };
let ports_ptr = unsafe { jack_get_ports(self.p, ptr::null_mut(), JACK_DEFAULT_MIDI_TYPE.as_ptr() as *const i8, flags.bits() as c_ulong) };
let slice = if ports_ptr.is_null() {
&[]
} else {
Expand All @@ -97,7 +97,7 @@ impl Client {

pub fn register_midi_port(&mut self, name: &str, flags: PortFlags) -> Result<MidiPort, ()> {
let c_name = CString::new(name).ok().expect("port name must not contain null bytes");
let result = unsafe { jack_port_register(self.p, c_name.as_ptr(), JACK_DEFAULT_MIDI_TYPE.as_ptr() as *const i8, flags.bits() as u64, 0) };
let result = unsafe { jack_port_register(self.p, c_name.as_ptr(), JACK_DEFAULT_MIDI_TYPE.as_ptr() as *const i8, flags.bits() as c_ulong, 0) };
if result.is_null() {
Err(())
} else {
Expand Down Expand Up @@ -247,4 +247,4 @@ impl Drop for Ringbuffer{
fn drop(&mut self) {
unsafe { jack_ringbuffer_free(self.p) }
}
}
}
12 changes: 6 additions & 6 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
// TODO: improve feature selection (make sure that there is always exactly one implementation, or enable dynamic backend selection)
// TODO: allow to disable build dependency on ALSA

#[cfg(all(target_os="windows", not(feature = "winrt")))] mod winmm;
#[cfg(all(target_os="windows", not(feature = "winrt")))] pub use self::winmm::*;
#[cfg(all(target_os="windows", not(any(feature = "winrt", feature = "winjack"))))] mod winmm;
#[cfg(all(target_os="windows", not(any(feature = "winrt", feature = "winjack"))))] pub use self::winmm::*;

#[cfg(all(target_os="windows", feature = "winrt"))] mod winrt;
#[cfg(all(target_os="windows", feature = "winrt"))] pub use self::winrt::*;
#[cfg(all(target_os="windows", feature = "winrt", not(feature = "winjack")))] mod winrt;
#[cfg(all(target_os="windows", feature = "winrt", not(feature = "winjack")))] pub use self::winrt::*;

#[cfg(all(target_os="macos", not(feature = "jack")))] mod coremidi;
#[cfg(all(target_os="macos", not(feature = "jack")))] pub use self::coremidi::*;

#[cfg(all(target_os="linux", not(feature = "jack")))] mod alsa;
#[cfg(all(target_os="linux", not(feature = "jack")))] pub use self::alsa::*;

#[cfg(all(feature = "jack", not(target_os="windows")))] mod jack;
#[cfg(all(feature = "jack", not(target_os="windows")))] pub use self::jack::*;
#[cfg(all(feature = "jack", any(unix, feature = "winjack")))] mod jack;
#[cfg(all(feature = "jack", any(unix, feature = "winjack")))] pub use self::jack::*;

#[cfg(target_arch="wasm32")] mod webmidi;
#[cfg(target_arch="wasm32")] pub use self::webmidi::*;
8 changes: 4 additions & 4 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ impl MidiIO for MidiInput {
}
}

#[cfg(unix)]
impl<T: Send> ::os::unix::VirtualInput<T> for MidiInput {
#[cfg(any(unix, feature = "winjack"))]
impl<T: Send> ::ext::VirtualInput<T> for MidiInput {
fn create_virtual<F>(
self, port_name: &str, callback: F, data: T
) -> Result<MidiInputConnection<T>, ConnectError<Self>>
Expand Down Expand Up @@ -252,8 +252,8 @@ impl MidiIO for MidiOutput {
}
}

#[cfg(unix)]
impl ::os::unix::VirtualOutput for MidiOutput {
#[cfg(any(unix, feature = "winjack"))]
impl ::ext::VirtualOutput for MidiOutput {
fn create_virtual(self, port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
match self.imp.create_virtual(port_name) {
Ok(imp) => Ok(MidiOutputConnection { imp: imp }),
Expand Down
8 changes: 3 additions & 5 deletions src/os/unix.rs → src/ext.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use ::ConnectError;
use ::{MidiInputConnection, MidiOutputConnection};

// TODO: maybe move to module `virtual` instead of `os::unix`?

/// Trait that is implemented by `MidiInput` on platforms that
/// support virtual ports (currently every platform but Windows).
/// support virtual ports (currently every platform but winmm and winrt).
pub trait VirtualInput<T: Send> where Self: Sized {
/// Creates a virtual input port. Once it has been created,
/// other applications can connect to this port and send MIDI
Expand All @@ -16,12 +14,12 @@ pub trait VirtualInput<T: Send> where Self: Sized {
}

/// Trait that is implemented by `MidiOutput` on platforms that
/// support virtual ports (currently every platform but Windows).
/// support virtual ports (currently every platform but winmm and winrt).
pub trait VirtualOutput where Self: Sized {
/// Creates a virtual output port. Once it has been created,
/// other applications can connect to this port and will
/// receive MIDI messages that are sent to this port.
fn create_virtual(
self, port_name: &str
) -> Result<MidiOutputConnection, ConnectError<Self>>;
}
}
14 changes: 12 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[cfg(all(feature = "winjack", feature = "winrt"))]
compile_error!("feature \"winjack\" and \"winrt\" cannot be enabled at the same time");

extern crate memalloc;

#[cfg(feature = "jack")]
Expand Down Expand Up @@ -57,12 +60,19 @@ impl MidiMessage {
}
}

pub mod os; // include platform-specific behaviour
#[cfg(any(unix, feature = "winjack"))] pub mod ext;

pub mod os {
#[cfg(any(unix, feature = "winjack"))]
pub mod unix {
pub use ext::{VirtualInput, VirtualOutput};
}
}

mod errors;
pub use errors::*;

mod common;
pub use common::*;

mod backend;
mod backend;
1 change: 0 additions & 1 deletion src/os/mod.rs

This file was deleted.

9 changes: 7 additions & 2 deletions tests/virtual.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
//! This file contains automated tests, but they require virtual ports and therefore can't work on Windows or Web MIDI ...
#![cfg(not(any(windows, target_arch = "wasm32")))]

#![cfg(not(any(all(windows, not(feature = "winjack")), target_arch = "wasm32")))]
extern crate midir;

#[cfg(all(windows, feature = "winjack"))]
#[link(name = "C:/Program Files/JACK2/lib/libjack64")]

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this test be run on CI? I.e., can you add "Jack on Windows" to the CI configuration (see

${{ if and(not(startsWith(parameters.name, 'Windows')), not(endsWith(parameters.name, 'WASM'))) }}:
stable-jack:
rustup_toolchain: stable-${{ parameters.target }}
features: "jack"
${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master') }}:
beta-jack:
rustup_toolchain: beta-${{ parameters.target }}
features: "jack"
nightly-jack:
rustup_toolchain: nightly-${{ parameters.target }}
features: "jack"
)?
That would require installing the Jack dependency on the CI machine ...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave this a go in the latest commit

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the following errors in the latest build of this PR on AzureDevOps (which might only be visible to me):
grafik

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't quite tell what the L75 issue is, but L34 and L73 should be fixed by 7680d23

extern "C" {}

use std::thread::sleep;
use std::time::Duration;

use midir::{MidiInput, MidiOutput, Ignore, MidiOutputPort};
use midir::os::unix::{VirtualInput, VirtualOutput};
use midir::ext::{VirtualInput, VirtualOutput};

#[test]
fn end_to_end() {
Expand Down