Compare commits

..

No commits in common. "4c9d94d7e536e0e747567d9ce5d2d6d75009156c" and "adf89eb3600305d9b5ba5c679721eb8dab511e02" have entirely different histories.

6 changed files with 46 additions and 53 deletions

View file

@ -24,11 +24,12 @@ zig build install --prefix ~/.local/
# on your input image file # on your input image file
convert blah.jpg blah.bmp 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 # TODO have an out.bmp
// blah_g1.bmp, the second saves to blah_g2.bmp, etc. # the path to the file is shown on stdout under "temporary name: blah", go with
$your_image_viewer blah_g1.bmp # that
$your_image_viewer out.bmp
``` ```
## todo ## todo

View file

@ -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;

View file

@ -0,0 +1,4 @@
load :0;
amp 3 1 20;
# echo 3 0 1 0.2;
quicksave;

View file

@ -13,7 +13,6 @@ pub const ImageError = error{
UnknownPlugin, UnknownPlugin,
InvalidSymbol, InvalidSymbol,
InstantiateFail, InstantiateFail,
WriteFail,
}; };
/// Low level integration function with libsndfile. /// Low level integration function with libsndfile.
@ -42,13 +41,22 @@ fn sopen(
return file.?; return file.?;
} }
fn swrite(file: *c.SNDFILE, buf: [*]f32, frames: i64) !void { ///Read a single frame from a file into an interleaved buffer.
const count = c.sf_writef_float(file, buf, frames); ///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) { const n_read: c.sf_count_t = c.sf_readf_float(file, buf.ptr, 1);
std.debug.warn("Wanted to read {}, got {}\n", frames, count); const buf_chans = @intCast(c_int, buf.len);
return ImageError.WriteFail;
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 { fn getEndPos(path: []const u8) !usize {
@ -166,7 +174,8 @@ pub const Image = struct {
params: plugins.ParamList, params: plugins.ParamList,
) !void { ) !void {
var ctx = try plugins.makeContext(self.allocator, plugin_uri); 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); var ports = try lv2.setupPorts(&ctx);
@ -175,8 +184,6 @@ pub const Image = struct {
return ImageError.InvalidPlugin; return ImageError.InvalidPlugin;
} }
// TODO check n_audio_out
// now, for each param for the plugin, we find its port, and set // now, for each param for the plugin, we find its port, and set
// the value for the port there. // the value for the port there.
var it = params.iterator(); 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 // now we need to generate a temporary file and put the output of
// running the plugin on that file // running the plugin on that file
var tmpnam = try temporaryName(self.allocator); 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_fmt = mkSfInfo();
var out_file = try sopen(self.allocator, tmpnam, c.SFM_WRITE, &out_fmt); var out_file = try sopen(self.allocator, tmpnam, c.SFM_WRITE, &out_fmt);
var rctx = try plugins.RunContext.init(self.allocator, ctx.plugin); var rctx = try plugins.RunContext.init(self.allocator, ctx.plugin);
defer rctx.deinit();
rctx.connectPorts(ports); rctx.connectPorts(ports);
lv2.lilv_instance_activate(rctx.instance); 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 // just copy the original image and the part where we run the plugin
// over the image. // over the image.
const file_end = try getEndPos(self.curpath); const end_pos = (try getEndPos(self.path)) - BMPHeaderSize;
const seek_pos = position.seekPos(file_end); 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); 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; 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're still on the bmp header phase, copy bytes
// if we aren't in the range from seek_pos, copy bytes // if we aren't in the range from seek_pos, copy bytes
// if we are in the range, run lilv plugin // if we are in the range, run lilv plugin
// TODO speed this up by not reading byte-by-byte. // TODO speed this up by not reading byte-by-byte.
const read_bytes = c.sf_readf_float(self.sndfile, rctx.in_buf.ptr, 1); // TODO check value of this
if (read_bytes == 0) { _ = c.sf_readf_float(self.sndfile, rctx.in_buf.ptr, 1);
std.debug.warn("WARN! reached EOF at idx={}\n", i);
break;
}
if (i < BMPHeaderSize or !seek_pos.contains(i)) { 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 { } else {
lv2.lilv_instance_run(rctx.instance, 1); 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); _ = 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; self.curpath = tmpnam;
} }

View file

@ -51,10 +51,6 @@ pub const Context = struct {
// they should both be 1. // they should both be 1.
n_audio_in: usize = 0, n_audio_in: usize = 0,
n_audio_out: 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. /// 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 { pub fn connectPorts(self: *RunContext, ports: []*lv2.Port) void {
var i: usize = 0; var i: usize = 0;
var o: usize = 0; var o: usize = 0;

View file

@ -73,9 +73,8 @@ pub const Runner = struct {
return RunError.NoBMP; return RunError.NoBMP;
} }
// we don't copy load_path into a temporary file because we're already // TODO, copy load_path into a temporary file, then use that
// loading it under the SFM_READ mode, which won't cause any destructive // file to work on things.
// operations on the file.
self.image = try Image.open(self.allocator, load_path); self.image = try Image.open(self.allocator, load_path);
} }