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 Activity = @import("activity.zig").Activity; const SoundSettings = @import("settings.zig").SoundSettings; const utility = @import("utility.zig"); pub fn singleSineTick(st: *SoundSettings, freq: f64, t: u32, phase: f64) f64 { const ft: f64 = @floatFromInt(t); return math.sin(st.sine_multiplier * freq * ft - phase * utility.tau); } pub fn main() !void { const allocator = std.heap.c_allocator; // Initializing sound settings var settings: SoundSettings = SoundSettings{}; // Creating a list of soundnodes var soundnodes = ArrayList(*SoundNode).init(allocator); defer 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("test.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"); try stdout.writeInt( u32, end_tick * 2 * settings.sample_width, Endian.little, ); // Setting up tick iteration var tick: u32 = start_tick; var amp: f64 = 0; var sample: i24 = 0.0; var left: *SoundNode = undefined; var right: *SoundNode = undefined; while (tick < end_tick) { while (cursor < buf.len) { opcode = std.mem.readVarInt(u16, buf[cursor..cursor+2], .big); //print("----\nOPCODE {d} :: {any}\n", .{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; 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 nodename = try std.fmt.allocPrint(allocator, "{d}", .{src_node}); const sn = try SoundNode.create(allocator, nodename); //print("Added node {s} at tick {d}\n", .{nodename, tick}); try soundnodes.append(sn); }, 1 => { const src = soundnodes.items[src_node]; const trg = soundnodes.items[trg_node]; //print("Wired nodes at tick {d}\n", .{tick}); try trg.wire_in.append(src); }, 2 => { const src = soundnodes.items[src_node]; const trg = soundnodes.items[trg_node]; //print("Aired nodes at tick {d}\n", .{tick}); try trg.air_in.append(src); }, 3 => { end_tick = tick_end; //print("End tick set to {d}\n", .{end_tick}); }, else => { const src = soundnodes.items[src_node]; const a = try Activity.create(allocator, tick_start, tick_end, opcode, src, [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 src.activities.append(a); }, } } } //All but left and right for (soundnodes.items, 2..) |soundnode, i| { for (soundnode.activities.items, 0..) |activity, j| { if (tick <= activity.end_tick and tick >= activity.start_tick) { try activity.do(); } _ = j; } soundnode.fab.increment_tick(); _ = i; } //Left and right for (soundnodes.items, 0..2) |soundnode, i| { for (soundnode.activities.items, 0..) |activity, j| { if (tick <= activity.end_tick and tick >= activity.start_tick) { try activity.do(); } _ = j; } soundnode.fab.increment_tick(); _ = i; } //Calculating and writing output amps amp = 0; left = soundnodes.items[0]; right = soundnodes.items[1]; const current_index = left.fab.current_index; const current_fal_left = left.fab.fal_array[current_index]; for (current_fal_left.arraylist.items) |fa| { amp += fa.r_amp * singleSineTick(&settings, fa.freq, tick, fa.phase); } sample = @intFromFloat(amp * @as(f64, @floatFromInt(settings.max_amp))); try stdout.writeInt(i24, sample, Endian.little); amp = 0; const current_fal_right = right.fab.fal_array[current_index]; for (current_fal_right.arraylist.items) |fa| { amp += fa.r_amp * singleSineTick(&settings, fa.freq, tick, fa.phase); } sample = @intFromFloat(amp * @as(f64, @floatFromInt(settings.max_amp))); try stdout.writeInt(i24, sample, Endian.little); tick += 1; } try bw.flush(); } pub fn nnnmain() !void { //var gpa = std.heap.GeneralPurposeAllocator(.{}){}; //const allocator = gpa.allocator(); const allocator = std.heap.c_allocator; var settings: SoundSettings = SoundSettings{}; const start_tick: u32 = 0; const end_tick: u32 = 44100 * 10; var left: SoundNode = try SoundNode.init(allocator, "left_sink"); defer left.deinit(); left.location.x = -0.15; var right: SoundNode = try SoundNode.init(allocator, "right_sink"); defer right.deinit(); right.location.x = 0.15; var sine: SoundNode = try SoundNode.init(allocator, "sine"); defer sine.deinit(); var a = Activity{ .start_tick = 0, .end_tick = 0, .opcode = 1, .soundnode = &sine, }; a.operands[0] = 440.0; a.operands[1] = 0.5; var sine2: SoundNode = try SoundNode.init(allocator, "sine2"); defer sine2.deinit(); var a4 = Activity{ .start_tick = 0, .end_tick = 0, .opcode = 1, .soundnode = &sine, }; a4.operands[0] = 449.0; a4.operands[1] = 0.5; a4.operands[2] = 0.55; try sine.activities.append(&a); try sine.activities.append(&a4); var a2 = Activity{ .start_tick = 0, .end_tick = end_tick, .opcode = 2, .soundnode = &left, }; try left.activities.append(&a2); var a3 = Activity{ .start_tick = 0, .end_tick = end_tick, .opcode = 2, .soundnode = &right, }; try right.activities.append(&a3); var soundnodes = ArrayList(*SoundNode).init(allocator); defer soundnodes.deinit(); //Preset sink nodes try soundnodes.append(&sine); try soundnodes.append(&sine2); try soundnodes.append(&left); try soundnodes.append(&right); try left.wire_in.append(&sine); try right.wire_in.append(&sine); var tick: u32 = start_tick; //STARTING WAV 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"); try stdout.writeInt( u32, end_tick * 2 * settings.sample_width, Endian.little, ); var sample: i24 = 0.0; while (tick < end_tick) { if (tick%44100 == 0) { print("TICK {d}\n", .{tick}); } for (soundnodes.items, 0..) |soundnode, i| { for (soundnode.activities.items, 0..) |activity, j| { if (tick <= activity.end_tick and tick >= activity.start_tick) { try activity.do(); } _ = j; } soundnode.fab.increment_tick(); _ = i; } var amp: f64 = 0; const current_index = left.fab.current_index; const current_fal_left = left.fab.fal_array[current_index]; for (current_fal_left.arraylist.items) |fa| { amp += fa.r_amp * singleSineTick(&settings, fa.freq, tick, fa.phase); } sample = @intFromFloat(amp * @as(f64, @floatFromInt(settings.max_amp))); try stdout.writeInt(i24, sample, Endian.little); amp = 0; const current_fal_right = right.fab.fal_array[current_index]; for (current_fal_right.arraylist.items) |fa| { amp += fa.r_amp * singleSineTick(&settings, fa.freq, tick, fa.phase); } sample = @intFromFloat(amp * @as(f64, @floatFromInt(settings.max_amp))); try stdout.writeInt(i24, sample, Endian.little); tick += 1; } try bw.flush(); }