Skip to content

Commit bd29e18

Browse files
committed
zig api: (WIP) add a Zig API/bindings for libremidi, also add the possibility to build using the Zig Build System
This commit adds Zig bindings for libremidi and implements a subset of the build logic in Zig's build system. At this point, I'm satisfied with the API I landed on for the bindings, now awaiting feedback! Work still needed on build logic.
1 parent 69aeec9 commit bd29e18

5 files changed

Lines changed: 1017 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,6 @@ build
9393

9494
.vscode
9595

96+
# Zig related
97+
.zig-cache
98+
zig-out

bindings/zig/examples/zig_api.zig

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
const std = @import("std");
2+
const lm = @import("libremidi");
3+
4+
5+
const EnumeratedPorts = extern struct {
6+
in_ports: [256]lm.midi.in.port.Handle = .{ lm.midi.in.port.Handle{} } ** 256,
7+
out_ports: [256]lm.midi.out.port.Handle = .{ lm.midi.out.port.Handle{} } ** 256,
8+
in_port_count: usize = 0,
9+
out_port_count: usize = 0,
10+
};
11+
12+
pub fn main() !void {
13+
14+
std.debug.print("Hello from midi Zig(ified) API example!\n", .{});
15+
std.debug.print("libremidi version: {s}\n\n", .{ lm.getVersion() });
16+
17+
var e: EnumeratedPorts = .{};
18+
19+
const observer: lm.observer.Handle = try .init(&.{
20+
.track_hardware = true,
21+
.track_virtual = true,
22+
.track_any = true,
23+
.input_added = .{
24+
.context = &e,
25+
.callback = on_input_port_found,
26+
},
27+
.output_added = .{
28+
.context = &e,
29+
.callback = on_output_port_found,
30+
},
31+
}, &.{
32+
.conf_type = .observer,
33+
.api = .alsa_seq,
34+
});
35+
defer free_observer(observer, &e);
36+
37+
try enumerate_ports(observer, &e);
38+
39+
const midi_in: lm.midi.in.Handle = try .init(&.{
40+
.version = .midi1,
41+
.port = .{ .input = e.in_ports[0] },
42+
.msg_callback = .{ .on_midi1_message = .{ .callback = on_midi1_message } },
43+
}, &.{
44+
.conf_type = .input,
45+
.api = .alsa_seq,
46+
});
47+
defer midi_in.free();
48+
49+
const midi_out: lm.midi.out.Handle = try .init(&.{
50+
.version = .midi1,
51+
.virtual_port = true,
52+
.port_name = "my-app",
53+
}, &.{
54+
.conf_type = .output,
55+
.api = .alsa_seq,
56+
});
57+
defer midi_out.free();
58+
59+
60+
for (0..99) |_| std.time.sleep(1e9); // sleep 1s, 100 times
61+
}
62+
63+
fn free_observer(observer: lm.observer.Handle, e: *EnumeratedPorts) void {
64+
65+
for (e.in_ports) |port| port.free();
66+
for (e.out_ports) |port| port.free();
67+
68+
observer.free();
69+
}
70+
71+
export fn on_input_port_found(ctx: ?*anyopaque, port: lm.midi.in.port.Handle) callconv(.C) void {
72+
73+
std.debug.print("input: {s}\n", .{ port.getName() catch "" });
74+
75+
var e: *EnumeratedPorts = @ptrCast(@alignCast(ctx));
76+
e.in_ports[e.in_port_count] = port.clone() catch lm.midi.in.port.Handle{};
77+
e.in_port_count += 1;
78+
}
79+
80+
export fn on_output_port_found(ctx: ?*anyopaque, port: lm.midi.out.port.Handle) callconv(.C) void {
81+
82+
std.debug.print("output: {s}\n", .{ port.getName() catch "" });
83+
84+
var e: *EnumeratedPorts = @ptrCast(@alignCast(ctx));
85+
e.out_ports[e.out_port_count] = port.clone() catch lm.midi.out.port.Handle{};
86+
e.out_port_count += 1;
87+
}
88+
89+
fn on_midi1_message(ctx: ?*anyopaque, ts: lm.Timestamp, msg: [*]const lm.midi.v1.Symbol, len: usize) callconv(.C) void {
90+
_ = ctx;
91+
_ = ts;
92+
_ = len;
93+
94+
std.debug.print("0x{x:02} 0x{x:02} 0x{x:02}\n", .{ msg[0], msg[1], msg[2] });
95+
}
96+
97+
fn on_midi2_message(ctx: ?*anyopaque, ts: lm.Timestamp, msg: [*]const lm.midi.v2.Symbol, len: usize) callconv(.C) void {
98+
_ = ctx;
99+
_ = ts;
100+
_ = len;
101+
102+
std.debug.print("0x{x:02} 0x{x:02} 0x{x:02}\n", .{ msg[0], msg[1], msg[2] });
103+
}
104+
105+
fn enumerate_ports(observer: lm.observer.Handle, e: *EnumeratedPorts) !void {
106+
try observer.enumerateInputPorts(e, on_input_port_found);
107+
try observer.enumerateOutputPorts(e, on_output_port_found);
108+
}

0 commit comments

Comments
 (0)