diff options
author | alaric <alaric@netmythos.org> | 2024-04-18 04:00:17 -0700 |
---|---|---|
committer | alaric <alaric@netmythos.org> | 2024-04-18 04:00:17 -0700 |
commit | 2f1cc050e56333eaf5efe83d4bbf1fe3e8ee254f (patch) | |
tree | b38bfa46d5eb4f25bff23696942ae6185661e3d6 | |
parent | 7180e5b0907f9125b3f45c9efa75fb03e400c98b (diff) | |
download | tiny-synth-2f1cc050e56333eaf5efe83d4bbf1fe3e8ee254f.tar.gz tiny-synth-2f1cc050e56333eaf5efe83d4bbf1fe3e8ee254f.zip |
feat:scuffed piano keys
-rw-r--r-- | build.zig | 13 | ||||
-rw-r--r-- | cors_server.py | 26 | ||||
m--------- | engine | 0 | ||||
-rw-r--r-- | src/main.zig | 88 |
4 files changed, 125 insertions, 2 deletions
@@ -6,6 +6,8 @@ pub fn build(b: *std.Build) void { const wasm_target: std.Target.Query = .{ .cpu_arch = .wasm32, .os_tag = .freestanding, + // Features needed for multithreading + .cpu_features_add = std.Target.wasm.featureSet(&.{ .atomics, .bulk_memory }), }; const target = b.standardTargetOptions(.{ .whitelist = &.{wasm_target}, @@ -28,6 +30,17 @@ pub fn build(b: *std.Build) void { // WASM doesn't use a normal entry point. The HTML/JS shell code is going // to handle calling our functions. exe.entry = .disabled; + // Enabling shared memory is required for multithreading + exe.shared_memory = true; + exe.import_memory = true; + + // TODO(Alaric): Pass these params down to the engine to support into the + // JS shell or something Idk. If they change when I change the code then that + // would be bad. + const init_pages = (1049972 / 65536) + 1; + const max_pages = (91553792 / 65536) + 1; + exe.initial_memory = init_pages * 65536; + exe.max_memory = max_pages * 65536; exe.root_module.addImport("engine", engine.module("engine")); // Here we install a pre-written HTML/JS shell. After building, if you diff --git a/cors_server.py b/cors_server.py new file mode 100644 index 0000000..0221711 --- /dev/null +++ b/cors_server.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +# It's python3 -m http.server PORT for a CORS world + +from http.server import HTTPServer, SimpleHTTPRequestHandler +import sys + + +class CORSRequestHandler(SimpleHTTPRequestHandler): + + def end_headers(self): + self.send_header('Cross-Origin-Opener-Policy', 'same-origin') + self.send_header('Cross-Origin-Embedder-Policy', 'require-corp') + self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate') + return super(CORSRequestHandler, self).end_headers() + + def do_OPTIONS(self): + self.send_response(200) + self.end_headers() + +host = sys.argv[1] if len(sys.argv) > 2 else '0.0.0.0' +port = int(sys.argv[len(sys.argv)-1]) if len(sys.argv) > 1 else 8080 + +print("Listening on {}:{}".format(host, port)) +httpd = HTTPServer((host, port), CORSRequestHandler) +httpd.serve_forever() diff --git a/engine b/engine -Subproject 89ed3b75abde2bc08eb1638d5c0becc8606e6a9 +Subproject e9b2f8b62f21ee3f8887304ebdcd625753e11b0 diff --git a/src/main.zig b/src/main.zig index 11ee946..e8c7d8c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,12 +1,96 @@ const engine = @import("engine"); const input = engine.input; -pub fn init() void {} +pub fn init() void { + engine.print("Hello Synth!", .{}); +} + pub fn update(dt: f32) void { _ = dt; + engine.webgl.viewportToScreen(); + engine.webgl.clear(engine.Color.blue); } + pub fn handleInput(ev: input.InputEvent) void { - _ = ev; + switch (ev) { + .key => |k| { + for (mappings, 0..) |map, i| { + if (k.codepoint == map[0] and !k.is_repeat) { + sine_counters[i][0] = k.is_down; + if (k.is_down) { + sine_counters[i][2] = 1.0; + } + } + } + }, + else => {}, + } +} + +var sine_counters = [1]struct { bool, f32, f32 }{.{ false, 0, 0 }} ** mappings.len; + +const mappings = [_]struct { u32, f32 }{ + .{ 'a', c4_hz }, + .{ 'w', csharp4_hz }, + .{ 's', d4_hz }, + .{ 'e', dsharp4_hz }, + .{ 'd', e4_hz }, + .{ 'f', f4_hz }, + .{ 't', fsharp4_hz }, + .{ 'g', g4_hz }, + .{ 'y', gsharp4_hz }, + .{ 'h', a4_hz }, + .{ 'u', asharp4_hz }, + .{ 'j', b4_hz }, +}; + +const c4_hz = 261.626; +const csharp4_hz = 277.1826; +const d4_hz = 293.6648; +const dsharp4_hz = 311.1270; +const e4_hz = 329.6276; +const f4_hz = 349.2282; +const fsharp4_hz = 369.9944; +const g4_hz = 391.9954; +const gsharp4_hz = 415.3047; +const a4_hz = 440.0000; +const asharp4_hz = 466.1638; +const b4_hz = 493.8833; + +const c5_hz = 523.251; +const loudness = 0.5; + +pub fn audioCallback(info: engine.wasm.AudioInfo) void { + const math = engine.math; + + for (info.write_area, 0..) |channel, channel_i| { + if (channel_i == 0) { + for (channel) |*s| { + s.* = 0; + var tone_count: f32 = 0; + for (&sine_counters, mappings) |*counter, mapping| { + if (!counter[0] and counter[2] < 0.0001) continue; + const incr = mapping[1] / @as(f32, @floatFromInt(info.sample_rate)); + const v = @sin(2 * math.pi * counter[1]); + + if (counter[0]) { + s.* += v; + } else { + s.* += v * counter[2]; + counter[2] *= 0.999; + } + + counter[1] += incr; + if (counter[1] > 1.0) counter[1] -= 1.0; + tone_count += 1; + } + s.* /= tone_count; + s.* *= loudness; + } + } else { + @memcpy(channel, info.write_area[channel_i - 1]); + } + } } comptime { |