const std = @import("std"); const math = std.math; const print = std.debug.print; const Allocator = std.mem.Allocator; const SoundNode = @import("soundnode.zig").SoundNode; const FreqAmpBuffer = @import("freqamp.zig").FreqAmpBuffer; const FreqAmpList = @import("freqamp.zig").FreqAmpList; const utility = @import("utility.zig"); pub const Activity = struct { start_tick: u32, end_tick: u32, opcode: u16, soundnode: *SoundNode, operands: [6]f64 = std.mem.zeroes([6]f64), pub fn create(allocator: Allocator, start_tick: u32, end_tick: u32, opcode: u16, soundnode: *SoundNode, operands: [6]f64) !*Activity { const a = try allocator.create(Activity); a.* = .{ .start_tick = start_tick, .end_tick = end_tick, .opcode = opcode, .soundnode = soundnode, .operands = operands, }; return a; } pub fn do(self: *Activity) !void { switch (self.opcode) { 4 => { self.relay(); }, 5 => { self.setpos(); }, 6 => { try self.setbasefreq(); }, 7 => { try self.setgain(); }, 8 => { try self.setphase(); }, 9 => { self.sine(); }, 10 => { self.triangle(); }, 11 => { self.square(); }, 12 => { self.sawtooth(); }, 13 => { try self.setskew(); }, 14 => { self.skewsine(); }, 15 => { try self.slidebasefreq(); }, 16 => { try self.slidegain(); }, 17 => { try self.slidephase(); }, 18 => { try self.slideskew(); }, 19 => { self.slidepos(); }, else => {}, } } pub fn relay_imprecise(self: *Activity) void { const current_tick: u32 = self.soundnode.fab.current_tick; for (self.soundnode.wire_in.items, 0..) |wired_sn, i| { const relayed_r_amp = wired_sn.fab.get_r_amp(current_tick); self.soundnode.fab.add_r_amp(relayed_r_amp); _ = i; } for (self.soundnode.air_in.items, 0..) |aired_sn, i| { const dist: f64 = self.soundnode.distance(aired_sn); var sample_tick: u32 = 0; const tck = @as(f64, @floatFromInt(current_tick)) - (128.571428 * dist); if (tck > 0) { sample_tick = @intFromFloat( @floor(tck) ); const attenuation: f64 = @as(f64, std.math.exp(-(dist / 100.0))); const relayed_r_amp = aired_sn.fab.get_r_amp(sample_tick) * attenuation; self.soundnode.fab.add_r_amp(relayed_r_amp); } _ = i; } } pub fn relay(self: *Activity) void { const current_tick: u32 = self.soundnode.fab.current_tick; for (self.soundnode.wire_in.items, 0..) |wired_sn, i| { const relayed_r_amp = wired_sn.fab.get_r_amp(current_tick); self.soundnode.fab.add_r_amp(relayed_r_amp); _ = i; } for (self.soundnode.air_in.items, 0..) |aired_sn, i| { const dist: f64 = self.soundnode.distance(aired_sn); var b_sample_tick: u32 = 0; var n_sample_tick: u32 = 0; const tck = @as(f64, @floatFromInt(current_tick)) - (128.571428 * dist); if (tck > 0) { b_sample_tick = @intFromFloat( @floor(tck) ); n_sample_tick = b_sample_tick + 1; const attenuation: f64 = @as(f64, std.math.exp(-(dist / 100.0))); const b_r_amp = aired_sn.fab.get_r_amp(b_sample_tick); const n_r_amp = aired_sn.fab.get_r_amp(n_sample_tick); const tick_diff = tck - @as(f64, @floatFromInt(b_sample_tick)); const relayed_r_amp = (b_r_amp + (tick_diff * (n_r_amp - b_r_amp))) * attenuation; self.soundnode.fab.add_r_amp(relayed_r_amp); } _ = i; } } pub fn setbasefreq(self: *Activity) !void { try self.soundnode.s("basefreq", self.operands[0]); } pub fn setgain(self: *Activity) !void { try self.soundnode.s("gain", self.operands[0]); } pub fn setphase(self: *Activity) !void { try self.soundnode.s("phase", self.operands[0]); } pub fn setpos(self: *Activity) void { self.soundnode.x = @as(f32, @floatCast(self.operands[0])); self.soundnode.y = @as(f32, @floatCast(self.operands[1])); self.soundnode.z = @as(f32, @floatCast(self.operands[2])); } pub fn sine(self: *Activity) void { const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); const freq = self.soundnode.g("basefreq"); const r_amp = self.soundnode.g("gain"); const phase = self.soundnode.g("phase"); const amp = r_amp * math.sin(utility.corrected_tau * freq * current_tick - phase * utility.tau); self.soundnode.fab.add_r_amp(amp); } pub fn triangle(self: *Activity) void { const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); const freq = self.soundnode.g("basefreq"); const r_amp = self.soundnode.g("gain"); const phase = self.soundnode.g("phase"); const period = 44100 / freq; const tp = current_tick / period; const amp = r_amp * (@abs(2 * (2 * ( tp - @floor(tp + 0.5) ) )) - 1 - (phase * utility.tau)); self.soundnode.fab.add_r_amp(amp); } pub fn square(self: *Activity) void { const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); const freq = self.soundnode.g("basefreq"); const r_amp = self.soundnode.g("gain"); const phase = self.soundnode.g("phase"); const sin = math.sin(utility.corrected_tau * freq * current_tick - phase * utility.tau); if (sin > 0) { self.soundnode.fab.add_r_amp(r_amp); } else { self.soundnode.fab.add_r_amp(-r_amp); } } pub fn sawtooth(self: *Activity) void { const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); const freq = self.soundnode.g("basefreq"); const r_amp = self.soundnode.g("gain"); const phase = self.soundnode.g("phase"); const period = 44100 / freq; const tp = current_tick / period; const amp = r_amp * (2 * (tp - @floor(0.5+tp) - (phase * utility.tau))); self.soundnode.fab.add_r_amp(amp); } pub fn setskew(self: *Activity) !void { try self.soundnode.s("skew", self.operands[0]); } pub fn skewsine(self: *Activity) void { const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); const freq = self.soundnode.g("basefreq"); const r_amp = self.soundnode.g("gain"); const phase = self.soundnode.g("phase"); const skew = self.soundnode.g("skew"); if (skew == 0) { const amp = r_amp * math.sin(utility.corrected_tau * freq * current_tick - phase * utility.tau); self.soundnode.fab.add_r_amp(amp); } else if (skew > 0) { const m = (utility.corrected_tau * freq * current_tick); const sincos = skew * math.sin(m) / (1 - skew*math.cos(m)); const amp = r_amp * ((1/skew) * math.atan(sincos) - (phase * utility.tau)); self.soundnode.fab.add_r_amp(amp); } else if (skew < 0) { const m = (utility.corrected_tau * freq * current_tick); const sincos = skew * math.cos(m) / (1 + skew*math.sin(m)); const amp = r_amp * ((1/skew) * math.atan(sincos) - (phase * utility.tau)); self.soundnode.fab.add_r_amp(amp); } } pub fn slidebasefreq(self: *Activity) !void { const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); const start_tick: f64 = @floatFromInt(self.start_tick); const end_tick: f64 = @floatFromInt(self.end_tick); const startfreq = self.operands[0]; const endfreq = self.operands[1]; const freq = utility.interpolate(current_tick, start_tick, end_tick, startfreq, endfreq); try self.soundnode.s("basefreq", freq); } pub fn slidegain(self: *Activity) !void { const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); const start_tick: f64 = @floatFromInt(self.start_tick); const end_tick: f64 = @floatFromInt(self.end_tick); const startgain = self.operands[0]; const endgain = self.operands[1]; const gain = utility.interpolate(current_tick, start_tick, end_tick, startgain, endgain); try self.soundnode.s("gain", gain); } pub fn slidephase(self: *Activity) !void { const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); const start_tick: f64 = @floatFromInt(self.start_tick); const end_tick: f64 = @floatFromInt(self.end_tick); const startphase = self.operands[0]; const endphase = self.operands[1]; const phase = utility.interpolate(current_tick, start_tick, end_tick, startphase, endphase); try self.soundnode.s("phase", phase); } pub fn slideskew(self: *Activity) !void { const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); const start_tick: f64 = @floatFromInt(self.start_tick); const end_tick: f64 = @floatFromInt(self.end_tick); const startskew = self.operands[0]; const endskew = self.operands[1]; const skew = utility.interpolate(current_tick, start_tick, end_tick, startskew, endskew); try self.soundnode.s("skew", skew); } pub fn slidepos(self: *Activity) void { const current_tick: f64 = @floatFromInt(self.soundnode.fab.current_tick); const start_tick: f64 = @floatFromInt(self.start_tick); const end_tick: f64 = @floatFromInt(self.end_tick); const start_x = self.operands[0]; const start_y = self.operands[1]; const start_z = self.operands[2]; const end_x = self.operands[3]; const end_y = self.operands[4]; const end_z = self.operands[5]; const x = utility.interpolate(current_tick, start_tick, end_tick, start_x, end_x); const y = utility.interpolate(current_tick, start_tick, end_tick, start_y, end_y); const z = utility.interpolate(current_tick, start_tick, end_tick, start_z, end_z); self.soundnode.x = @as(f32, @floatCast(x)); self.soundnode.y = @as(f32, @floatCast(y)); self.soundnode.z = @as(f32, @floatCast(z)); } };