diff --git a/src/custom.zig b/src/custom.zig new file mode 100644 index 0000000..e0fadc3 --- /dev/null +++ b/src/custom.zig @@ -0,0 +1,24 @@ +// Custom plugins +const std = @import("std"); +const lv2 = @import("lv2_helpers.zig"); +const plugins = @import("plugin.zig"); + +const c = lv2.c; + +const RunContext = plugins.RunContext; + +pub const RandomNoise = struct { + allocator: *std.mem.Allocator, + + pub fn init( + allocator: *std.mem.Allocator, + ) RandomNoise { + return RandomNoise{ + .allocator = allocator, + }; + } + + pub fn run(self: *RandomNoise, rctx: *RunContext) void { + rctx.in_buf[0] = f32(2); + } +}; diff --git a/src/image.zig b/src/image.zig index 6fd37db..f6a2ae1 100644 --- a/src/image.zig +++ b/src/image.zig @@ -292,15 +292,18 @@ pub const Image = struct { var i: usize = seek_pos.start; std.debug.warn("\tseek pos start: {} end: {}\n", seek_pos.start, seek_pos.end); + var inbuf = rctx.buffers.in; + var outbuf = rctx.buffers.out; + while (i <= seek_pos.end) : (i += 1) { - const read_bytes = c.sf_readf_float(self.sndfile, rctx.in_buf.ptr, 1); + const read_bytes = c.sf_readf_float(self.sndfile, inbuf.ptr, 1); if (read_bytes == 0) { std.debug.warn("WARN! reached EOF at idx={}\n", i); break; } lv2.lilv_instance_run(rctx.instance, 1); - try swrite(out_file, rctx.out_buf.ptr, 1); + try swrite(out_file, outbuf.ptr, 1); } _ = c.sf_seek(self.sndfile, @intCast(i64, seek_pos.end), c.SEEK_SET); @@ -326,4 +329,12 @@ pub const Image = struct { std.debug.warn("saved to '{}'\n", out_path); try std.fs.copyFile(self.curpath, out_path); } + + pub fn runCustomPlugin( + self: *Image, + comptime Plugin: type, + pos: plugins.Position, + ) void { + var plugin = Plugin.init(self.allocator); + } }; diff --git a/src/lang.zig b/src/lang.zig index 0c38a93..20506fa 100644 --- a/src/lang.zig +++ b/src/lang.zig @@ -26,6 +26,7 @@ pub const CommandType = enum { Delay, Vinyl, RevDelay, + Noise, }; pub const Command = struct { @@ -143,6 +144,9 @@ pub const Lang = struct { _ = try self.keywords.put("delay", .Delay); _ = try self.keywords.put("vinyl", .Vinyl); _ = try self.keywords.put("revdelay", .RevDelay); + + // custom implementations (not lv2) + _ = try self.keywords.put("noise", .Noise); } pub fn parse(self: *Lang, data: []const u8) !CommandList { diff --git a/src/plugin.zig b/src/plugin.zig index abc22f5..a3e40d4 100644 --- a/src/plugin.zig +++ b/src/plugin.zig @@ -57,10 +57,36 @@ pub const Context = struct { } }; +/// Specific run context for non-plugins. +pub const RunBuffers = struct { + allocator: *std.mem.Allocator, + + in: []f32, + out: []f32, + + pub fn init(allocator: *std.mem.Allocator) !RunBuffers { + // we allocate []f32 with size 2 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. + var in_buf = try allocator.alloc(f32, 2); + std.mem.secureZero(f32, in_buf); + + return RunBuffers{ + .allocator = allocator, + .in = in_buf, + .out = try allocator.alloc(f32, 2), + }; + } + + pub fn deinit(self: *RunBuffers) void { + self.allocator.free(self.in); + self.allocator.free(self.out); + } +}; + /// Represents the specific run context of plugin instantation. pub const RunContext = struct { - in_buf: []f32, - out_buf: []f32, + buffers: RunBuffers, instance: *c.LilvInstance, pub fn init( @@ -79,20 +105,23 @@ pub const RunContext = struct { std.mem.secureZero(f32, in_buf); return RunContext{ - .in_buf = in_buf, - .out_buf = try allocator.alloc(f32, 2), + .buffers = try RunBuffers.init(allocator), .instance = instance.?, }; } pub fn deinit(self: *RunContext) void { c.lilv_instance_free(self.instance); + self.buffers.deinit(); } pub fn connectPorts(self: *RunContext, ports: []*lv2.Port) void { var i: usize = 0; var o: usize = 0; + var in_buf = self.buffers.in; + var out_buf = self.buffers.out; + for (ports) |port, p_idx| { var p = @intCast(u32, p_idx); @@ -100,10 +129,10 @@ pub const RunContext = struct { .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]); + lv2.lilv_instance_connect_port(self.instance, p, &in_buf[i]); i += 1; } else { - lv2.lilv_instance_connect_port(self.instance, p, &self.out_buf[o]); + lv2.lilv_instance_connect_port(self.instance, p, &out_buf[o]); o += 1; } }, diff --git a/src/runner.zig b/src/runner.zig index 5632dca..4e54aaa 100644 --- a/src/runner.zig +++ b/src/runner.zig @@ -2,6 +2,7 @@ const std = @import("std"); const lang = @import("lang.zig"); const images = @import("image.zig"); const plugin = @import("plugin.zig"); +const custom = @import("custom.zig"); const Position = plugin.Position; const ParamList = plugin.ParamList; @@ -245,6 +246,11 @@ pub const Runner = struct { try image.runPlugin("http://plugin.org.uk/swh-plugins/revdelay", pos, params); } + fn noiseCmd(self: *Runner, pos: Position, params: ParamList) !void { + var image = try self.getImage(); + image.runCustomPlugin(custom.RandomNoise, pos); + } + fn runCommand(self: *Runner, cmd: *lang.Command) !void { var params = ParamList.init(self.allocator); defer params.deinit(); @@ -384,6 +390,11 @@ pub const Runner = struct { try self.revDelayCmd(pos, params); }, + .Noise => blk: { + const pos = try cmd.consumePosition(); + try self.noiseCmd(pos, params); + }, + else => blk: { std.debug.warn("Unsupported command: {}\n", cmd.command); break :blk RunError.UnknownCommand;