const std = @import("std"); const math = std.math; const print = std.debug.print; const ArrayList = std.ArrayList; const Endian = std.builtin.Endian; const SoundNode = @import("soundnode.zig").SoundNode; const Link = @import ("link.zig").Link; const Activity = @import("activity.zig").Activity; const SoundSettings = @import("settings.zig").SoundSettings; const utility = @import("utility.zig"); pub fn returnSoundNodeToList(snlist: *ArrayList(*SoundNode), sn: *SoundNode) !void { for (snlist.items, 0..) |soundnode, ind| { if (sn.uid < soundnode.uid) { try snlist.insert(ind, sn); return; } } try snlist.append(sn); return; } pub fn removeSoundNodeFromList(snlist: *ArrayList(*SoundNode), sn: *SoundNode) u8 { var found: u8 = 0; var toremove: usize = 0; for (snlist.items, 0..) |soundnode, ind| { if (sn.uid == soundnode.uid) { toremove = ind; found = 1; } } if (found == 1) { _ = snlist.orderedRemove(toremove); } return found; } pub fn reactivateSoundNode(alist: *ArrayList(*SoundNode), plist: *ArrayList(*SoundNode), sn: *SoundNode) !void { const remove_success = removeSoundNodeFromList(plist, sn); _ = remove_success; try returnSoundNodeToList(alist, sn); } pub fn deactivateSoundNode(alist: *ArrayList(*SoundNode), plist: *ArrayList(*SoundNode), sn: *SoundNode) !void { const remove_success = removeSoundNodeFromList(alist, sn); _ = remove_success; try plist.append(sn); } pub fn main() !void { const allocator = std.heap.c_allocator; // Initializing sound settings const settings: SoundSettings = SoundSettings{}; // Creating a list of soundnodes var soundnodes = ArrayList(*SoundNode).init(allocator); defer soundnodes.deinit(); // Active and passive soundnodes var a_soundnodes = ArrayList(*SoundNode).init(allocator); defer a_soundnodes.deinit(); var p_soundnodes = ArrayList(*SoundNode).init(allocator); defer p_soundnodes.deinit(); // Determining length of resulting audio in ticks const start_tick: u32 = 0; var end_tick: u32 = 44100 * 10; // Loading the input binary code, preparing registers const file = try std.fs.cwd().openFile("source.snmb", .{}); defer file.close(); const stat = try file.stat(); const buf: []u8 = try file.readToEndAlloc(allocator, stat.size); var cursor: u32 = 0; var opcode: u16 = 0; var tick_start: u32 = 0; var tick_end: u32 = 0; var src_node: u16 = 0; var trg_node: u16 = 0; var op1: f64 = 0; var op2: f64 = 0; var op3: f64 = 0; var op4: f64 = 0; var op5: f64 = 0; var op6: f64 = 0; // Preparing to write wav data to stdout const stdout_file = std.io.getStdOut().writer(); var bw = std.io.bufferedWriter(stdout_file); const stdout = bw.writer(); // Writing WAV header try stdout.writeAll("RIFF"); try stdout.writeInt( u32, 36 + (end_tick * 2 * settings.sample_width), Endian.little, ); try stdout.writeAll("WAVE"); try stdout.writeAll("fmt "); try stdout.writeInt(u32, 16, Endian.little); try stdout.writeInt(u16, 1, Endian.little); try stdout.writeInt(u16, 2, Endian.little); try stdout.writeInt(u32, settings.sample_rate, Endian.little); const block_align: u16 = @intCast(2 * settings.sample_width); try stdout.writeInt(u32, @as(u32, block_align) * settings.sample_rate, Endian.little); try stdout.writeInt(u16, block_align, Endian.little); try stdout.writeInt(u16, settings.bit_depth, Endian.little); try stdout.writeAll("data"); // Setting up tick iteration var tick: u32 = start_tick; var sample: i24 = 0.0; var left: *SoundNode = undefined; var right: *SoundNode = undefined; var nextopcodetick: u32 = 0; while (tick < end_tick) { if (tick%44100 == 0) { print("{d}-- ", .{tick/44100}); } for (a_soundnodes.items, 0..) |soundnode, i| { //print("TICK {d} I {d} ", .{tick, i}); @memset(soundnode.pins[0..32], 0); _ = i; } if (tick == nextopcodetick) { while (cursor < buf.len) { opcode = std.mem.readVarInt(u16, buf[cursor..cursor+2], .big); //print("----\nCURRENT TICK {d}\nOPCODE {d} :: {any}\n", .{tick, opcode, buf[cursor..cursor+2]}); cursor += 2; tick_start = std.mem.readVarInt(u32, buf[cursor..cursor+4], .big); //print("TICKSTART {d} :: {any}\n", .{tick_start, buf[cursor..cursor+4]}); cursor += 4; if (tick_start > tick) { cursor -= 6; nextopcodetick = tick_start; break; } else { tick_end = std.mem.readVarInt(u32, buf[cursor..cursor+4], .big); //print("TICKEND {d} :: {any}\n", .{tick_end, buf[cursor..cursor+4]}); cursor += 4; src_node = std.mem.readVarInt(u16, buf[cursor..cursor+2], .big); //print("SRCNODE {d} :: {any}\n", .{src_node, buf[cursor..cursor+2]}); cursor += 2; trg_node = std.mem.readVarInt(u16, buf[cursor..cursor+2], .big); //print("TRGNODE {d} :: {any}\n", .{trg_node, buf[cursor..cursor+2]}); cursor += 2; op1 = @bitCast(std.mem.readVarInt(u64, buf[cursor..cursor+8], .big)); //print("OP1 {d} :: {any}\n", .{op1, buf[cursor..cursor+8]}); cursor += 8; op2 = @bitCast(std.mem.readVarInt(u64, buf[cursor..cursor+8], .big)); //print("OP2 {d} :: {any}\n", .{op2, buf[cursor..cursor+8]}); cursor += 8; op3 = @bitCast(std.mem.readVarInt(u64, buf[cursor..cursor+8], .big)); //print("OP3 {d} :: {any}\n", .{op3, buf[cursor..cursor+8]}); cursor += 8; op4 = @bitCast(std.mem.readVarInt(u64, buf[cursor..cursor+8], .big)); //print("OP4 {d} :: {any}\n", .{op4, buf[cursor..cursor+8]}); cursor += 8; op5 = @bitCast(std.mem.readVarInt(u64, buf[cursor..cursor+8], .big)); //print("OP5 {d} :: {any}\n", .{op5, buf[cursor..cursor+8]}); cursor += 8; op6 = @bitCast(std.mem.readVarInt(u64, buf[cursor..cursor+8], .big)); //print("OP6 {d} :: {any}\n", .{op6, buf[cursor..cursor+8]}); cursor += 8; // Executing opcodes switch (opcode) { 0 => { const uid: usize = @as(usize, src_node); const freq_q: u8 = @truncate(trg_node); const sn = try SoundNode.create(allocator, uid, freq_q); sn.pins[32]=1; //print("Added node {s} at tick {d}\n", .{nodename, tick}); try soundnodes.append(sn); try p_soundnodes.append(sn); }, 1 => { const src = soundnodes.items[src_node]; const trg = soundnodes.items[trg_node]; //print("Wired nodes at tick {d}\n", .{tick}); const src_pin: usize = @intFromFloat(op1); const trg_pin: usize = @intFromFloat(op2); const link = try Link.create(allocator, src, trg, src_pin, trg_pin); try trg.links.append(link); }, 2 => { end_tick = tick_end; try stdout.writeInt( u32, end_tick * 2 * settings.sample_width, Endian.little); }, 3 => { const sn = soundnodes.items[src_node]; const sn_pin: usize = @intFromFloat(op1); sn.pins[sn_pin] = op2; }, 9 => { const sn = soundnodes.items[src_node]; sn.wantprint = true; }, 8 => { const src = soundnodes.items[src_node]; const trg = soundnodes.items[trg_node]; //print("Wired nodes at tick {d}\n", .{tick}); const src_pin: usize = @intFromFloat(op1); const trg_pin: usize = @intFromFloat(op2); var found: bool = false; var toremove: u64 = 0; for (trg.links.items, 0..) |link, j| { if (link.src_node == src and link.trg_node == trg and link.src_pin == src_pin and link.trg_pin == trg_pin) { toremove = j; found = true; break; } } if (found) { _ = trg.links.orderedRemove(toremove); } }, else => { const soundnode = soundnodes.items[src_node]; const a = try Activity.create(allocator, tick_start, tick_end, opcode, soundnode, [6]f64{op1, op2, op3, op4, op5, op6}); //print("Set activity {d} for node {d} s at tick {d}\n", .{opcode, src_node, tick}); try soundnode.activities.append(a); if (soundnode.activities.items.len == 1 and soundnode.active == 0) { soundnode.active = 1; try reactivateSoundNode(&a_soundnodes, &p_soundnodes, soundnode); } }, } } } } //All but left and right var iter: usize = 1; //while (iter < 0) { while (iter < a_soundnodes.items.len - 1) { iter += 1; const soundnode = a_soundnodes.items[iter]; for (soundnode.links.items, 0..) |link, j| { if (link.src_node.active == 1 or link.trg_pin == 1) { link.propagate(); } _ = j; } var toremove = ArrayList(usize).init(allocator); defer toremove.deinit(); for (soundnode.activities.items, 0..) |activity, j| { if (tick <= activity.end_tick and tick >= activity.start_tick) { try activity.do(); } else if (tick >= activity.end_tick) { try toremove.append(j); } } if (soundnode.wantprint == true) { soundnode.wantprint = false; soundnode.printState(); } var j: usize = toremove.items.len; if (j == 0) { soundnode.fab.increment_tick(); } while (j > 0) { j -= 1; const activity_ind = toremove.items[j]; _ = soundnode.activities.swapRemove(activity_ind); if (soundnode.activities.items.len == 0 and soundnode.active == 1) { soundnode.active = 0; try deactivateSoundNode(&a_soundnodes, &p_soundnodes, soundnode); //print("DEACTIVATING {d} AT TICK {d} ", .{soundnode.uid, tick}); } } } // Incrementing passive ones too for (p_soundnodes.items, 0..) |soundnode, i| { soundnode.fab.increment_tick(); _ = i; } //Left and right iter = 0; //while (iter < 0) { while (iter < 2) { const soundnode = soundnodes.items[iter]; iter += 1; for (soundnode.links.items, 0..) |link, jz| { if (link.src_node.active == 1 or link.trg_pin == 1) { link.propagate(); } _ = jz; } var toremove = ArrayList(usize).init(allocator); defer toremove.deinit(); for (soundnode.activities.items, 0..) |activity, j| { if (tick <= activity.end_tick and tick >= activity.start_tick) { try activity.do(); } else if (tick >= activity.end_tick) { try toremove.append(j); } } if (soundnode.wantprint == true) { soundnode.wantprint = false; soundnode.printState(); } var j: usize = toremove.items.len; while (j > 0) { j -= 1; const activity_ind = toremove.items[j]; _ = soundnode.activities.swapRemove(activity_ind); } } //Calculating and writing output amps left = soundnodes.items[0]; right = soundnodes.items[1]; var left_r_amp = left.pins[0]; if (left_r_amp > 1) { left_r_amp = 1; } else if (left_r_amp < -1) { left_r_amp = -1; } sample = @intFromFloat(left_r_amp * settings.max_amp_multiplier); try stdout.writeInt(i24, sample, Endian.little); var right_r_amp = right.pins[0]; if (right_r_amp > 1) { right_r_amp = 1; } else if (right_r_amp < -1) { right_r_amp = -1; } sample = @intFromFloat(right_r_amp * settings.max_amp_multiplier); try stdout.writeInt(i24, sample, Endian.little); left.fab.current_tick += 1; right.fab.current_tick += 1; tick += 1; } try bw.flush(); print("\n", .{}); }