Compare commits
No commits in common. "bbf34f1133a36bbab71349b87cdbddf94fdee742" and "276100c55692c6f65f4f87efbadd3cfb63b410a3" have entirely different histories.
bbf34f1133
...
276100c556
7 changed files with 28 additions and 311 deletions
|
@ -1,4 +1,3 @@
|
||||||
load :0;
|
load :0;
|
||||||
amp 3 1 10;
|
echo 3 0 1 0.2;
|
||||||
# echo 3 0 1 0.2;
|
|
||||||
quicksave;
|
quicksave;
|
||||||
|
|
|
@ -1,20 +1,9 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const lv2 = @import("lv2_helpers.zig");
|
|
||||||
|
|
||||||
const c = @cImport({
|
const c = @cImport({
|
||||||
@cInclude("sndfile.h");
|
@cInclude("sndfile.h");
|
||||||
|
|
||||||
@cInclude("lilv/lilv.h");
|
|
||||||
@cInclude("lv2/core/lv2.h");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const plugins = @import("plugin.zig");
|
pub const ImageError = error{OpenFail};
|
||||||
|
|
||||||
pub const ImageError = error{
|
|
||||||
OpenFail,
|
|
||||||
InvalidPlugin,
|
|
||||||
UnknownPlugin,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Low level integration function with libsndfile.
|
/// Low level integration function with libsndfile.
|
||||||
fn sopen(
|
fn sopen(
|
||||||
|
@ -81,35 +70,4 @@ 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 {
|
|
||||||
var context = try plugins.makeContext(self.allocator, plugin_uri);
|
|
||||||
std.debug.warn("world: {}\n", context.world);
|
|
||||||
std.debug.warn("plugin: {}\n", context.plugin);
|
|
||||||
|
|
||||||
var ports = try lv2.setupPorts(&context);
|
|
||||||
for (ports) |port| {
|
|
||||||
std.debug.warn("port: {}\n", port.*);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
28
src/lang.zig
28
src/lang.zig
|
@ -3,7 +3,6 @@ const std = @import("std");
|
||||||
pub const ParseError = error{
|
pub const ParseError = error{
|
||||||
NoCommandGiven,
|
NoCommandGiven,
|
||||||
UnknownCommand,
|
UnknownCommand,
|
||||||
ArgRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const CommandType = enum {
|
pub const CommandType = enum {
|
||||||
|
@ -20,32 +19,6 @@ pub const Command = struct {
|
||||||
pub fn print(self: *const Command) void {
|
pub fn print(self: *const Command) void {
|
||||||
std.debug.warn("cmd:{}\n", self.command);
|
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 = try self.argAt(idx);
|
|
||||||
return try std.fmt.parseInt(i32, arg, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn floatArgAt(self: *const Command, idx: usize) !f32 {
|
|
||||||
var arg = try self.argAt(idx);
|
|
||||||
return try std.fmt.parseFloat(f32, arg);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const CommandList = std.ArrayList(*Command);
|
pub const CommandList = std.ArrayList(*Command);
|
||||||
|
@ -82,7 +55,6 @@ pub const Lang = struct {
|
||||||
stmt = std.mem.trimLeft(u8, stmt, "\n");
|
stmt = std.mem.trimLeft(u8, stmt, "\n");
|
||||||
|
|
||||||
if (stmt.len == 0) continue;
|
if (stmt.len == 0) continue;
|
||||||
if (stmt[0] == '#') continue;
|
|
||||||
|
|
||||||
// TODO better tokenizer instead of just tokenize(" ");
|
// TODO better tokenizer instead of just tokenize(" ");
|
||||||
var tok_it = std.mem.tokenize(stmt, " ");
|
var tok_it = std.mem.tokenize(stmt, " ");
|
||||||
|
|
|
@ -1,150 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const plugin = @import("plugin.zig");
|
|
||||||
|
|
||||||
pub 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const PortType = enum {
|
|
||||||
Control,
|
|
||||||
Audio,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Port = struct {
|
|
||||||
lilv_port: ?*const c.LilvPort,
|
|
||||||
ptype: PortType,
|
|
||||||
index: u32,
|
|
||||||
value: f32,
|
|
||||||
is_input: bool,
|
|
||||||
optional: bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Setup ports for a given plugin. Gives an array to pointers of Port structs.
|
|
||||||
/// This setup is required so we link the plugin to the ports later on, and
|
|
||||||
/// also link our buffers, and control values.
|
|
||||||
pub fn setupPorts(ctx: *plugin.Context) ![]*Port {
|
|
||||||
var world = ctx.world;
|
|
||||||
const n_ports: u32 = c.lilv_plugin_get_num_ports(ctx.plugin);
|
|
||||||
|
|
||||||
var ports = try ctx.allocator.alloc(*Port, n_ports);
|
|
||||||
|
|
||||||
for (ports) |port_ptr, idx| {
|
|
||||||
var port = try ctx.allocator.create(Port);
|
|
||||||
port.* = Port{
|
|
||||||
.lilv_port = null,
|
|
||||||
.ptype = .Control,
|
|
||||||
.index = f32(0),
|
|
||||||
.value = f32(0),
|
|
||||||
.is_input = false,
|
|
||||||
.optional = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
ports[idx] = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
var values: []f32 = try ctx.allocator.alloc(f32, n_ports);
|
|
||||||
defer ctx.allocator.free(values);
|
|
||||||
|
|
||||||
c.lilv_plugin_get_port_ranges_float(ctx.plugin, null, null, values.ptr);
|
|
||||||
|
|
||||||
// bad solution, but it really do be like that
|
|
||||||
const LV2_CORE__InputPort = try Lv2Core("#InputPort");
|
|
||||||
const LV2_CORE__OutputPort = try Lv2Core("#OutputPort");
|
|
||||||
const LV2_CORE__AudioPort = try Lv2Core("#AudioPort");
|
|
||||||
const LV2_CORE__ControlPort = try Lv2Core("#ControlPort");
|
|
||||||
const LV2_CORE__connectionOptional = try Lv2Core("#connectionOptional");
|
|
||||||
|
|
||||||
var lv2_InputPort = c.lilv_new_uri(world, LV2_CORE__InputPort.ptr);
|
|
||||||
defer std.heap.c_allocator.destroy(lv2_InputPort);
|
|
||||||
|
|
||||||
var lv2_OutputPort = c.lilv_new_uri(world, LV2_CORE__OutputPort.ptr);
|
|
||||||
defer std.heap.c_allocator.destroy(lv2_OutputPort);
|
|
||||||
|
|
||||||
var lv2_AudioPort = c.lilv_new_uri(world, LV2_CORE__AudioPort.ptr);
|
|
||||||
defer std.heap.c_allocator.destroy(lv2_AudioPort);
|
|
||||||
|
|
||||||
var lv2_ControlPort = c.lilv_new_uri(world, LV2_CORE__ControlPort.ptr);
|
|
||||||
defer std.heap.c_allocator.destroy(lv2_ControlPort);
|
|
||||||
|
|
||||||
var lv2_connectionOptional = c.lilv_new_uri(world, LV2_CORE__connectionOptional.ptr);
|
|
||||||
defer std.heap.c_allocator.destroy(lv2_connectionOptional);
|
|
||||||
|
|
||||||
var i: u32 = 0;
|
|
||||||
while (i < n_ports) : (i += 1) {
|
|
||||||
var port: *Port = ports[i];
|
|
||||||
|
|
||||||
const lport = c.lilv_plugin_get_port_by_index(ctx.plugin, i).?;
|
|
||||||
|
|
||||||
port.lilv_port = lport;
|
|
||||||
port.index = i;
|
|
||||||
|
|
||||||
if (std.math.isNan(values[i])) {
|
|
||||||
port.value = f32(0);
|
|
||||||
} else {
|
|
||||||
port.value = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
port.optional = c.lilv_port_has_property(ctx.plugin, lport, lv2_connectionOptional);
|
|
||||||
|
|
||||||
if (c.lilv_port_is_a(ctx.plugin, lport, lv2_InputPort)) {
|
|
||||||
port.is_input = true;
|
|
||||||
} else if (!c.lilv_port_is_a(ctx.plugin, lport, lv2_OutputPort) and !port.optional) {
|
|
||||||
std.debug.warn("Port {} is neither input or output\n", i);
|
|
||||||
return error.UnassignedIOPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if port is an audio or control port
|
|
||||||
if (c.lilv_port_is_a(ctx.plugin, lport, lv2_ControlPort)) {
|
|
||||||
port.ptype = .Control;
|
|
||||||
} else if (c.lilv_port_is_a(ctx.plugin, lport, lv2_AudioPort)) {
|
|
||||||
port.ptype = .Audio;
|
|
||||||
|
|
||||||
if (port.is_input) {
|
|
||||||
ctx.n_audio_in += 1;
|
|
||||||
} else {
|
|
||||||
ctx.n_audio_out += 1;
|
|
||||||
}
|
|
||||||
} else if (!port.optional) {
|
|
||||||
std.debug.warn("Port {} has unsupported type\n", i);
|
|
||||||
return error.UnsupportedPortType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ports;
|
|
||||||
}
|
|
24
src/main.zig
24
src/main.zig
|
@ -60,6 +60,30 @@ const Param = struct {
|
||||||
value: f32,
|
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 ParamList = std.ArrayList(Param);
|
||||||
|
|
||||||
const PortType = enum {
|
const PortType = enum {
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
const c = @import("lv2_helpers.zig").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 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 {
|
|
||||||
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 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 };
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const lang = @import("lang.zig");
|
const lang = @import("lang.zig");
|
||||||
const images = @import("image.zig");
|
const images = @import("image.zig");
|
||||||
const plugin = @import("plugin.zig");
|
|
||||||
|
|
||||||
const Image = images.Image;
|
const Image = images.Image;
|
||||||
|
|
||||||
|
@ -16,9 +15,7 @@ pub const Runner = struct {
|
||||||
image: ?*Image = null,
|
image: ?*Image = null,
|
||||||
|
|
||||||
pub fn init(allocator: *std.mem.Allocator) Runner {
|
pub fn init(allocator: *std.mem.Allocator) Runner {
|
||||||
return Runner{
|
return Runner{ .allocator = allocator };
|
||||||
.allocator = allocator,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Runner) void {
|
pub fn deinit(self: *Runner) void {
|
||||||
|
@ -73,8 +70,6 @@ pub const Runner = struct {
|
||||||
return RunError.NoBMP;
|
return RunError.NoBMP;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO, copy load_path into a temporary file, then use that
|
|
||||||
// file to work on things.
|
|
||||||
self.image = try Image.open(self.allocator, load_path);
|
self.image = try Image.open(self.allocator, load_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,24 +135,6 @@ pub const Runner = struct {
|
||||||
std.debug.warn("out path: {}\n", out_path);
|
std.debug.warn("out path: {}\n", out_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the http://lv2plug.in/plugins/eg-amp plugin over the file.
|
|
||||||
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.* = plugin.Param{ .sym = "gain", .value = gain };
|
|
||||||
|
|
||||||
var params = plugin.ParamList.init(self.allocator);
|
|
||||||
defer params.deinit();
|
|
||||||
|
|
||||||
try image.runPlugin(
|
|
||||||
"http://lv2plug.in/plugins/eg-amp",
|
|
||||||
plugin.Position{ .split = split, .index = index },
|
|
||||||
params,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn runCommand(self: *Runner, cmd: *lang.Command) !void {
|
fn runCommand(self: *Runner, cmd: *lang.Command) !void {
|
||||||
return switch (cmd.command) {
|
return switch (cmd.command) {
|
||||||
.Noop => {},
|
.Noop => {},
|
||||||
|
@ -166,15 +143,8 @@ pub const Runner = struct {
|
||||||
try self.loadCmd(path);
|
try self.loadCmd(path);
|
||||||
break :blk;
|
break :blk;
|
||||||
},
|
},
|
||||||
|
|
||||||
.Quicksave => try self.quicksaveCmd(),
|
.Quicksave => try self.quicksaveCmd(),
|
||||||
|
|
||||||
.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: {
|
else => blk: {
|
||||||
std.debug.warn("Unknown command: {}\n", cmd.command);
|
std.debug.warn("Unknown command: {}\n", cmd.command);
|
||||||
break :blk RunError.UnknownCommand;
|
break :blk RunError.UnknownCommand;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue