add basic machinery around plugin
This commit is contained in:
parent
eea39cdd24
commit
8e453298bc
7 changed files with 144 additions and 38 deletions
|
@ -1,4 +1,4 @@
|
|||
load :0;
|
||||
amp 10 1;
|
||||
amp 3 1 10;
|
||||
# echo 3 0 1 0.2;
|
||||
quicksave;
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
const std = @import("std");
|
||||
const c = @cImport({
|
||||
@cInclude("sndfile.h");
|
||||
|
||||
@cInclude("lilv/lilv.h");
|
||||
@cInclude("lv2/core/lv2.h");
|
||||
});
|
||||
|
||||
pub const ImageError = error{OpenFail};
|
||||
const plugins = @import("plugin.zig");
|
||||
|
||||
pub const ImageError = error{
|
||||
OpenFail,
|
||||
InvalidPlugin,
|
||||
UnknownPlugin,
|
||||
};
|
||||
|
||||
/// Low level integration function with libsndfile.
|
||||
fn sopen(
|
||||
|
@ -70,4 +79,30 @@ pub const Image = struct {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(self: *Image, file_chans: c_int, buf: []f32) bool {
|
||||
var file = file_opt.?;
|
||||
|
||||
const n_read: c.sf_count_t = c.sf_readf_float(file, buf.ptr, 1);
|
||||
const buf_chans = @intCast(c_int, buf.len);
|
||||
|
||||
var i = file_chans - 1;
|
||||
while (i < buf_chans) : (i += 1) {
|
||||
//buf[@intCast(usize, i)] = buf[i % file_chans];
|
||||
buf[@intCast(usize, i)] = buf[@intCast(usize, @mod(i, file_chans))];
|
||||
}
|
||||
|
||||
return n_read == 1;
|
||||
}
|
||||
|
||||
pub fn runPlugin(
|
||||
self: *Image,
|
||||
plugin_uri: []const u8,
|
||||
pos: plugins.Position,
|
||||
params: plugins.ParamList,
|
||||
) !void {
|
||||
const context = try plugins.makeContext(self.allocator, plugin_uri);
|
||||
std.debug.warn("world: {}\n", context.world);
|
||||
std.debug.warn("plugin: {}\n", context.plugin);
|
||||
}
|
||||
};
|
||||
|
|
21
src/lang.zig
21
src/lang.zig
|
@ -3,6 +3,7 @@ const std = @import("std");
|
|||
pub const ParseError = error{
|
||||
NoCommandGiven,
|
||||
UnknownCommand,
|
||||
ArgRequired,
|
||||
};
|
||||
|
||||
pub const CommandType = enum {
|
||||
|
@ -20,13 +21,29 @@ pub const Command = struct {
|
|||
std.debug.warn("cmd:{}\n", self.command);
|
||||
}
|
||||
|
||||
pub fn argAt(self: *const Command, idx: usize) ![]const u8 {
|
||||
const args = self.args.toSliceConst();
|
||||
|
||||
if (idx > (args.len - 1)) {
|
||||
std.debug.warn("Expected argument at index {}\n", idx);
|
||||
return ParseError.ArgRequired;
|
||||
}
|
||||
|
||||
return args[idx];
|
||||
}
|
||||
|
||||
pub fn usizeArgAt(self: *const Command, idx: usize) !usize {
|
||||
var arg = try self.argAt(idx);
|
||||
return try std.fmt.parseInt(usize, arg, 10);
|
||||
}
|
||||
|
||||
pub fn intArgAt(self: *const Command, idx: usize) !i32 {
|
||||
var arg = self.args.at(idx);
|
||||
var arg = try self.argAt(idx);
|
||||
return try std.fmt.parseInt(i32, arg, 10);
|
||||
}
|
||||
|
||||
pub fn floatArgAt(self: *const Command, idx: usize) !f32 {
|
||||
var arg = self.args.at(idx);
|
||||
var arg = try self.argAt(idx);
|
||||
return try std.fmt.parseFloat(f32, arg);
|
||||
}
|
||||
};
|
||||
|
|
39
src/lv2_helpers.zig
Normal file
39
src/lv2_helpers.zig
Normal file
|
@ -0,0 +1,39 @@
|
|||
const c = @cImport({
|
||||
@cInclude("lilv/lilv.h");
|
||||
@cInclude("lv2/core/lv2.h");
|
||||
});
|
||||
|
||||
const LV2_CORE_URI = "http://lv2plug.in/ns/lv2core";
|
||||
|
||||
pub fn Lv2Core(ns: []const u8) ![]const u8 {
|
||||
var allocator = std.heap.direct_allocator;
|
||||
|
||||
return try std.cstr.addNullByte(
|
||||
allocator,
|
||||
try std.fmt.allocPrint(allocator, "{}{}", LV2_CORE_URI, ns),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn lilv_instance_connect_port(
|
||||
instance: [*c]c.LilvInstance,
|
||||
port_index: u32,
|
||||
data_location: ?*c_void,
|
||||
) void {
|
||||
instance.?.*.lv2_descriptor.?.*.connect_port.?(instance.?.*.lv2_handle, port_index, data_location);
|
||||
}
|
||||
|
||||
pub fn lilv_instance_activate(instance: [*c]c.LilvInstance) void {
|
||||
if (instance.?.*.lv2_descriptor.?.*.activate != null) {
|
||||
instance.?.*.lv2_descriptor.?.*.activate.?(instance.?.*.lv2_handle);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lilv_instance_run(instance: [*c]c.LilvInstance, sample_count: u32) void {
|
||||
instance.?.*.lv2_descriptor.?.*.run.?(instance.?.*.lv2_handle, sample_count);
|
||||
}
|
||||
|
||||
pub fn lilv_instance_deactivate(instance: [*c]c.LilvInstance) void {
|
||||
if (instance.?.*.lv2_descriptor.?.*.deactivate != null) {
|
||||
instance.?.*.lv2_descriptor.?.*.deactivate.?(instance.?.*.lv2_handle);
|
||||
}
|
||||
}
|
24
src/main.zig
24
src/main.zig
|
@ -60,30 +60,6 @@ const Param = struct {
|
|||
value: f32,
|
||||
};
|
||||
|
||||
pub fn lilv_instance_connect_port(
|
||||
instance: [*c]c.LilvInstance,
|
||||
port_index: u32,
|
||||
data_location: ?*c_void,
|
||||
) void {
|
||||
instance.?.*.lv2_descriptor.?.*.connect_port.?(instance.?.*.lv2_handle, port_index, data_location);
|
||||
}
|
||||
|
||||
pub fn lilv_instance_activate(instance: [*c]c.LilvInstance) void {
|
||||
if (instance.?.*.lv2_descriptor.?.*.activate != null) {
|
||||
instance.?.*.lv2_descriptor.?.*.activate.?(instance.?.*.lv2_handle);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lilv_instance_run(instance: [*c]c.LilvInstance, sample_count: u32) void {
|
||||
instance.?.*.lv2_descriptor.?.*.run.?(instance.?.*.lv2_handle, sample_count);
|
||||
}
|
||||
|
||||
pub fn lilv_instance_deactivate(instance: [*c]c.LilvInstance) void {
|
||||
if (instance.?.*.lv2_descriptor.?.*.deactivate != null) {
|
||||
instance.?.*.lv2_descriptor.?.*.deactivate.?(instance.?.*.lv2_handle);
|
||||
}
|
||||
}
|
||||
|
||||
const ParamList = std.ArrayList(Param);
|
||||
|
||||
const PortType = enum {
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
const std = @import("std");
|
||||
|
||||
const c = @cImport({
|
||||
@cInclude("lilv/lilv.h");
|
||||
@cInclude("lv2/core/lv2.h");
|
||||
});
|
||||
|
||||
const ImageError = @import("image.zig").ImageError;
|
||||
|
||||
/// Control port
|
||||
pub const Param = struct {
|
||||
/// Port symbol
|
||||
|
@ -9,9 +16,39 @@ pub const Param = struct {
|
|||
value: f32,
|
||||
};
|
||||
|
||||
/// List of parameters to be set to control ports.
|
||||
pub const ParamList = std.ArrayList(Param);
|
||||
|
||||
/// Represents a relative position in the image
|
||||
pub const Position = struct {
|
||||
split: usize,
|
||||
index: usize,
|
||||
};
|
||||
|
||||
/// Represents the starting context for a single plugin run.
|
||||
pub const Context = struct {
|
||||
world: *c.LilvWorld,
|
||||
plugin: *const c.LilvPlugin,
|
||||
};
|
||||
|
||||
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{ .world = world, .plugin = plugin };
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@ pub const Runner = struct {
|
|||
image: ?*Image = null,
|
||||
|
||||
pub fn init(allocator: *std.mem.Allocator) Runner {
|
||||
return Runner{ .allocator = allocator };
|
||||
return Runner{
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Runner) void {
|
||||
|
@ -139,16 +141,16 @@ pub const Runner = struct {
|
|||
}
|
||||
|
||||
/// Run the http://lv2plug.in/plugins/eg-amp plugin over the file.
|
||||
fn ampCmd(self: *Runner, split: i32, index: i32, gain: f32) !void {
|
||||
fn ampCmd(self: *Runner, split: usize, index: usize, gain: f32) !void {
|
||||
var image = try self.getImage();
|
||||
var param = try self.allocator.create(plugin.Param);
|
||||
defer self.allocator.destroy(param);
|
||||
|
||||
param.* = Param{ .sym = "gain", .value = gain };
|
||||
param.* = plugin.Param{ .sym = "gain", .value = gain };
|
||||
|
||||
var params = plugin.ParamList.init(self.allocator);
|
||||
defer params.deinit();
|
||||
|
||||
// TODO impl this
|
||||
try image.runPlugin(
|
||||
"http://lv2plug.in/plugins/eg-amp",
|
||||
plugin.Position{ .split = split, .index = index },
|
||||
|
@ -166,12 +168,12 @@ pub const Runner = struct {
|
|||
},
|
||||
.Quicksave => try self.quicksaveCmd(),
|
||||
|
||||
// .Amp => blk: {
|
||||
// const split = try cmd.intArgAt(0);
|
||||
// const index = try cmd.intArgAt(1);
|
||||
// const gain = try cmd.floatArgAt(2);
|
||||
// try self.ampCmd(split, index, gain);
|
||||
// }
|
||||
.Amp => blk: {
|
||||
const split = try cmd.usizeArgAt(0);
|
||||
const index = try cmd.usizeArgAt(1);
|
||||
const gain = try cmd.floatArgAt(2);
|
||||
try self.ampCmd(split, index, gain);
|
||||
},
|
||||
|
||||
else => blk: {
|
||||
std.debug.warn("Unknown command: {}\n", cmd.command);
|
||||
|
|
Loading…
Reference in a new issue