fix multiple plugin runs over same file
- add deinit() functions to help
This commit is contained in:
parent
adf89eb360
commit
17ca737291
4 changed files with 46 additions and 39 deletions
8
examples/middle_amp.scri
Normal file
8
examples/middle_amp.scri
Normal file
|
@ -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;
|
|
@ -1,4 +0,0 @@
|
||||||
load :0;
|
|
||||||
amp 3 1 20;
|
|
||||||
# echo 3 0 1 0.2;
|
|
||||||
quicksave;
|
|
|
@ -13,6 +13,7 @@ pub const ImageError = error{
|
||||||
UnknownPlugin,
|
UnknownPlugin,
|
||||||
InvalidSymbol,
|
InvalidSymbol,
|
||||||
InstantiateFail,
|
InstantiateFail,
|
||||||
|
WriteFail,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Low level integration function with libsndfile.
|
/// Low level integration function with libsndfile.
|
||||||
|
@ -41,22 +42,13 @@ fn sopen(
|
||||||
return file.?;
|
return file.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Read a single frame from a file into an interleaved buffer.
|
fn swrite(file: *c.SNDFILE, buf: [*]f32, frames: i64) !void {
|
||||||
///If more channels are required than are available in the file, the remaining
|
const count = c.sf_writef_float(file, buf, frames);
|
||||||
///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.?;
|
|
||||||
|
|
||||||
const n_read: c.sf_count_t = c.sf_readf_float(file, buf.ptr, 1);
|
if (count != frames) {
|
||||||
const buf_chans = @intCast(c_int, buf.len);
|
std.debug.warn("Wanted to read {}, got {}\n", frames, count);
|
||||||
|
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 {
|
||||||
|
@ -174,8 +166,7 @@ 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);
|
||||||
std.debug.warn("\tworld: {}\n", ctx.world);
|
defer ctx.deinit();
|
||||||
std.debug.warn("\tplugin: {}\n", ctx.plugin);
|
|
||||||
|
|
||||||
var ports = try lv2.setupPorts(&ctx);
|
var ports = try lv2.setupPorts(&ctx);
|
||||||
|
|
||||||
|
@ -184,6 +175,8 @@ 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();
|
||||||
|
@ -213,12 +206,14 @@ 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("temporary name: {}\n", tmpnam);
|
std.debug.warn("\trunning plugin from '{}' to '{}'\n", self.curpath, 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);
|
||||||
|
|
||||||
|
@ -226,41 +221,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 end_pos = (try getEndPos(self.path)) - BMPHeaderSize;
|
const file_end = try getEndPos(self.curpath);
|
||||||
std.debug.warn("file end: {}\n", end_pos);
|
const seek_pos = position.seekPos(file_end);
|
||||||
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 < end_pos) : (i += 1) {
|
while (i < file_end) : (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.
|
||||||
// TODO check value of this
|
const read_bytes = c.sf_readf_float(self.sndfile, rctx.in_buf.ptr, 1);
|
||||||
_ = 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)) {
|
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 {
|
} 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,10 @@ 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.
|
||||||
|
@ -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 {
|
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;
|
||||||
|
|
Loading…
Reference in a new issue