diff --git a/src/image.zig b/src/image.zig index c11e3fd..4bffee9 100644 --- a/src/image.zig +++ b/src/image.zig @@ -7,6 +7,9 @@ const plugins = @import("plugin.zig"); /// Approximate size of the BMP header. pub const BMPHeaderSize: usize = 82000; +/// Buffer size for main copying +pub const BufferSize: usize = 60000; + pub const ImageError = error{ OpenFail, InvalidPlugin, @@ -155,6 +158,34 @@ pub const Image = struct { return n_read == 1; } + fn copyBytes( + self: *Image, + out_file: *c.SNDFILE, + buf: []f32, + start: usize, + end: usize, + ) !void { + const total_bytes = end - start; + + var i: usize = start; + while (i < end) : (i += buf.len) { + const read_bytes = c.sf_readf_float(self.sndfile, buf.ptr, @intCast(i64, buf.len)); + + var view: []f32 = buf[0..buf.len]; + if (i + buf.len > end) { + const excess = i + buf.len - end; + view = buf[0..excess]; + _ = c.sf_seek( + self.sndfile, + -@intCast(i64, excess), + c.SEEK_CUR, + ); + } + + try swrite(out_file, view.ptr, @intCast(i64, view.len)); + } + } + /// Run a plugin over the image. /// This setups a new lilv world/plugin among other things. /// The internal SNDFILE pointer is modified to point to the output of the @@ -228,28 +259,52 @@ pub const Image = struct { // make sure we start from 0 _ = c.sf_seek(self.sndfile, 0, c.SEEK_SET); - var i: usize = 0; + // there are four main stages: + // - the bmp header copy + // - pre-plugin + // - plugin + // - post-plugin - 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 + var header_buf = try self.allocator.alloc(f32, BMPHeaderSize); + defer self.allocator.free(header_buf); - // TODO speed this up by not reading byte-by-byte. + var file_copy_buf = try self.allocator.alloc(f32, BufferSize); + defer self.allocator.free(file_copy_buf); + + // bmp header copy + const header_len = @intCast(i64, header_buf.len); + _ = c.sf_readf_float(self.sndfile, header_buf.ptr, header_len); + try swrite(out_file, header_buf.ptr, header_len); + + // pre-plugin copy + try self.copyBytes( + out_file, + file_copy_buf, + BMPHeaderSize, + seek_pos.start, + ); + + var i: usize = seek_pos.start; + + while (i < seek_pos.end) : (i += 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)) { - try swrite(out_file, rctx.in_buf.ptr, 1); - } else { - lv2.lilv_instance_run(rctx.instance, 1); - try swrite(out_file, rctx.out_buf.ptr, 1); - } + lv2.lilv_instance_run(rctx.instance, 1); + try swrite(out_file, rctx.out_buf.ptr, 1); } + // post-plugin copy + try self.copyBytes( + out_file, + file_copy_buf, + seek_pos.end, + file_end, + ); + c.sf_write_sync(out_file); _ = c.sf_close(out_file); _ = c.sf_close(self.sndfile);