summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralaric <alaric@netmythos.org>2024-04-18 05:43:45 -0700
committeralaric <alaric@netmythos.org>2024-04-18 05:43:45 -0700
commit37e8f04af45812a987a0668e81300e39460ccf70 (patch)
treea4aa87208018901ef9b2836345dfc9452d33bf0f
parentfd2c21fe088654c5df56ca7275e7602246a56c4a (diff)
downloadtiny-synth-37e8f04af45812a987a0668e81300e39460ccf70.tar.gz
tiny-synth-37e8f04af45812a987a0668e81300e39460ccf70.zip
feat: it works more or less
m---------engine0
-rw-r--r--src/main.zig109
2 files changed, 94 insertions, 15 deletions
diff --git a/engine b/engine
-Subproject 4bc2379da46d12143ec79230b6ee815d09605bd
+Subproject 20ebeac9a56c70ffa57356ce8403caf101ee4ba
diff --git a/src/main.zig b/src/main.zig
index e8c7d8c..d7d3ee7 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -1,14 +1,91 @@
const engine = @import("engine");
+const matrix = engine.matrix;
+const Mat3 = matrix.Matrix(f32, 3, 3);
+const webgl = engine.webgl;
const input = engine.input;
+const Color = engine.Color;
+
+var prog: webgl.General2DSolidProgram = undefined;
+var vao: webgl.VertexArrayObject = undefined;
+var buf: webgl.Buffer = undefined;
pub fn init() void {
engine.print("Hello Synth!", .{});
+
+ prog = webgl.createGeneral2DSolidProgram() catch unreachable;
+ buf = webgl.Buffer.init();
+ vao = webgl.VertexArrayObject.init();
+ prog.setVertexAttribPointer(.pos, vao, buf);
+ const r_points: [4][2]f32 = .{ .{ 0, 0 }, .{ 1, 0 }, .{ 0, 1 }, .{ 1, 1 } };
+ buf.bindAndFill(.array_buffer, .vec2, &r_points, .static_draw);
+ prog.use();
+ vao.bind();
+ prog.setUniform(.view, Mat3.identity);
}
+fn drawRectangle(x: f32, y: f32, width: f32, height: f32, col: engine.Color) void {
+ const model = Mat3.translation(.{ x, y }).scaled(.{ width, height });
+ prog.setUniform(.model, model);
+ prog.setUniform(.color, .{ col.r, col.g, col.b });
+ webgl.drawArrays(.triangle_strip, 0, 4);
+}
+
+const key_is_black = [_]bool{
+ false,
+ true,
+ false,
+ true,
+ false,
+ false,
+ true,
+ false,
+ true,
+ false,
+ true,
+ false,
+};
+
+var click_location: [2]f32 = undefined;
+var is_mouse_down: bool = false;
+var was_mouse_down: bool = false;
+
pub fn update(dt: f32) void {
_ = dt;
+ const dims = webgl.getScreenSize();
engine.webgl.viewportToScreen();
- engine.webgl.clear(engine.Color.blue);
+ engine.webgl.clear(Color.rgbFromScalar(0.4));
+ prog.setUniform(.projection, matrix.projectionMatrix2D(dims[0], dims[1]));
+
+ const gap = 8.0;
+ const key_width = 60.0;
+ const key_height = 100.0;
+
+ const total_width = @as(f32, @floatFromInt(key_is_black.len)) * (key_width + gap);
+ const base_y = dims[1] * 0.5 - key_height * 0.5;
+
+ var x: f32 = dims[0] * 0.5 - total_width * 0.5;
+ for (0.., key_is_black) |i, is_black| {
+ const col: Color = if (is_black) Color.black else Color.white;
+ const y: f32 = if (is_black) base_y + key_height * 0.5 else base_y;
+ const w: f32 = key_width;
+
+ drawRectangle(x, y, w, key_height, col);
+
+ const click = is_mouse_down and !was_mouse_down;
+ const release = !is_mouse_down and was_mouse_down;
+ if (click or release) {
+ const in_rect_x = click_location[0] >= x and click_location[0] <= x + key_width;
+ const my = dims[1] - click_location[1];
+ const in_rect_y = my >= y and my <= y + key_height;
+ if (in_rect_x and in_rect_y) {
+ sine_counters[i][0] = is_mouse_down;
+ }
+ }
+
+ x += w + gap;
+ }
+
+ was_mouse_down = is_mouse_down;
}
pub fn handleInput(ev: input.InputEvent) void {
@@ -17,13 +94,15 @@ pub fn handleInput(ev: input.InputEvent) void {
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 => {},
+ .mouse => |m| {
+ is_mouse_down = m.buttons.left;
+ if (is_mouse_down and !was_mouse_down) {
+ click_location = m.pos;
+ }
+ },
}
}
@@ -58,33 +137,33 @@ const asharp4_hz = 466.1638;
const b4_hz = 493.8833;
const c5_hz = 523.251;
-const loudness = 0.5;
+const loudness = 1.0;
+const loudness_per_tone: f32 = 1.0 / @as(f32, @floatFromInt(mappings.len));
-pub fn audioCallback(info: engine.wasm.AudioInfo) void {
+pub fn audioCallback(info: *const engine.wasm.AudioInfo) void {
const math = engine.math;
+ var incr: f32 = 0.0;
+ var v: f32 = 0.0;
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]);
+ incr = mapping[1] / @as(f32, @floatFromInt(info.sample_rate));
+ v = @sin(2 * math.pi * counter[1]);
+ s.* += v * counter[2] * loudness_per_tone;
if (counter[0]) {
- s.* += v;
+ counter[2] = math.interpolateRange(math.easeInSine, counter[2], 1.0, 0.01);
} else {
- s.* += v * counter[2];
- counter[2] *= 0.999;
+ counter[2] = math.interpolateRange(math.easeInSine, counter[2], 0.0, 0.01);
}
counter[1] += incr;
if (counter[1] > 1.0) counter[1] -= 1.0;
- tone_count += 1;
}
- s.* /= tone_count;
s.* *= loudness;
}
} else {