scritcher/src/plugin.zig

131 lines
3.6 KiB
Zig

const std = @import("std");
const lv2 = @import("lv2_helpers.zig");
const c = lv2.c;
const ImageError = @import("image.zig").ImageError;
/// Control port
pub const Param = struct {
/// Port symbol
sym: []const u8,
/// Control value
value: f32,
};
/// List of parameters to be set to control ports.
pub const ParamList = std.ArrayList(Param);
/// Represents an absolute position in the image.
pub const SeekPos = struct {
start: usize,
end: usize,
pub fn contains(self: SeekPos, idx: usize) bool {
return (self.start <= idx) and (idx <= self.end);
}
};
/// Represents a relative position in the image
pub const Position = struct {
split: usize,
index: usize,
pub fn seekPos(self: Position, total_size: usize) SeekPos {
var tot = total_size / self.split;
return SeekPos{
.start = self.index * tot,
.end = (self.index + 1) * tot,
};
}
};
/// Represents the starting context for a single plugin run.
pub const Context = struct {
allocator: *std.mem.Allocator,
world: *c.LilvWorld,
plugin: *const c.LilvPlugin,
// 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);
}
};
/// Represents the specific run context of plugin instantation.
pub const RunContext = struct {
in_buf: []f32,
out_buf: []f32,
instance: *c.LilvInstance,
pub fn init(
allocator: *std.mem.Allocator,
plugin: *const c.LilvPlugin,
) !RunContext {
var instance = c.lilv_plugin_instantiate(plugin, f64(44100), null);
if (instance == null) {
return ImageError.InstantiateFail;
}
return RunContext{
.in_buf = try allocator.alloc(f32, 1),
.out_buf = try allocator.alloc(f32, 2),
.instance = instance.?,
};
}
pub fn deinit(self: *RunContext) void {
c.lilv_instance_free(self.instance);
}
pub fn connectPorts(self: *RunContext, ports: []*lv2.Port) void {
var i: usize = 0;
var o: usize = 0;
for (ports) |port, p_idx| {
var p = @intCast(u32, p_idx);
switch (port.ptype) {
.Control => lv2.lilv_instance_connect_port(self.instance, p, &port.value),
.Audio => blk: {
if (port.is_input) {
lv2.lilv_instance_connect_port(self.instance, p, &self.in_buf[i]);
i += 1;
} else {
lv2.lilv_instance_connect_port(self.instance, p, &self.out_buf[o]);
o += 1;
}
},
else => lv2.lilv_instance_connect_port(self.instance, p, null),
}
}
}
};
pub fn makeContext(allocator: *std.mem.Allocator, plugin_uri: []const u8) !Context {
const cstr_plugin_uri = try std.cstr.addNullByte(allocator, plugin_uri);
var world = c.lilv_world_new().?;
c.lilv_world_load_all(world);
var uri: *c.LilvNode = c.lilv_new_uri(world, cstr_plugin_uri.ptr) orelse blk: {
std.debug.warn("Invalid plugin URI <{}>\n", plugin_uri);
return ImageError.InvalidPlugin;
};
const plugins: *const c.LilvPlugins = c.lilv_world_get_all_plugins(world);
var plugin: *const c.LilvPlugin = c.lilv_plugins_get_by_uri(plugins, uri) orelse blk: {
std.debug.warn("Plugin <{}> not found\n", plugin_uri);
return ImageError.UnknownPlugin;
};
c.lilv_node_free(uri);
return Context{ .allocator = allocator, .world = world, .plugin = plugin };
}