Repository navigation
Expand file tree
/
Copy pathshow_midi.rs
More file actions
111 lines (100 loc) · 3.29 KB
/
Copy pathshow_midi.rs
File metadata and controls
111 lines (100 loc) · 3.29 KB
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
//! Creates a jack midi input and output ports. The application prints
//! out all values sent to it through the input port. It also sends a
//! Note On and Off event, once every cycle, on the output port.
use std::convert::From;
use std::io;
use std::sync::mpsc::sync_channel;
const MAX_MIDI: usize = 3;
//a fixed size container to copy data out of real-time thread
#[derive(Copy, Clone)]
struct MidiCopy {
len: usize,
data: [u8; MAX_MIDI],
time: jack::Frames,
}
impl From<jack::RawMidi<'_>> for MidiCopy {
fn from(midi: jack::RawMidi<'_>) -> Self {
let len = std::cmp::min(MAX_MIDI, midi.bytes.len());
let mut data = [0; MAX_MIDI];
data[..len].copy_from_slice(&midi.bytes[..len]);
MidiCopy {
len,
data,
time: midi.time,
}
}
}
impl std::fmt::Debug for MidiCopy {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Midi {{ time: {}, len: {}, data: {:?} }}",
self.time,
self.len,
&self.data[..self.len]
)
}
}
fn main() {
// Open the client.
let (client, _status) =
jack::Client::new("rust_jack_show_midi", jack::ClientOptions::default()).unwrap();
// Create a sync channel to send back copies of midi messages we get.
let (sender, receiver) = sync_channel(64);
// Define process logic.
let mut maker = client
.register_port("rust_midi_maker", jack::MidiOut::default())
.unwrap();
let shower = client
.register_port("rust_midi_shower", jack::MidiIn::default())
.unwrap();
let cback = move |_: &jack::Client, ps: &jack::ProcessScope| -> jack::Control {
let show_p = shower.iter(ps);
for e in show_p {
let c: MidiCopy = e.into();
// Prefer try send to not block the audio thread. Blocking the audio thread may crash
// the program.
let _ = sender.try_send(c);
}
let mut put_p = maker.writer(ps);
put_p
.write(&jack::RawMidi {
time: 0,
bytes: &[
0b10010000, /* Note On, channel 1 */
0b01000000, /* Key number */
0b01111111, /* Velocity */
],
})
.unwrap();
put_p
.write(&jack::RawMidi {
time: ps.n_frames() / 2,
bytes: &[
0b10000000, /* Note Off, channel 1 */
0b01000000, /* Key number */
0b01111111, /* Velocity */
],
})
.unwrap();
jack::Control::Continue
};
// Activate
let active_client = client
.activate_async((), jack::contrib::ClosureProcessHandler::new(cback))
.unwrap();
// Spawn a non-real-time thread that prints out the midi messages we get.
std::thread::spawn(move || {
while let Ok(m) = receiver.recv() {
println!("{m:?}");
}
});
// Wait
println!("Press any key to quit");
let mut user_input = String::new();
io::stdin().read_line(&mut user_input).ok();
// Optional deactivation.
if let Err(err) = active_client.deactivate() {
eprintln!("JACK exited with error: {err}");
};
}