我正在使用 0.10.0 版的 cratemidir
在我的 Linux 机器上接收和发送 MIDI 信号。根据其存储库中的示例代码,我创建了一个小示例,其中我只需打开一个输入和一个输出连接。它基本上可以正常工作。然而,在图形配线架应用程序(例如Patchance或qjackctl)中,每个端口都出现在自己的框中。
我尝试了一些其他音乐应用程序。有些由多个框表示,有些由一个带有输入和输出的框表示。SetBFree是后者的一个例子(见下文)。我的应用程序应该接收 MIDI 输入信号,修改它们并将它们发送到其他应用程序。因此,我希望将端口分组到同一个框中,将其输入和输出端口分组在一起。
有可能吗?我如何控制配线架应用程序如何识别我的应用程序?
我已经尝试在MidiInput::new
和中使用相同的名称MidiOutput::new
,但效果是一样的——只是系统在其名称后附加了一个随机整数。
我将非常感激任何提示,包括示例 C/C++ 代码或其他 MIDI 库,或文档。唯一的条件是它应该在 Linux 上运行。
我的代码(有点快速和肮脏,改编自midir):
use std::error::Error;
use std::io::{stdin, stdout, Write};
use midir::{Ignore, MidiInput, MidiIO, MidiOutput};
fn main() {
match run() {
Ok(_) => (),
Err(err) => println!("Error: {}", err),
}
}
fn get_port<M: MidiIO>(midi_io: &M) -> Result<M::Port, Box<dyn Error>> {
// Get an input port (read from console if multiple are available)
let in_ports = midi_io.ports();
let in_port = match in_ports.len() {
0 => return Err("no input port found".into()),
1 => {
println!(
"Choosing the only available input port: {}",
midi_io.port_name(&in_ports[0]).unwrap()
);
&in_ports[0]
}
_ => {
println!("\nAvailable input ports:");
for (i, p) in in_ports.iter().enumerate() {
println!("{}: {}", i, midi_io.port_name(p).unwrap());
}
print!("Please select input port: ");
stdout().flush()?;
let mut input = String::new();
stdin().read_line(&mut input)?;
in_ports
.get(input.trim().parse::<usize>()?)
.ok_or("invalid input port selected")?
}
};
Ok(in_port.clone())
}
fn run() -> Result<(), Box<dyn Error>> {
let mut input = String::new();
let mut midi_in = MidiInput::new("midir reading input")?;
let mut midi_out = MidiOutput::new("midir reading output")?;
midi_in.ignore(Ignore::None);
let in_port = get_port(&midi_in).unwrap();
let out_port = get_port(&midi_out).unwrap();
println!("\nOpening input connection");
let in_port_name = midi_in.port_name(&in_port)?;
// _conn_in needs to be a named parameter, because it needs to be kept alive until the end of the scope
let _conn_in = midi_in.connect(
&in_port,
"midir-read-input",
move |stamp, message, _| {
println!("{}: {:?} (len = {})", stamp, message, message.len());
},
(),
)?;
println!("\nOpening output connection");
let _conn_out = midi_out.connect(
&out_port,
"midir-write-output",
);
println!(
"Connection open, reading input from '{}' (press enter to exit) ...",
in_port_name
);
input.clear();
stdin().read_line(&mut input)?; // wait for next enter key press
println!("Closing connection");
Ok(())
}
似乎不可能做到这一点,
midir
因为它会为每个端口创建一个新的 JACK 连接,这只是糟糕的 api 设计。midir
在它的私有Client
结构上确实有仅具有此功能的方法,所以我不知道他们是怎么做的。箱子
jack
里有一个midi 示例,可以按照您的需要工作。还有箱子pipewire
。使用一些粗略的变换和复制,您可以证明问题在于多个 JACK 连接
midir
(请勿实际使用此代码)。