diff options
-rw-r--r-- | build.zig | 17 | ||||
-rw-r--r-- | examples/hrtf.zig | 67 | ||||
-rw-r--r-- | examples/play.zig | 5 | ||||
-rw-r--r-- | src/al.zig | 12 | ||||
-rw-r--r-- | src/sf.zig | 2 | ||||
-rw-r--r-- | src/zeal.zig | 17 |
6 files changed, 108 insertions, 12 deletions
diff --git a/build.zig b/build.zig index afc422f..9dd9fa2 100644 --- a/build.zig +++ b/build.zig @@ -24,13 +24,14 @@ pub fn build(b: *std.build.Builder) void { const mode = b.standardReleaseOptions(); const lib = b.addStaticLibrary("zeal", "src/zeal.zig"); + lib.linkSystemLibrary("openal"); + lib.linkSystemLibrary("sndfile"); + lib.linkSystemLibrary("c"); lib.setBuildMode(mode); lib.install(); var main_tests = b.addTest("src/zeal.zig"); - main_tests.linkSystemLibrary("openal"); - main_tests.linkSystemLibrary("sndfile"); - main_tests.linkSystemLibrary("c"); + main_tests.linkLibrary(lib); main_tests.setBuildMode(mode); const test_step = b.step("test", "Run library tests"); @@ -38,9 +39,13 @@ pub fn build(b: *std.build.Builder) void { const example_play = b.addExecutable("zeal-play", "examples/play.zig"); example_play.addPackagePath("zeal", "src/zeal.zig"); - example_play.linkSystemLibrary("openal"); - example_play.linkSystemLibrary("sndfile"); - example_play.linkSystemLibrary("c"); + example_play.linkLibrary(lib); example_play.setBuildMode(mode); example_play.install(); + + const example_hrtf = b.addExecutable("zeal-hrtf", "examples/hrtf.zig"); + example_hrtf.addPackagePath("zeal", "src/zeal.zig"); + example_hrtf.linkLibrary(lib); + example_hrtf.setBuildMode(mode); + example_hrtf.install(); } diff --git a/examples/hrtf.zig b/examples/hrtf.zig new file mode 100644 index 0000000..723571d --- /dev/null +++ b/examples/hrtf.zig @@ -0,0 +1,67 @@ +// Positional audio example with HRTF +// Copyright (C) 2021 Nguyễn Gia Phong +// +// This file is part of zeal. +// +// Zeal is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Zeal is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with zeal. If not, see <https://www.gnu.org/licenses/>. + +const std = @import("std"); +const allocator = std.heap.c_allocator; +const args = std.process.args; +const print = std.debug.print; +const sleep = std.time.sleep; + +const zeal = @import("zeal"); +const al = zeal.al; +const alc = zeal.alc; +const Device = zeal.Device; +const Context = zeal.Context; +const Audio = zeal.Audio; +const useContext = zeal.useContext; +const Buffer = zeal.Buffer; +const Source = zeal.Source; + +pub fn main() !void { + const device = try Device.init(null); + defer device.deinit() catch unreachable; + + const context = try Context.init(device, &.{ alc.HRTF, alc.TRUE }); + if (try device.enabledHrtf()) + print("HRTF enabled!\n", .{}) + else + print("HRTF not enabled!\n", .{}); + defer context.deinit() catch unreachable; + + var argv = args(); + allocator.free(try argv.next(allocator).?); + const path = try argv.next(allocator).?; + defer allocator.free(path); + const audio = try Audio.read(allocator, path); + defer audio.free(); + + try useContext(context); + const buffer = try Buffer.init(context, audio); + defer buffer.deinit() catch unreachable; + + const source = try Source.init(context); + defer source.deinit() catch unreachable; + try source.setSpatialize(al.TRUE); + try source.play(buffer); + defer print("\n", .{}); + while (try source.isPlaying()) { + const offset = try source.getSecOffset(); + try source.setPosition(.{ @sin(offset), 0, @cos(offset) }); + sleep(10_000_000); + } +} diff --git a/examples/play.zig b/examples/play.zig index 7297181..0a031f9 100644 --- a/examples/play.zig +++ b/examples/play.zig @@ -19,6 +19,7 @@ const std = @import("std"); const allocator = std.heap.c_allocator; const args = std.process.args; +const print = std.debug.print; const sleep = std.time.sleep; const zeal = @import("zeal"); @@ -50,9 +51,9 @@ pub fn main() !void { const source = try Source.init(context); defer source.deinit() catch unreachable; try source.play(buffer); - defer std.debug.print("\n", .{}); + defer print("\n", .{}); while (try source.isPlaying()) { sleep(10_000_000); - defer std.debug.print("\r{d:.1} s", .{ source.getSecOffset() }); + defer print("\r{d:.1} s", .{ source.getSecOffset() }); } } diff --git a/src/al.zig b/src/al.zig index 7b2e6db..bbde02e 100644 --- a/src/al.zig +++ b/src/al.zig @@ -18,7 +18,10 @@ const Child = @import("std").meta.Child; -usingnamespace @cImport(@cInclude("AL/al.h")); +usingnamespace @cImport({ + @cInclude("AL/al.h"); + @cInclude("AL/alext.h"); +}); pub const Error = error { /// Bad name (ID) passed to an OpenAL function. @@ -33,12 +36,17 @@ pub const Error = error { OutOfMemory, }; +pub const FALSE = AL_FALSE; +pub const TRUE = AL_TRUE; +pub const AUTO = AL_AUTO_SOFT; + pub const BUFFER = AL_BUFFER; pub const POSITION = AL_POSITION; pub const ORIENTATION = AL_ORIENTATION; pub const PLAYING = AL_PLAYING; pub const SEC_OFFSET = AL_SEC_OFFSET; pub const SOURCE_STATE = AL_SOURCE_STATE; +pub const SOURCE_SPATIALIZE = AL_SOURCE_SPATIALIZE_SOFT; pub const listener = struct { /// Set a property for the listener. @@ -211,7 +219,5 @@ pub const source = struct { } }; -// alGetSourcei // alSourcePause -// alSourcePlay // alSourceStop diff --git a/src/sf.zig b/src/sf.zig index a95999c..a63da19 100644 --- a/src/sf.zig +++ b/src/sf.zig @@ -67,7 +67,7 @@ pub const SndFile = struct { .channels = info.channels, .format = info.format, .sections = info.sections, - .seekable = if (info.seekable == 0) false else true, + .seekable = info.seekable != 0, }; } diff --git a/src/zeal.zig b/src/zeal.zig index 26dffa8..af9fd85 100644 --- a/src/zeal.zig +++ b/src/zeal.zig @@ -35,6 +35,10 @@ pub const Device = struct { return Device{ .pimpl = try alc.openDevice(name) }; } + pub fn enabledHrtf(self: Device) alc.Error!bool { + return 0 != try alc.getInt(self.pimpl, alc.HRTF); + } + pub fn deinit(self: Device) alc.Error!void { try alc.closeDevice(self.pimpl); } @@ -152,6 +156,19 @@ pub const Source = struct { try al.source.destroy(&self.reference); } + /// Specify if the source always has 3D spatialization features (al.ON), + /// never has 3D spatialization features (al.OFF), or if spatialization + /// is enabled based on playing a mono sound or not (al.AUTO, default). + pub fn setSpatialize(self: Source, value: i32) Error!void { + try checkContext(self.context); + try al.source.set(self.reference, al.SOURCE_SPATIALIZE, value); + } + + pub fn setPosition(self: Source, position: [3]f32) Error!void { + try checkContext(self.context); + try al.source.set(self.reference, al.POSITION, position); + } + pub fn isPlaying(self: Source) Error!bool { try checkContext(self.context); const state = try al.source.get(i32, self.reference, al.SOURCE_STATE); |