// Custom plugins const std = @import("std"); const lv2 = @import("lv2_helpers.zig"); const plugins = @import("plugin.zig"); const image = @import("image.zig"); const log = std.log.scoped(.scritcher_custom); const c = lv2.c; const RunBuffers = plugins.RunBuffers; pub const RandomNoise = struct { r: std.rand.DefaultPrng, rand_buf: ?[]f32 = null, allocator: ?std.mem.Allocator = null, cnt: usize = 0, pub fn init( allocator: std.mem.Allocator, params: anytype, ) ?RandomNoise { var r = std.rand.DefaultPrng.init(params.seed); if (params.fill_bytes > 0) { var rand_buf = allocator.alloc(f32, params.fill_bytes) catch return null; for (rand_buf, 0..) |_, idx| { rand_buf[idx] = r.random().float(f32); } return RandomNoise{ .r = r, .allocator = allocator, .rand_buf = rand_buf, }; } else { return RandomNoise{ .r = r, }; } } pub fn deinit(self: *RandomNoise) void { if (self.allocator == null) return; if (self.rand_buf == null) return; self.allocator.?.free(self.rand_buf.?); } pub fn run(self: *RandomNoise, bufs: *RunBuffers) void { if (self.rand_buf) |rand_buf| { if (self.cnt >= rand_buf.len) self.cnt = 0; bufs.out[0] = rand_buf[self.cnt]; self.cnt += 1; } else { bufs.out[0] = self.r.random().float(f32); } } }; pub const WildNoise = struct { r: std.rand.DefaultPrng, rand_buf: ?[]f32 = null, allocator: ?std.mem.Allocator = null, cnt: usize = 0, pub fn init( allocator: std.mem.Allocator, params: anytype, ) ?WildNoise { var r = std.rand.DefaultPrng.init(params.seed); if (params.fill_bytes > 0) { var rand_buf = allocator.alloc(f32, params.fill_bytes) catch return null; for (rand_buf, 0..) |_, idx| { rand_buf[idx] = @as(f32, @floatFromInt(r.random().int(u1))); } return WildNoise{ .r = r, .rand_buf = rand_buf, }; } else { return WildNoise{ .r = r, }; } } pub fn deinit(self: *WildNoise) void { if (self.allocator == null) return; if (self.rand_buf == null) return; self.allocator.?.free(self.rand_buf.?); } pub fn run(self: *WildNoise, bufs: *RunBuffers) void { if (self.rand_buf) |rand_buf| { if (self.cnt >= rand_buf.len) self.cnt = 0; bufs.out[0] = rand_buf[self.cnt]; self.cnt += 1; } else { bufs.out[0] = @as(f32, @floatFromInt(self.r.random().int(u1))); } } }; /// Write any float to the image. /// Keep in mind that the bit representation of the float will clash with /// the format of BMP pixel data, which means writing 0 everywhere won't give /// you the black color. pub const Write = struct { data: f32, pub fn init( allocator: std.mem.Allocator, params: anytype, ) Write { _ = allocator; return Write{ .data = params.data, }; } pub fn deinit(self: *Write) void { _ = self; } pub fn run(self: *Write, bufs: *RunBuffers) void { bufs.out[0] = self.data; } }; pub const Embed = struct { allocator: std.mem.Allocator, filepath: []const u8, sndfile: *c.SNDFILE = undefined, buf: []f32 = undefined, pub fn init(allocator: std.mem.Allocator, params: anytype) @This() { return Embed{ .allocator = allocator, .filepath = params.path, }; } pub fn setup(self: *@This()) !void { var in_fmt = c.SF_INFO{ .frames = @as(c_int, 0), .samplerate = @as(c_int, 0), .channels = @as(c_int, 0), .format = @as(c_int, 0), .sections = @as(c_int, 0), .seekable = @as(c_int, 0), }; self.sndfile = try image.sopen( self.allocator, self.filepath, c.SFM_READ, &in_fmt, ); image.sseek(self.sndfile, 0); self.buf = try self.allocator.alloc(f32, @as(usize, @intCast(in_fmt.channels))); } pub fn deinit(self: *@This()) void { _ = self; } pub fn run(self: *@This(), bufs: *RunBuffers) void { const read_bytes = c.sf_readf_float(self.sndfile, self.buf.ptr, 1); if (read_bytes == 0) { bufs.out[0] = bufs.in[0]; return; } if (read_bytes < 0) { const st: i32 = c.sf_error(self.sndfile); log.debug("Failed to read {s} ({s})", .{ self.filepath, c.sf_error_number(st), }); return; } bufs.out[0] = bufs.in[0] + self.buf[0]; } };