// Custom plugins const std = @import("std"); const lv2 = @import("lv2_helpers.zig"); const plugins = @import("plugin.zig"); const image = @import("image.zig"); 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: *plugins.ParamMap, ) ?RandomNoise { const seed = @floatToInt(u64, params.get("seed").?.value); const fillbytes = @floatToInt(usize, params.get("fill_bytes").?.value); var r = std.rand.DefaultPrng.init(seed); if (fillbytes > 0) { var rand_buf = allocator.alloc(f32, fillbytes) catch return null; for (rand_buf) |_, 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: *plugins.ParamMap, ) ?WildNoise { const seed = @floatToInt(u64, params.get("seed").?.value); const fillbytes = @floatToInt(usize, params.get("fill_bytes").?.value); var r = std.rand.DefaultPrng.init(seed); if (fillbytes > 0) { var rand_buf = allocator.alloc(f32, fillbytes) catch return null; for (rand_buf) |_, idx| { rand_buf[idx] = @intToFloat(f32, 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] = @intToFloat(f32, 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: *plugins.ParamMap, ) Write { const data = params.get("data").?; return Write{ .data = data.value, }; } pub fn deinit(self: *Write) void {} 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, filepath: []const u8) @This() { return Embed{ .allocator = allocator, .filepath = filepath, }; } pub fn setup(self: *@This()) !void { var in_fmt = c.SF_INFO{ .frames = c_int(0), .samplerate = c_int(0), .channels = c_int(0), .format = c_int(0), .sections = c_int(0), .seekable = 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, @intCast(usize, in_fmt.channels)); } pub fn deinit(self: *@This()) void {} 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); std.debug.warn( "Failed to read {} ({})\n", self.filepath, c.sf_error_number(st), ); return; } bufs.out[0] = bufs.in[0] + self.buf[0]; } };