diff --git a/examples/middle_amp.scri b/examples/middle_amp.scri new file mode 100644 index 0000000..e1eed36 --- /dev/null +++ b/examples/middle_amp.scri @@ -0,0 +1,8 @@ +load :0; +amp 5 1 8; +amp 7 4 2; +amp 80 70 10; +amp 80 73 20; +amp 80 75 20; +amp 80 76 20; +quicksave; diff --git a/examples/middle_echo.scri b/examples/middle_echo.scri deleted file mode 100644 index be4e7cf..0000000 --- a/examples/middle_echo.scri +++ /dev/null @@ -1,4 +0,0 @@ -load :0; -amp 3 1 20; -# echo 3 0 1 0.2; -quicksave; diff --git a/src/image.zig b/src/image.zig index 179ac45..221d3cb 100644 --- a/src/image.zig +++ b/src/image.zig @@ -13,6 +13,7 @@ pub const ImageError = error{ UnknownPlugin, InvalidSymbol, InstantiateFail, + WriteFail, }; /// Low level integration function with libsndfile. @@ -41,22 +42,13 @@ fn sopen( return file.?; } -///Read a single frame from a file into an interleaved buffer. -///If more channels are required than are available in the file, the remaining -///channels are distributed in a round-robin fashion (LRLRL). -fn sread(file_opt: ?*c.SNDFILE, file_chans: c_int, buf: []f32) bool { - var file = file_opt.?; +fn swrite(file: *c.SNDFILE, buf: [*]f32, frames: i64) !void { + const count = c.sf_writef_float(file, buf, frames); - 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))]; + if (count != frames) { + std.debug.warn("Wanted to read {}, got {}\n", frames, count); + return ImageError.WriteFail; } - - return n_read == 1; } fn getEndPos(path: []const u8) !usize { @@ -174,8 +166,7 @@ pub const Image = struct { params: plugins.ParamList, ) !void { var ctx = try plugins.makeContext(self.allocator, plugin_uri); - std.debug.warn("\tworld: {}\n", ctx.world); - std.debug.warn("\tplugin: {}\n", ctx.plugin); + defer ctx.deinit(); var ports = try lv2.setupPorts(&ctx); @@ -184,6 +175,8 @@ pub const Image = struct { return ImageError.InvalidPlugin; } + // TODO check n_audio_out + // now, for each param for the plugin, we find its port, and set // the value for the port there. var it = params.iterator(); @@ -213,12 +206,14 @@ pub const Image = struct { // now we need to generate a temporary file and put the output of // running the plugin on that file var tmpnam = try temporaryName(self.allocator); - std.debug.warn("temporary name: {}\n", tmpnam); + std.debug.warn("\trunning plugin from '{}' to '{}'\n", self.curpath, tmpnam); var out_fmt = mkSfInfo(); var out_file = try sopen(self.allocator, tmpnam, c.SFM_WRITE, &out_fmt); var rctx = try plugins.RunContext.init(self.allocator, ctx.plugin); + defer rctx.deinit(); + rctx.connectPorts(ports); lv2.lilv_instance_activate(rctx.instance); @@ -226,41 +221,41 @@ pub const Image = struct { // just copy the original image and the part where we run the plugin // over the image. - const end_pos = (try getEndPos(self.path)) - BMPHeaderSize; - std.debug.warn("file end: {}\n", end_pos); - const seek_pos = position.seekPos(end_pos); + const file_end = try getEndPos(self.curpath); + const seek_pos = position.seekPos(file_end); std.debug.warn("start {} end {}\n", seek_pos.start, seek_pos.end); + var seeked = c.sf_seek(self.sndfile, 0, c.SEEK_SET); + std.debug.warn("in: seek {}\n", seeked); + var i: usize = 0; - while (i < end_pos) : (i += 1) { + while (i < file_end) : (i += 1) { // if we're still on the bmp header phase, copy bytes // if we aren't in the range from seek_pos, copy bytes // if we are in the range, run lilv plugin // TODO speed this up by not reading byte-by-byte. - // TODO check value of this - _ = c.sf_readf_float(self.sndfile, rctx.in_buf.ptr, 1); + const read_bytes = c.sf_readf_float(self.sndfile, rctx.in_buf.ptr, 1); + if (read_bytes == 0) { + std.debug.warn("WARN! reached EOF at idx={}\n", i); + break; + } if (i < BMPHeaderSize or !seek_pos.contains(i)) { - _ = c.sf_writef_float(out_file, rctx.in_buf.ptr, 1); + try swrite(out_file, rctx.in_buf.ptr, 1); } else { lv2.lilv_instance_run(rctx.instance, 1); - - var count = c.sf_writef_float(out_file, rctx.out_buf.ptr, 1); - if (count != 1) { - std.debug.warn( - "Failed to write to output file at idx {}.\n", - i, - ); - - // maybe we return an error? - } + try swrite(out_file, rctx.out_buf.ptr, 1); } } + c.sf_write_sync(out_file); + _ = c.sf_close(out_file); _ = c.sf_close(self.sndfile); - self.sndfile = out_file; + + // reopen the file as SFM_READ so we can run plugin chains etc + self.sndfile = try sopen(self.allocator, tmpnam, c.SFM_READ, &out_fmt); self.curpath = tmpnam; } diff --git a/src/plugin.zig b/src/plugin.zig index 45ea8d2..6ee0c94 100644 --- a/src/plugin.zig +++ b/src/plugin.zig @@ -51,6 +51,10 @@ pub const Context = struct { // 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. @@ -75,6 +79,10 @@ pub const RunContext = struct { }; } + 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;