diff --git a/README.md b/README.md index 4a4c010..a2faa81 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,12 @@ zig build install --prefix ~/.local/ # on your input image file convert blah.jpg blah.bmp -scritcher examples/middle_amp.scri blah.bmp +scritcher examples/middle_echo.scri blah.bmp -// scritcher saves it on an incremental basis, so the first run will save to -// blah_g1.bmp, the second saves to blah_g2.bmp, etc. -$your_image_viewer blah_g1.bmp +# TODO have an out.bmp +# the path to the file is shown on stdout under "temporary name: blah", go with +# that +$your_image_viewer out.bmp ``` ## todo diff --git a/examples/middle_amp.scri b/examples/middle_amp.scri deleted file mode 100644 index e1eed36..0000000 --- a/examples/middle_amp.scri +++ /dev/null @@ -1,8 +0,0 @@ -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 new file mode 100644 index 0000000..be4e7cf --- /dev/null +++ b/examples/middle_echo.scri @@ -0,0 +1,4 @@ +load :0; +amp 3 1 20; +# echo 3 0 1 0.2; +quicksave; diff --git a/src/image.zig b/src/image.zig index 221d3cb..179ac45 100644 --- a/src/image.zig +++ b/src/image.zig @@ -13,7 +13,6 @@ pub const ImageError = error{ UnknownPlugin, InvalidSymbol, InstantiateFail, - WriteFail, }; /// Low level integration function with libsndfile. @@ -42,13 +41,22 @@ fn sopen( return file.?; } -fn swrite(file: *c.SNDFILE, buf: [*]f32, frames: i64) !void { - const count = c.sf_writef_float(file, buf, frames); +///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.?; - if (count != frames) { - std.debug.warn("Wanted to read {}, got {}\n", frames, count); - return ImageError.WriteFail; + 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; } fn getEndPos(path: []const u8) !usize { @@ -166,7 +174,8 @@ pub const Image = struct { params: plugins.ParamList, ) !void { var ctx = try plugins.makeContext(self.allocator, plugin_uri); - defer ctx.deinit(); + std.debug.warn("\tworld: {}\n", ctx.world); + std.debug.warn("\tplugin: {}\n", ctx.plugin); var ports = try lv2.setupPorts(&ctx); @@ -175,8 +184,6 @@ 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(); @@ -206,14 +213,12 @@ 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("\trunning plugin from '{}' to '{}'\n", self.curpath, tmpnam); + std.debug.warn("temporary name: {}\n", 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); @@ -221,41 +226,41 @@ pub const Image = struct { // just copy the original image and the part where we run the plugin // over the image. - const file_end = try getEndPos(self.curpath); - const seek_pos = position.seekPos(file_end); + const end_pos = (try getEndPos(self.path)) - BMPHeaderSize; + std.debug.warn("file end: {}\n", end_pos); + const seek_pos = position.seekPos(end_pos); 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 < file_end) : (i += 1) { + while (i < end_pos) : (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. - 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; - } + // TODO check value of this + _ = c.sf_readf_float(self.sndfile, rctx.in_buf.ptr, 1); if (i < BMPHeaderSize or !seek_pos.contains(i)) { - try swrite(out_file, rctx.in_buf.ptr, 1); + _ = c.sf_writef_float(out_file, rctx.in_buf.ptr, 1); } else { lv2.lilv_instance_run(rctx.instance, 1); - try swrite(out_file, rctx.out_buf.ptr, 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? + } } } - c.sf_write_sync(out_file); - _ = c.sf_close(out_file); _ = c.sf_close(self.sndfile); - - // 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.sndfile = out_file; self.curpath = tmpnam; } diff --git a/src/plugin.zig b/src/plugin.zig index 6ee0c94..45ea8d2 100644 --- a/src/plugin.zig +++ b/src/plugin.zig @@ -51,10 +51,6 @@ 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. @@ -79,10 +75,6 @@ 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; diff --git a/src/runner.zig b/src/runner.zig index 30fc12a..076bdbd 100644 --- a/src/runner.zig +++ b/src/runner.zig @@ -73,9 +73,8 @@ pub const Runner = struct { return RunError.NoBMP; } - // we don't copy load_path into a temporary file because we're already - // loading it under the SFM_READ mode, which won't cause any destructive - // operations on the file. + // 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); }