remove unmaintained WASM support
Same reasoning as outlined in #1254 > nobody is interested in actively maintaining or contributing to that today. Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
984d4de3bd
commit
51e996db72
10 changed files with 6 additions and 978 deletions
5
.github/workflows/m1_ci.yml
vendored
5
.github/workflows/m1_ci.yml
vendored
|
|
@ -26,5 +26,6 @@ jobs:
|
||||||
run: zig build test
|
run: zig build test
|
||||||
- name: build
|
- name: build
|
||||||
run: zig build
|
run: zig build
|
||||||
- name: build (WASM)
|
# TODO: get WASM builds working
|
||||||
run: zig build -Dtarget=wasm32-freestanding-none
|
# - name: build (WASM)
|
||||||
|
# run: zig build -Dtarget=wasm32-freestanding-none
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,6 @@ fn buildExamples(
|
||||||
core: bool = false,
|
core: bool = false,
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
deps: []const Dependency = &.{},
|
deps: []const Dependency = &.{},
|
||||||
wasm: bool = false,
|
|
||||||
has_assets: bool = false,
|
has_assets: bool = false,
|
||||||
}{
|
}{
|
||||||
// Mach core examples
|
// Mach core examples
|
||||||
|
|
@ -388,7 +387,6 @@ fn buildExamples(
|
||||||
.{ .name = "sprite", .deps = &.{ .zigimg, .assets } },
|
.{ .name = "sprite", .deps = &.{ .zigimg, .assets } },
|
||||||
.{ .name = "text", .deps = &.{.assets} },
|
.{ .name = "text", .deps = &.{.assets} },
|
||||||
}) |example| {
|
}) |example| {
|
||||||
if (target.result.cpu.arch == .wasm32 and !example.wasm) continue;
|
|
||||||
const exe = b.addExecutable(.{
|
const exe = b.addExecutable(.{
|
||||||
.name = if (example.core) b.fmt("core-{s}", .{example.name}) else example.name,
|
.name = if (example.core) b.fmt("core-{s}", .{example.name}) else example.name,
|
||||||
.root_source_file = if (example.core)
|
.root_source_file = if (example.core)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const WasmTimer = @import("wasm/Timer.zig");
|
const PlatformTimer = if (builtin.cpu.arch == .wasm32) @panic("TODO: support WASM") else NativeTimer;
|
||||||
const PlatformTimer = if (builtin.cpu.arch == .wasm32) WasmTimer else NativeTimer;
|
|
||||||
|
|
||||||
const Timer = @This();
|
const Timer = @This();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const js = @import("js.zig");
|
|
||||||
|
|
||||||
pub const Timer = @This();
|
|
||||||
|
|
||||||
initial: f64 = undefined,
|
|
||||||
|
|
||||||
pub fn start() !Timer {
|
|
||||||
return Timer{ .initial = js.machPerfNow() };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(timer: *Timer) u64 {
|
|
||||||
return @intFromFloat((js.machPerfNow() - timer.initial) * std.time.ns_per_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(timer: *Timer) void {
|
|
||||||
timer.initial = js.machPerfNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lap(timer: *Timer) u64 {
|
|
||||||
const now = js.machPerfNow();
|
|
||||||
const initial = timer.initial;
|
|
||||||
timer.initial = now;
|
|
||||||
return @as(u64, @intFromFloat(now - initial)) * std.time.ns_per_ms;
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
// Check that the user's app matches the required interface.
|
|
||||||
comptime {
|
|
||||||
if (!@import("builtin").is_test) @import("mach").core.AppInterface(@import("app"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward "app" declarations into our namespace, such that @import("root").foo works as expected.
|
|
||||||
pub usingnamespace @import("app");
|
|
||||||
const App = @import("app").App;
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
const mach = @import("mach");
|
|
||||||
const core = mach.core;
|
|
||||||
const gpu = mach.gpu;
|
|
||||||
|
|
||||||
var app: App = undefined;
|
|
||||||
export fn wasmInit() void {
|
|
||||||
App.init(&app) catch |err| @panic(@errorName(err));
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn wasmUpdate() bool {
|
|
||||||
if (core.update(&app) catch |err| @panic(@errorName(err))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn wasmDeinit() void {
|
|
||||||
app.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define std_options.logFn if the user did not in their "app" main.zig
|
|
||||||
pub usingnamespace if (@hasDecl(App, "std_options")) struct {} else struct {
|
|
||||||
pub const std_options = std.Options{
|
|
||||||
.logFn = core.defaultLog,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define panic() if the user did not in their "app" main.zig
|
|
||||||
pub usingnamespace if (@hasDecl(App, "panic")) struct {} else struct {
|
|
||||||
pub const panic = core.defaultPanic;
|
|
||||||
};
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
pub const CanvasId = u32;
|
|
||||||
|
|
||||||
pub extern "mach" fn machLogWrite(str: [*]const u8, len: u32) void;
|
|
||||||
pub extern "mach" fn machLogFlush() void;
|
|
||||||
pub extern "mach" fn machPanic(str: [*]const u8, len: u32) void;
|
|
||||||
|
|
||||||
pub extern "mach" fn machCanvasInit(selector_id: *u8) CanvasId;
|
|
||||||
pub extern "mach" fn machCanvasDeinit(canvas: CanvasId) void;
|
|
||||||
pub extern "mach" fn machCanvasFramebufferWidth(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machCanvasFramebufferHeight(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machCanvasSetTitle(canvas: CanvasId, title: [*]const u8, len: u32) void;
|
|
||||||
pub extern "mach" fn machCanvasSetDisplayMode(canvas: CanvasId, mode: u32) void;
|
|
||||||
pub extern "mach" fn machCanvasDisplayMode(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machCanvasSetBorder(canvas: CanvasId, value: bool) void;
|
|
||||||
pub extern "mach" fn machCanvasBorder(canvas: CanvasId) bool;
|
|
||||||
pub extern "mach" fn machCanvasSetHeadless(canvas: CanvasId, value: bool) void;
|
|
||||||
pub extern "mach" fn machCanvasHeadless(canvas: CanvasId) bool;
|
|
||||||
pub extern "mach" fn machCanvasSetVsync(canvas: CanvasId, mode: u32) void;
|
|
||||||
pub extern "mach" fn machCanvasVsync(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machCanvasSetSize(canvas: CanvasId, width: u32, height: u32) void;
|
|
||||||
pub extern "mach" fn machCanvasWidth(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machCanvasHeight(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machCanvasSetSizeLimit(canvas: CanvasId, min_width: i32, min_height: i32, max_width: i32, max_height: i32) void;
|
|
||||||
pub extern "mach" fn machCanvasMinWidth(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machCanvasMinHeight(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machCanvasMaxWidth(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machCanvasMaxHeight(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machSetCursorMode(canvas: CanvasId, mode: u32) void;
|
|
||||||
pub extern "mach" fn machCursorMode(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machSetCursorShape(canvas: CanvasId, shape: u32) void;
|
|
||||||
pub extern "mach" fn machCursorShape(canvas: CanvasId) u32;
|
|
||||||
pub extern "mach" fn machJoystickName(idx: u8, dest: [*:0]u8, dest_len: usize) void;
|
|
||||||
pub extern "mach" fn machJoystickButtons(idx: u8, dest: [*]u8, dest_len: usize) void;
|
|
||||||
pub extern "mach" fn machJoystickAxes(idx: u8, dest: [*]f32, dest_len: usize) void;
|
|
||||||
|
|
||||||
pub extern "mach" fn machShouldClose() bool;
|
|
||||||
pub extern "mach" fn machHasEvent() bool;
|
|
||||||
pub extern "mach" fn machEventShift() i32;
|
|
||||||
pub extern "mach" fn machEventShiftFloat() f64;
|
|
||||||
pub extern "mach" fn machChangeShift() u32;
|
|
||||||
|
|
||||||
pub extern "mach" fn machPerfNow() f64;
|
|
||||||
|
|
@ -1,569 +0,0 @@
|
||||||
const text_decoder = new TextDecoder();
|
|
||||||
const text_encoder = new TextEncoder();
|
|
||||||
|
|
||||||
const mach = {
|
|
||||||
canvases: [],
|
|
||||||
wasm: undefined,
|
|
||||||
observer: undefined,
|
|
||||||
events: [],
|
|
||||||
changes: [],
|
|
||||||
log_buf: "",
|
|
||||||
|
|
||||||
init(wasm) {
|
|
||||||
mach.wasm = wasm;
|
|
||||||
mach.observer = new MutationObserver((mutables) => {
|
|
||||||
mutables.forEach((mutable) => {
|
|
||||||
mach.canvases.forEach((canvas) => {
|
|
||||||
if (mutable.target == canvas) {
|
|
||||||
if (mutable.attributeName === "width" ||
|
|
||||||
mutable.attributeName === "height" ||
|
|
||||||
mutable.attributeName === "style") {
|
|
||||||
mutable.target.dispatchEvent(new Event("mach-canvas-resize"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
getString(str, len) {
|
|
||||||
const memory = mach.wasm.exports.memory.buffer;
|
|
||||||
return text_decoder.decode(new Uint8Array(memory, str, len));
|
|
||||||
},
|
|
||||||
|
|
||||||
setString(str, buf) {
|
|
||||||
const memory = mach.wasm.exports.memory.buffer;
|
|
||||||
const strbuf = text_encoder.encode(str);
|
|
||||||
const outbuf = new Uint8Array(memory, buf, strbuf.length);
|
|
||||||
for (let i = 0; i < strbuf.length; i += 1) {
|
|
||||||
outbuf[i] = strbuf[i];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
machLogWrite(str, len) {
|
|
||||||
mach.log_buf += mach.getString(str, len);
|
|
||||||
},
|
|
||||||
|
|
||||||
machLogFlush() {
|
|
||||||
console.log(mach.log_buf);
|
|
||||||
mach.log_buf = "";
|
|
||||||
},
|
|
||||||
|
|
||||||
machPanic(str, len) {
|
|
||||||
throw Error(mach.getString(str, len));
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasInit(id) {
|
|
||||||
let canvas = document.createElement("canvas");
|
|
||||||
canvas.id = "#mach-canvas-" + mach.canvases.length;
|
|
||||||
canvas.style.border = "1px solid";
|
|
||||||
canvas.style.position = "absolute";
|
|
||||||
canvas.style.display = "block";
|
|
||||||
canvas.tabIndex = 1;
|
|
||||||
|
|
||||||
mach.observer.observe(canvas, { attributes: true });
|
|
||||||
|
|
||||||
mach.setString(canvas.id, id);
|
|
||||||
|
|
||||||
canvas.addEventListener("contextmenu", (ev) => ev.preventDefault());
|
|
||||||
|
|
||||||
canvas.addEventListener("keydown", (ev) => {
|
|
||||||
if (ev.repeat) {
|
|
||||||
mach.events.push(...[EventCode.key_repeat, convertKeyCode(ev.code)]);
|
|
||||||
} else {
|
|
||||||
mach.events.push(...[EventCode.key_press, convertKeyCode(ev.code)]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("keyup", (ev) => {
|
|
||||||
mach.events.push(...[EventCode.key_release, convertKeyCode(ev.code)]);
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("mousemove", (ev) => {
|
|
||||||
mach.events.push(...[EventCode.mouse_motion, ev.clientX, ev.clientY]);
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("mousedown", (ev) => {
|
|
||||||
mach.events.push(...[EventCode.mouse_press, ev.button]);
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("mouseup", (ev) => {
|
|
||||||
mach.events.push(...[EventCode.mouse_release, ev.button]);
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("wheel", (ev) => {
|
|
||||||
mach.events.push(...[EventCode.mouse_scroll, ev.deltaX, ev.deltaY]);
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("gamepadconnected", (ev) => {
|
|
||||||
mach.events.push(...[
|
|
||||||
EventCode.joystick_connected, ev.gamepad.index,
|
|
||||||
ev.gamepad.buttons.length, ev.gamepad.axes.length,
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("gamepaddisconnected", (ev) => {
|
|
||||||
mach.events.push(...[EventCode.joystick_disconnected, ev.gamepad.index]);
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("mach-canvas-resize", (ev) => {
|
|
||||||
const cv_index = mach.canvases.findIndex((el) => el === ev.currentTarget);
|
|
||||||
const cv = mach.canvases[cv_index];
|
|
||||||
mach.events.push(...[EventCode.framebuffer_resize, cv.width, cv.height, window.devicePixelRatio]);
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("focus", (ev) => {
|
|
||||||
mach.events.push(...[EventCode.focus_gained]);
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("blur", (ev) => {
|
|
||||||
mach.events.push(...[EventCode.focus_lost]);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.body.appendChild(canvas);
|
|
||||||
return mach.canvases.push(canvas) - 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasDeinit(canvas) {
|
|
||||||
if (mach.canvases[canvas] != undefined) {
|
|
||||||
mach.canvases.splice(canvas, 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasFramebufferWidth(canvas) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
return cv.width;
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasFramebufferHeight(canvas) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
return cv.height;
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasSetTitle(canvas, title, len) {
|
|
||||||
// TODO(wasm)
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasSetDisplayMode(canvas, mode) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
switch (mode) {
|
|
||||||
case DisplayMode.windowed:
|
|
||||||
document.exitFullscreen();
|
|
||||||
break;
|
|
||||||
case DisplayMode.fullscreen:
|
|
||||||
cv.requestFullscreen();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasDisplayMode(canvas) {
|
|
||||||
if (mach.canvases[canvas].fullscreenElement == null) {
|
|
||||||
return DisplayMode.windowed;
|
|
||||||
} else {
|
|
||||||
return DisplayMode.fullscreen;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasSetBorder(canvas, value) {
|
|
||||||
// TODO(wasm)
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasBorder(canvas) {
|
|
||||||
// TODO(wasm)
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasSetHeadless(canvas, value) {
|
|
||||||
// TODO(wasm)
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasHeadless(canvas) {
|
|
||||||
// TODO(wasm)
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasSetVSync(canvas, mode) {
|
|
||||||
// TODO(wasm)
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasVSync(canvas) {
|
|
||||||
// TODO(wasm)
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasSetSize(canvas, width, height) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
if (width > 0 && height > 0) {
|
|
||||||
cv.style.width = width + "px";
|
|
||||||
cv.style.height = height + "px";
|
|
||||||
cv.width = Math.floor(width * window.devicePixelRatio);
|
|
||||||
cv.height = Math.floor(height * window.devicePixelRatio);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasWidth(canvas) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
return cv.width / window.devicePixelRatio;
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasHeight(canvas) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
return cv.height / window.devicePixelRatio;
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasSetSizeLimit(canvas, min_width, min_height, max_width, max_height) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
if (min_width == -1) {
|
|
||||||
cv.style.minWidth = "inherit"
|
|
||||||
} else {
|
|
||||||
cv.style.minWidth = min_width + "px";
|
|
||||||
}
|
|
||||||
if (min_width == -1) {
|
|
||||||
cv.style.minHeight = "inherit"
|
|
||||||
} else {
|
|
||||||
cv.style.minHeight = min_height + "px";
|
|
||||||
}
|
|
||||||
if (min_width == -1) {
|
|
||||||
cv.style.maxWidth = "inherit"
|
|
||||||
} else {
|
|
||||||
cv.style.maxWidth = max_width + "px";
|
|
||||||
}
|
|
||||||
if (min_width == -1) {
|
|
||||||
cv.style.maxHeight = "inherit"
|
|
||||||
} else {
|
|
||||||
cv.style.maxHeight = max_height + "px";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasMinWidth(canvas) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
return cv.style.minWidth;
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasMinHeight(canvas) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
return cv.style.minHeight;
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasMaxWidth(canvas) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
return cv.style.maxWidth;
|
|
||||||
},
|
|
||||||
|
|
||||||
machCanvasMaxHeight(canvas) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
return cv.style.maxHeight;
|
|
||||||
},
|
|
||||||
|
|
||||||
machSetCursorMode(canvas, mode) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
switch (mode) {
|
|
||||||
case CursorMode.normal:
|
|
||||||
cv.style.cursor = 'default';
|
|
||||||
break;
|
|
||||||
case CursorMode.hidden:
|
|
||||||
cv.style.cursor = 'none';
|
|
||||||
break;
|
|
||||||
case CursorMode.hidden:
|
|
||||||
cv.style.cursor = 'none';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
machCursorMode(canvas) {
|
|
||||||
switch (mach.canvases[canvas].style.cursor) {
|
|
||||||
case 'none': return CursorMode.hidden;
|
|
||||||
default: return CursorMode.normal;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
machSetCursorShape(canvas, shape) {
|
|
||||||
const cv = mach.canvases[canvas];
|
|
||||||
switch (shape) {
|
|
||||||
case CursorShape.arrow:
|
|
||||||
cv.style.cursor = 'default';
|
|
||||||
break;
|
|
||||||
case CursorShape.ibeam:
|
|
||||||
cv.style.cursor = 'text';
|
|
||||||
break;
|
|
||||||
case CursorShape.crosshair:
|
|
||||||
cv.style.cursor = 'crosshair';
|
|
||||||
break;
|
|
||||||
case CursorShape.pointing_hand:
|
|
||||||
cv.style.cursor = 'pointer';
|
|
||||||
break;
|
|
||||||
case CursorShape.resize_ew:
|
|
||||||
cv.style.cursor = 'ew-resize';
|
|
||||||
break;
|
|
||||||
case CursorShape.resize_ns:
|
|
||||||
cv.style.cursor = 'ns-resize';
|
|
||||||
break;
|
|
||||||
case CursorShape.resize_nwse:
|
|
||||||
cv.style.cursor = 'nwse-resize';
|
|
||||||
break;
|
|
||||||
case CursorShape.resize_nesw:
|
|
||||||
cv.style.cursor = 'nesw-resize';
|
|
||||||
break;
|
|
||||||
case CursorShape.resize_all:
|
|
||||||
cv.style.cursor = 'move';
|
|
||||||
break;
|
|
||||||
case CursorShape.not_allowed:
|
|
||||||
cv.style.cursor = 'not-allowed';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
machCursorShape(canvas) {
|
|
||||||
switch (mach.canvases[canvas].style.cursor) {
|
|
||||||
case 'default': return CursorShape.arrow;
|
|
||||||
case 'text': return CursorShape.ibeam;
|
|
||||||
case 'crosshair': return CursorShape.crosshair;
|
|
||||||
case 'pointer': return CursorShape.pointing_hand;
|
|
||||||
case 'ew-resize': return CursorShape.resize_ew;
|
|
||||||
case 'ns-resize': return CursorShape.resize_ns;
|
|
||||||
case 'nwse-resize': return CursorShape.resize_nwse;
|
|
||||||
case 'nesw-resize': return CursorShape.resize_nesw;
|
|
||||||
case 'move': return CursorShape.resize_all;
|
|
||||||
case 'not-allowed': return CursorShape.not_allowed;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
machJoystickName(idx, dest, dest_len) {
|
|
||||||
const gamepads = navigator.getGamepads();
|
|
||||||
|
|
||||||
if( idx < 0 || idx > gamepads.length )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( gamepads[idx] === null || gamepads[idx] === undefined )
|
|
||||||
return;
|
|
||||||
|
|
||||||
const name = gamepads[idx].id;
|
|
||||||
const strbuf = text_encoder.encode(name).slice(0, dest_len);
|
|
||||||
const dstbuf = new Uint8Array(mach.wasm.exports.memory.buffer, dest, dest_len+1);
|
|
||||||
dstbuf.set(strbuf);
|
|
||||||
dstbuf[dest_len] = 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
machJoystickButtons(idx, dest, dest_len) {
|
|
||||||
const gamepads = navigator.getGamepads();
|
|
||||||
|
|
||||||
if( idx < 0 || idx > gamepads.length )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( gamepads[idx] === null || gamepads[idx] === undefined )
|
|
||||||
return;
|
|
||||||
|
|
||||||
const buttons = gamepads[idx].buttons.map(x => x.pressed ? 1 : 0);
|
|
||||||
const count = Math.min(dest_len, buttons.length);
|
|
||||||
const dstbuf = new Uint8Array(mach.wasm.exports.memory.buffer, dest, count);
|
|
||||||
dstbuf.set(buttons);
|
|
||||||
},
|
|
||||||
|
|
||||||
machJoystickAxes(idx, dest, dest_len) {
|
|
||||||
const gamepads = navigator.getGamepads();
|
|
||||||
|
|
||||||
if( idx < 0 || idx > gamepads.length )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( gamepads[idx] === null || gamepads[idx] === undefined )
|
|
||||||
return;
|
|
||||||
|
|
||||||
const axes = gamepads[idx].axes;
|
|
||||||
const count = Math.min(dest_len, axes.length);
|
|
||||||
const dstbuf = new Float32Array(mach.wasm.exports.memory.buffer, dest, count);
|
|
||||||
dstbuf.set(axes);
|
|
||||||
},
|
|
||||||
|
|
||||||
machHasEvent() {
|
|
||||||
return mach.events.length > 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
machEventShift() {
|
|
||||||
if (mach.machHasEvent())
|
|
||||||
return mach.events.shift();
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
machEventShiftFloat() {
|
|
||||||
return mach.machEventShift();
|
|
||||||
},
|
|
||||||
|
|
||||||
machPerfNow() {
|
|
||||||
return performance.now();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function convertKeyCode(code) {
|
|
||||||
const k = Key[code];
|
|
||||||
if (k != undefined)
|
|
||||||
return k;
|
|
||||||
return 118; // Unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
const EventCode = {
|
|
||||||
key_press: 0,
|
|
||||||
key_repeat: 1,
|
|
||||||
key_release: 2,
|
|
||||||
char_input: 3,
|
|
||||||
mouse_motion: 4,
|
|
||||||
mouse_press: 5,
|
|
||||||
mouse_release: 6,
|
|
||||||
mouse_scroll: 7,
|
|
||||||
joystick_connected: 8,
|
|
||||||
joystick_disconnected: 9,
|
|
||||||
framebuffer_resize: 10,
|
|
||||||
focus_gained: 11,
|
|
||||||
focus_lost: 12,
|
|
||||||
close: 13,
|
|
||||||
};
|
|
||||||
|
|
||||||
const Key = {
|
|
||||||
KeyA: 0,
|
|
||||||
KeyB: 1,
|
|
||||||
KeyC: 2,
|
|
||||||
KeyD: 3,
|
|
||||||
KeyE: 4,
|
|
||||||
KeyF: 5,
|
|
||||||
KeyG: 6,
|
|
||||||
KeyH: 7,
|
|
||||||
KeyI: 8,
|
|
||||||
KeyJ: 9,
|
|
||||||
KeyK: 10,
|
|
||||||
KeyL: 11,
|
|
||||||
KeyM: 12,
|
|
||||||
KeyN: 13,
|
|
||||||
KeyO: 14,
|
|
||||||
KeyP: 15,
|
|
||||||
KeyQ: 16,
|
|
||||||
KeyR: 17,
|
|
||||||
KeyS: 18,
|
|
||||||
KeyT: 19,
|
|
||||||
KeyU: 20,
|
|
||||||
KeyV: 21,
|
|
||||||
KeyW: 22,
|
|
||||||
KeyX: 23,
|
|
||||||
KeyY: 24,
|
|
||||||
KeyZ: 25,
|
|
||||||
|
|
||||||
Digit0: 26,
|
|
||||||
Digit1: 27,
|
|
||||||
Digit2: 28,
|
|
||||||
Digit3: 29,
|
|
||||||
Digit4: 30,
|
|
||||||
Digit5: 31,
|
|
||||||
Digit6: 32,
|
|
||||||
Digit7: 33,
|
|
||||||
Digit8: 34,
|
|
||||||
Digit9: 35,
|
|
||||||
|
|
||||||
F1: 36,
|
|
||||||
F2: 37,
|
|
||||||
F3: 38,
|
|
||||||
F4: 39,
|
|
||||||
F5: 40,
|
|
||||||
F6: 41,
|
|
||||||
F7: 42,
|
|
||||||
F8: 43,
|
|
||||||
F9: 44,
|
|
||||||
F10: 45,
|
|
||||||
F11: 46,
|
|
||||||
F12: 47,
|
|
||||||
F13: 48,
|
|
||||||
F14: 49,
|
|
||||||
F15: 50,
|
|
||||||
F16: 51,
|
|
||||||
F17: 52,
|
|
||||||
F18: 53,
|
|
||||||
F19: 54,
|
|
||||||
F20: 55,
|
|
||||||
F21: 56,
|
|
||||||
F22: 57,
|
|
||||||
F23: 58,
|
|
||||||
F24: 59,
|
|
||||||
F25: 60,
|
|
||||||
|
|
||||||
NumpadDivide: 61,
|
|
||||||
NumpadMultiply: 62,
|
|
||||||
NumpadSubtract: 63,
|
|
||||||
NumpadAdd: 64,
|
|
||||||
Numpad0: 65,
|
|
||||||
Numpad1: 66,
|
|
||||||
Numpad2: 67,
|
|
||||||
Numpad3: 68,
|
|
||||||
Numpad4: 69,
|
|
||||||
Numpad5: 70,
|
|
||||||
Numpad6: 71,
|
|
||||||
Numpad7: 72,
|
|
||||||
Numpad8: 73,
|
|
||||||
Numpad9: 74,
|
|
||||||
NumpadDecimal: 75,
|
|
||||||
NumpadEqual: 76,
|
|
||||||
NumpadEnter: 77,
|
|
||||||
|
|
||||||
Enter: 78,
|
|
||||||
Escape: 79,
|
|
||||||
Tab: 80,
|
|
||||||
ShiftLeft: 81,
|
|
||||||
ShiftRight: 82,
|
|
||||||
ControlLeft: 83,
|
|
||||||
ControlRight: 84,
|
|
||||||
AltLeft: 85,
|
|
||||||
AltRight: 86,
|
|
||||||
OSLeft: 87,
|
|
||||||
MetaLeft: 87,
|
|
||||||
OSRight: 88,
|
|
||||||
MetaRight: 88,
|
|
||||||
ContextMenu: 89,
|
|
||||||
NumLock: 90,
|
|
||||||
CapsLock: 91,
|
|
||||||
PrintScreen: 92,
|
|
||||||
ScrollLock: 93,
|
|
||||||
Pause: 94,
|
|
||||||
Delete: 95,
|
|
||||||
Home: 96,
|
|
||||||
End: 97,
|
|
||||||
PageUp: 98,
|
|
||||||
PageDown: 99,
|
|
||||||
Insert: 100,
|
|
||||||
ArrowLeft: 101,
|
|
||||||
ArrowRight: 102,
|
|
||||||
ArrowUp: 103,
|
|
||||||
ArrowDown: 104,
|
|
||||||
Backspace: 105,
|
|
||||||
Space: 106,
|
|
||||||
Minus: 107,
|
|
||||||
Equal: 108,
|
|
||||||
BracketLeft: 109,
|
|
||||||
BracketRight: 110,
|
|
||||||
Backslash: 111,
|
|
||||||
Semicolon: 112,
|
|
||||||
Quote: 113,
|
|
||||||
Comma: 114,
|
|
||||||
Period: 115,
|
|
||||||
Slash: 116,
|
|
||||||
Backquote: 117,
|
|
||||||
};
|
|
||||||
|
|
||||||
const DisplayMode = {
|
|
||||||
windowed: 0,
|
|
||||||
fullscreen: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
const CursorMode = {
|
|
||||||
normal: 0,
|
|
||||||
hidden: 1,
|
|
||||||
disabled: 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
const CursorShape = {
|
|
||||||
arrow: 0,
|
|
||||||
ibeam: 1,
|
|
||||||
crosshair: 2,
|
|
||||||
pointing_hand: 3,
|
|
||||||
resize_ew: 4,
|
|
||||||
resize_ns: 5,
|
|
||||||
resize_nwse: 6,
|
|
||||||
resize_nesw: 7,
|
|
||||||
resize_all: 8,
|
|
||||||
not_allowed: 9,
|
|
||||||
};
|
|
||||||
|
|
||||||
export { mach };
|
|
||||||
|
|
@ -5,14 +5,9 @@ const math = mach.math;
|
||||||
const vec2 = math.vec2;
|
const vec2 = math.vec2;
|
||||||
const Vec2 = math.Vec2;
|
const Vec2 = math.Vec2;
|
||||||
|
|
||||||
pub const Font = FontInterface(if (@import("builtin").cpu.arch == .wasm32) {
|
pub const Font = FontInterface(if (@import("builtin").cpu.arch == .wasm32) @panic("TODO: implement wasm/Font.zig") else @import("native/Font.zig"));
|
||||||
@panic("TODO: implement wasm/Font.zig");
|
|
||||||
} else @import("native/Font.zig"));
|
|
||||||
|
|
||||||
pub const TextRun = TextRunInterface(if (@import("builtin").cpu.arch == .wasm32)
|
pub const TextRun = TextRunInterface(if (@import("builtin").cpu.arch == .wasm32) @panic("TODO: implement wasm/TextRun.zig") else @import("native/TextRun.zig"));
|
||||||
{
|
|
||||||
@panic("TODO: implement wasm/TextRun.zig");
|
|
||||||
} else @import("native/TextRun.zig"));
|
|
||||||
|
|
||||||
fn FontInterface(comptime T: type) type {
|
fn FontInterface(comptime T: type) type {
|
||||||
assertDecl(T, "initBytes", fn (font_bytes: []const u8) anyerror!T);
|
assertDecl(T, "initBytes", fn (font_bytes: []const u8) anyerror!T);
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,6 @@ pub const Context = switch (builtin.os.tag) {
|
||||||
dummy: *@import("dummy.zig").Context,
|
dummy: *@import("dummy.zig").Context,
|
||||||
},
|
},
|
||||||
.freestanding => switch (builtin.cpu.arch) {
|
.freestanding => switch (builtin.cpu.arch) {
|
||||||
.wasm32 => union(enum) {
|
|
||||||
webaudio: *@import("webaudio.zig").Context,
|
|
||||||
dummy: *@import("dummy.zig").Context,
|
|
||||||
},
|
|
||||||
else => union(enum) {
|
else => union(enum) {
|
||||||
dummy: *@import("dummy.zig").Context,
|
dummy: *@import("dummy.zig").Context,
|
||||||
},
|
},
|
||||||
|
|
@ -60,10 +56,6 @@ pub const Player = switch (builtin.os.tag) {
|
||||||
dummy: *@import("dummy.zig").Player,
|
dummy: *@import("dummy.zig").Player,
|
||||||
},
|
},
|
||||||
.freestanding => switch (builtin.cpu.arch) {
|
.freestanding => switch (builtin.cpu.arch) {
|
||||||
.wasm32 => union(enum) {
|
|
||||||
webaudio: *@import("webaudio.zig").Player,
|
|
||||||
dummy: *@import("dummy.zig").Player,
|
|
||||||
},
|
|
||||||
else => union(enum) {
|
else => union(enum) {
|
||||||
dummy: *@import("dummy.zig").Player,
|
dummy: *@import("dummy.zig").Player,
|
||||||
},
|
},
|
||||||
|
|
@ -94,10 +86,6 @@ pub const Recorder = switch (builtin.os.tag) {
|
||||||
dummy: *@import("dummy.zig").Recorder,
|
dummy: *@import("dummy.zig").Recorder,
|
||||||
},
|
},
|
||||||
.freestanding => switch (builtin.cpu.arch) {
|
.freestanding => switch (builtin.cpu.arch) {
|
||||||
.wasm32 => union(enum) {
|
|
||||||
webaudio: *@import("webaudio.zig").Recorder,
|
|
||||||
dummy: *@import("dummy.zig").Recorder,
|
|
||||||
},
|
|
||||||
else => union(enum) {
|
else => union(enum) {
|
||||||
dummy: *@import("dummy.zig").Recorder,
|
dummy: *@import("dummy.zig").Recorder,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,275 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const js = @import("sysjs");
|
|
||||||
const main = @import("main.zig");
|
|
||||||
const backends = @import("backends.zig");
|
|
||||||
const util = @import("util.zig");
|
|
||||||
|
|
||||||
const default_sample_rate = 44_100; // Hz
|
|
||||||
const channel_size = 1024;
|
|
||||||
const channel_size_bytes = channel_size * @sizeOf(f32);
|
|
||||||
|
|
||||||
const default_playback = main.Device{
|
|
||||||
.id = "default-playback",
|
|
||||||
.name = "Default Device",
|
|
||||||
.mode = .playback,
|
|
||||||
.channels = undefined,
|
|
||||||
.formats = &.{.f32},
|
|
||||||
.sample_rate = .{
|
|
||||||
.min = 8_000,
|
|
||||||
.max = 96_000,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Context = struct {
|
|
||||||
allocator: std.mem.Allocator,
|
|
||||||
devices_info: util.DevicesInfo,
|
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, options: main.Context.Options) !backends.Context {
|
|
||||||
_ = options;
|
|
||||||
|
|
||||||
const audio_context = js.global().get("AudioContext");
|
|
||||||
if (audio_context.is(.undefined))
|
|
||||||
return error.ConnectionRefused;
|
|
||||||
|
|
||||||
const ctx = try allocator.create(Context);
|
|
||||||
errdefer allocator.destroy(ctx);
|
|
||||||
ctx.* = .{
|
|
||||||
.allocator = allocator,
|
|
||||||
.devices_info = util.DevicesInfo.init(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return .{ .webaudio = ctx };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(ctx: *Context) void {
|
|
||||||
for (ctx.devices_info.list.items) |d|
|
|
||||||
freeDevice(ctx.allocator, d);
|
|
||||||
ctx.devices_info.list.deinit(ctx.allocator);
|
|
||||||
ctx.allocator.destroy(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn refresh(ctx: *Context) !void {
|
|
||||||
for (ctx.devices_info.list.items) |d|
|
|
||||||
freeDevice(ctx.allocator, d);
|
|
||||||
ctx.devices_info.clear();
|
|
||||||
|
|
||||||
try ctx.devices_info.list.append(ctx.allocator, default_playback);
|
|
||||||
ctx.devices_info.list.items[0].channels = try ctx.allocator.alloc(main.ChannelPosition, 2);
|
|
||||||
ctx.devices_info.list.items[0].channels[0] = .front_left;
|
|
||||||
ctx.devices_info.list.items[0].channels[1] = .front_right;
|
|
||||||
ctx.devices_info.setDefault(.playback, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn devices(ctx: Context) []const main.Device {
|
|
||||||
return ctx.devices_info.list.items;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn defaultDevice(ctx: Context, mode: main.Device.Mode) ?main.Device {
|
|
||||||
return ctx.devices_info.default(mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn createPlayer(ctx: *Context, device: main.Device, writeFn: main.WriteFn, options: main.StreamOptions) !backends.Player {
|
|
||||||
const context_options = js.createMap();
|
|
||||||
defer context_options.deinit();
|
|
||||||
context_options.set("sampleRate", js.createNumber(options.sample_rate orelse default_sample_rate));
|
|
||||||
|
|
||||||
const audio_context = js.constructType("AudioContext", &.{context_options.toValue()});
|
|
||||||
const gain_node = audio_context.call("createGain", &.{
|
|
||||||
js.createNumber(1),
|
|
||||||
js.createNumber(0),
|
|
||||||
js.createNumber(device.channels.len),
|
|
||||||
}).view(.object);
|
|
||||||
const process_node = audio_context.call("createScriptProcessor", &.{
|
|
||||||
js.createNumber(channel_size),
|
|
||||||
js.createNumber(device.channels.len),
|
|
||||||
}).view(.object);
|
|
||||||
|
|
||||||
const player = try ctx.allocator.create(Player);
|
|
||||||
errdefer ctx.allocator.destroy(player);
|
|
||||||
|
|
||||||
var captures = try ctx.allocator.alloc(js.Value, 1);
|
|
||||||
captures[0] = js.createNumber(@intFromPtr(player));
|
|
||||||
|
|
||||||
const document = js.global().get("document").view(.object);
|
|
||||||
defer document.deinit();
|
|
||||||
const click_event_str = js.createString("click");
|
|
||||||
defer click_event_str.deinit();
|
|
||||||
const resume_on_click = js.createFunction(Player.resumeOnClick, captures);
|
|
||||||
_ = document.call("addEventListener", &.{ click_event_str.toValue(), resume_on_click.toValue() });
|
|
||||||
|
|
||||||
const audio_process_event = js.createFunction(Player.audioProcessEvent, captures);
|
|
||||||
defer audio_process_event.deinit();
|
|
||||||
process_node.set("onaudioprocess", audio_process_event.toValue());
|
|
||||||
|
|
||||||
player.* = .{
|
|
||||||
.allocator = ctx.allocator,
|
|
||||||
.audio_context = audio_context,
|
|
||||||
.process_node = process_node,
|
|
||||||
.gain_node = gain_node,
|
|
||||||
.process_captures = captures,
|
|
||||||
.resume_on_click = resume_on_click,
|
|
||||||
.buf = try ctx.allocator.alloc(u8, channel_size_bytes * device.channels.len),
|
|
||||||
.buf_js = js.constructType("Uint8Array", &.{js.createNumber(channel_size_bytes)}),
|
|
||||||
.is_paused = false,
|
|
||||||
.writeFn = writeFn,
|
|
||||||
.user_data = options.user_data,
|
|
||||||
.channels = device.channels,
|
|
||||||
.format = .f32,
|
|
||||||
.sample_rate = options.sample_rate orelse default_sample_rate,
|
|
||||||
};
|
|
||||||
|
|
||||||
return .{ .webaudio = player };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn createRecorder(ctx: *Context, device: main.Device, readFn: main.ReadFn, options: main.StreamOptions) !backends.Recorder {
|
|
||||||
_ = readFn;
|
|
||||||
const recorder = try ctx.allocator.create(Recorder);
|
|
||||||
recorder.* = .{
|
|
||||||
.allocator = ctx.allocator,
|
|
||||||
.is_paused = false,
|
|
||||||
.vol = 1.0,
|
|
||||||
.channels = device.channels,
|
|
||||||
.format = options.format,
|
|
||||||
.sample_rate = options.sample_rate orelse default_sample_rate,
|
|
||||||
};
|
|
||||||
return .{ .webaudio = recorder };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Player = struct {
|
|
||||||
allocator: std.mem.Allocator,
|
|
||||||
audio_context: js.Object,
|
|
||||||
process_node: js.Object,
|
|
||||||
gain_node: js.Object,
|
|
||||||
process_captures: []js.Value,
|
|
||||||
resume_on_click: js.Function,
|
|
||||||
buf: []u8,
|
|
||||||
buf_js: js.Object,
|
|
||||||
is_paused: bool,
|
|
||||||
writeFn: main.WriteFn,
|
|
||||||
user_data: ?*anyopaque,
|
|
||||||
|
|
||||||
channels: []main.ChannelPosition,
|
|
||||||
format: main.Format,
|
|
||||||
sample_rate: u24,
|
|
||||||
|
|
||||||
pub fn deinit(player: *Player) void {
|
|
||||||
player.resume_on_click.deinit();
|
|
||||||
player.buf_js.deinit();
|
|
||||||
player.gain_node.deinit();
|
|
||||||
player.process_node.deinit();
|
|
||||||
player.audio_context.deinit();
|
|
||||||
player.allocator.free(player.process_captures);
|
|
||||||
player.allocator.free(player.buf);
|
|
||||||
player.allocator.destroy(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start(player: *Player) !void {
|
|
||||||
const destination = player.audio_context.get("destination").view(.object);
|
|
||||||
defer destination.deinit();
|
|
||||||
_ = player.gain_node.call("connect", &.{destination.toValue()});
|
|
||||||
_ = player.process_node.call("connect", &.{player.gain_node.toValue()});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resumeOnClick(args: js.Object, _: usize, captures: []js.Value) js.Value {
|
|
||||||
const player = @as(*Player, @ptrFromInt(@as(usize, @intFromFloat(captures[0].view(.num)))));
|
|
||||||
player.play() catch {};
|
|
||||||
|
|
||||||
const document = js.global().get("document").view(.object);
|
|
||||||
defer document.deinit();
|
|
||||||
|
|
||||||
const event = args.getIndex(0).view(.object);
|
|
||||||
defer event.deinit();
|
|
||||||
_ = document.call("removeEventListener", &.{ event.toValue(), player.resume_on_click.toValue() });
|
|
||||||
|
|
||||||
return js.createUndefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn audioProcessEvent(args: js.Object, _: usize, captures: []js.Value) js.Value {
|
|
||||||
const player = @as(*Player, @ptrFromInt(@as(usize, @intFromFloat(captures[0].view(.num)))));
|
|
||||||
|
|
||||||
const event = args.getIndex(0).view(.object);
|
|
||||||
defer event.deinit();
|
|
||||||
const output_buffer = event.get("outputBuffer").view(.object);
|
|
||||||
defer output_buffer.deinit();
|
|
||||||
|
|
||||||
player.writeFn(player.user_data, player.buf[0..channel_size]);
|
|
||||||
|
|
||||||
for (player.channels, 0..) |_, i| {
|
|
||||||
player.buf_js.copyBytes(player.buf[i * channel_size_bytes .. (i + 1) * channel_size_bytes]);
|
|
||||||
const buf_f32_js = js.constructType("Float32Array", &.{ player.buf_js.get("buffer"), player.buf_js.get("byteOffset"), js.createNumber(channel_size) });
|
|
||||||
defer buf_f32_js.deinit();
|
|
||||||
_ = output_buffer.call("copyToChannel", &.{ buf_f32_js.toValue(), js.createNumber(i) });
|
|
||||||
}
|
|
||||||
|
|
||||||
return js.createUndefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn play(player: *Player) !void {
|
|
||||||
_ = player.audio_context.call("resume", &.{js.createUndefined()});
|
|
||||||
player.is_paused = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pause(player: *Player) !void {
|
|
||||||
_ = player.audio_context.call("suspend", &.{js.createUndefined()});
|
|
||||||
player.is_paused = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn paused(player: *Player) bool {
|
|
||||||
return player.is_paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setVolume(player: *Player, vol: f32) !void {
|
|
||||||
const gain = player.gain_node.get("gain").view(.object);
|
|
||||||
defer gain.deinit();
|
|
||||||
gain.set("value", js.createNumber(vol));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn volume(player: *Player) !f32 {
|
|
||||||
const gain = player.gain_node.get("gain").view(.object);
|
|
||||||
defer gain.deinit();
|
|
||||||
return @as(f32, @floatCast(gain.get("value").view(.num)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Recorder = struct {
|
|
||||||
allocator: std.mem.Allocator,
|
|
||||||
is_paused: bool,
|
|
||||||
vol: f32,
|
|
||||||
|
|
||||||
channels: []main.ChannelPosition,
|
|
||||||
format: main.Format,
|
|
||||||
sample_rate: u24,
|
|
||||||
|
|
||||||
pub fn deinit(recorder: *Recorder) void {
|
|
||||||
recorder.allocator.destroy(recorder);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start(recorder: *Recorder) !void {
|
|
||||||
_ = recorder;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn record(recorder: *Recorder) !void {
|
|
||||||
recorder.is_paused = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pause(recorder: *Recorder) !void {
|
|
||||||
recorder.is_paused = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn paused(recorder: *Recorder) bool {
|
|
||||||
return recorder.is_paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setVolume(recorder: *Recorder, vol: f32) !void {
|
|
||||||
recorder.vol = vol;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn volume(recorder: *Recorder) !f32 {
|
|
||||||
return recorder.vol;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fn freeDevice(allocator: std.mem.Allocator, device: main.Device) void {
|
|
||||||
allocator.free(device.channels);
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue