scritcher/src/plugin.zig

161 lines
4.5 KiB
Zig
Raw Normal View History

2019-07-09 01:40:52 +00:00
const std = @import("std");
2019-07-09 18:15:02 +00:00
const lv2 = @import("lv2_helpers.zig");
const c = lv2.c;
2019-07-09 03:04:01 +00:00
2022-04-27 23:01:09 +00:00
const log = std.log.scoped(.scritcher_plugin);
2019-07-09 03:04:01 +00:00
const ImageError = @import("image.zig").ImageError;
2019-07-09 01:40:52 +00:00
/// Control port
pub const Param = struct {
/// Port symbol
sym: []const u8,
/// Control value
value: f32,
};
2019-07-09 03:04:01 +00:00
/// List of parameters to be set to control ports.
2019-07-09 01:40:52 +00:00
pub const ParamList = std.ArrayList(Param);
pub const ParamMap = std.StringHashMap(f32);
2019-07-09 01:40:52 +00:00
2019-07-09 19:52:46 +00:00
/// Represents an absolute position in the image.
pub const SeekPos = struct {
start: usize,
end: usize,
2019-07-09 21:34:05 +00:00
pub fn contains(self: SeekPos, idx: usize) bool {
return (self.start <= idx) and (idx <= self.end);
}
2019-07-09 19:52:46 +00:00
};
2019-07-09 03:04:01 +00:00
/// Represents a relative position in the image
2019-07-09 01:40:52 +00:00
pub const Position = struct {
split: usize,
index: usize,
2019-07-09 19:52:46 +00:00
pub fn seekPos(self: Position, total_size: usize) SeekPos {
std.debug.assert(self.index <= self.split);
2019-07-09 19:52:46 +00:00
var tot = total_size / self.split;
return SeekPos{
.start = self.index * tot,
.end = (self.index + 1) * tot,
};
}
2019-07-09 01:40:52 +00:00
};
2019-07-09 03:04:01 +00:00
/// Represents the starting context for a single plugin run.
pub const Context = struct {
2022-04-27 23:01:12 +00:00
allocator: std.mem.Allocator,
2019-07-09 03:04:01 +00:00
world: *c.LilvWorld,
2019-07-09 18:15:02 +00:00
plugin: *const c.LilvPlugin,
2019-07-09 16:21:07 +00:00
// they should both be 1.
n_audio_in: usize = 0,
n_audio_out: usize = 0,
pub fn deinit(self: *Context) void {
c.lilv_world_free(self.world);
}
2019-07-09 03:04:01 +00:00
};
/// Specific run context for non-plugins.
pub const RunBuffers = struct {
2020-01-26 01:46:00 +00:00
// we use [2]f32 to account for stereo plugins, however
// we only use in_buf[0] and out_buf[0], and don't use the
// (supposedly) right side of neither input or output.
in: [2]f32 = [_]f32{0} ** 2,
out: [2]f32 = [_]f32{0} ** 2,
};
2019-07-09 18:15:02 +00:00
/// Represents the specific run context of plugin instantation.
pub const RunContext = struct {
buffers: RunBuffers,
2019-07-09 18:15:02 +00:00
instance: *c.LilvInstance,
pub fn init(
2022-04-27 23:01:12 +00:00
allocator: std.mem.Allocator,
2019-07-09 18:15:02 +00:00
plugin: *const c.LilvPlugin,
) !RunContext {
2022-04-27 23:01:12 +00:00
_ = allocator; // TODO batch RunBuffers?
2019-11-10 16:37:59 +00:00
var instance = c.lilv_plugin_instantiate(plugin, @as(f64, 44100), null);
errdefer c.lilv_instance_free(instance);
2019-07-09 18:15:02 +00:00
if (instance == null) {
return ImageError.InstantiateFail;
}
return RunContext{
2020-01-26 01:46:00 +00:00
.buffers = RunBuffers{},
2019-07-09 18:15:02 +00:00
.instance = instance.?,
};
}
pub fn deinit(self: *RunContext) void {
c.lilv_instance_free(self.instance);
}
pub fn connectPorts(self: *RunContext, ports: []lv2.Port) void {
2019-07-09 18:15:02 +00:00
var i: usize = 0;
var o: usize = 0;
for (ports) |_, p_idx| {
2019-07-09 18:15:02 +00:00
var p = @intCast(u32, p_idx);
var port: *lv2.Port = &ports[p_idx];
2019-07-09 18:15:02 +00:00
switch (port.ptype) {
.Control => lv2.lilv_instance_connect_port(self.instance, p, &port.value),
2020-08-18 20:49:23 +00:00
.Audio => {
2019-07-09 18:15:02 +00:00
if (port.is_input) {
2020-01-26 01:46:00 +00:00
lv2.lilv_instance_connect_port(
self.instance,
p,
&self.buffers.in[i],
);
2019-07-09 18:15:02 +00:00
i += 1;
} else {
2020-01-26 01:46:00 +00:00
lv2.lilv_instance_connect_port(
self.instance,
p,
&self.buffers.out[o],
);
2019-07-09 18:15:02 +00:00
o += 1;
}
},
2020-08-18 20:49:23 +00:00
// else => lv2.lilv_instance_connect_port(self.instance, p, null),
2019-07-09 18:15:02 +00:00
}
}
}
};
2022-04-27 23:01:12 +00:00
pub fn makeContext(allocator: std.mem.Allocator, plugin_uri: []const u8) !Context {
2019-07-09 03:04:01 +00:00
const cstr_plugin_uri = try std.cstr.addNullByte(allocator, plugin_uri);
2019-08-14 12:10:09 +00:00
defer allocator.free(cstr_plugin_uri);
var world: *c.LilvWorld = c.lilv_world_new().?;
errdefer c.lilv_world_free(world);
2019-07-09 03:04:01 +00:00
c.lilv_world_load_all(world);
2020-08-18 20:49:23 +00:00
var uri: *c.LilvNode = c.lilv_new_uri(world, cstr_plugin_uri.ptr) orelse {
2022-10-08 18:14:56 +00:00
log.debug("Invalid plugin URI <{s}>", .{plugin_uri});
2019-07-09 03:04:01 +00:00
return ImageError.InvalidPlugin;
};
defer c.lilv_node_free(uri);
2019-07-09 03:04:01 +00:00
2020-07-23 19:32:33 +00:00
const plugins: *const c.LilvPlugins = c.lilv_world_get_all_plugins(world).?;
2019-07-09 03:04:01 +00:00
2020-08-18 20:49:23 +00:00
var plugin: *const c.LilvPlugin = c.lilv_plugins_get_by_uri(plugins, uri) orelse {
2022-10-08 18:14:56 +00:00
log.debug("Plugin <{s}> not found", .{plugin_uri});
2019-07-09 03:04:01 +00:00
return ImageError.UnknownPlugin;
};
return Context{
.allocator = allocator,
.world = world,
.plugin = plugin,
};
2019-07-09 03:04:01 +00:00
}