summary refs log tree commit diff
path: root/src/alc.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/alc.zig')
-rw-r--r--src/alc.zig203
1 files changed, 186 insertions, 17 deletions
diff --git a/src/alc.zig b/src/alc.zig
index c69a54d..0b6439a 100644
--- a/src/alc.zig
+++ b/src/alc.zig
@@ -16,7 +16,16 @@
 // 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 assert = std.debug.assert;
 const c = @import("cimport.zig");
+const find = std.mem.indexOfScalar;
+const span = std.mem.span;
+const std = @import("std");
+comptime {
+    // OpenAL Soft defines these as int, but comments they're 32-bit.
+    assert(@sizeOf(c.ALCenum) == @sizeOf(i32));
+    assert(@sizeOf(c.ALCint) == @sizeOf(i32));
+}
 
 /// Opaque device handle.
 pub const Device = c.ALCdevice;
@@ -36,16 +45,156 @@ pub const Error = error {
     OutOfMemory,
 };
 
-pub const FALSE = c.ALC_FALSE;
-pub const TRUE = c.ALC_TRUE;
-pub const DONT_CARE  = c.ALC_DONT_CATE_SOFT;
+pub const Enum = enum(i32) {
+    /// No error.
+    no_error = c.ALC_NO_ERROR,
+    /// Invalid enum parameter passed to an ALC call.
+    invalid_enum = c.ALC_INVALID_ENUM,
+    /// Invalid value parameter passed to an ALC call.
+    invalid_value = c.ALC_INVALID_VALUE,
+    /// Invalid device handle.
+    invalid_device = c.ALC_INVALID_DEVICE,
+    /// Invalid context handle.
+    invalid_context = c.ALC_INVALID_CONTEXT,
+    /// Out of memory error.
+    out_of_memory = c.ALC_OUT_OF_MEMORY,
+
+    device_specifier = c.ALC_DEVICE_SPECIFIER,
+    all_devices_specifier = c.ALC_ALL_DEVICES_SPECIFIER,
+    capture_device_specifier = c.ALC_CAPTURE_DEVICE_SPECIFIER,
+    default_device_specifier = c.ALC_DEFAULT_DEVICE_SPECIFIER,
+    default_all_devices_specifier = c.ALC_DEFAULT_ALL_DEVICES_SPECIFIER,
+    capture_default_device_specifier = c.ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER,
+
+    /// Extension list.
+    extensions = c.ALC_EXTENSIONS,
+    hrtf_specifier = c.ALC_HRTF_SPECIFIER_SOFT,
+
+    /// OpenAL major version.
+    major_version = c.ALC_MAJOR_VERSION,
+    /// OpenAL minor version.
+    minor_version = c.ALC_MINOR_VERSION,
+    /// Effects Extension major version.
+    efx_major_version = c.ALC_EFX_MAJOR_VERSION,
+    /// Effects Extension minor version.
+    efx_minor_version = c.ALC_EFX_MINOR_VERSION,
+
+    /// Audio channels' format.
+    channels_format = c.ALC_FORMAT_CHANNELS_SOFT,
+    /// Sample type.
+    sample_type = c.ALC_FORMAT_TYPE_SOFT,
+    /// Frequency in hertz.
+    frequency = c.ALC_FREQUENCY,
+
+    /// Ambisonic component ordering.
+    ambisonic_layout = c.ALC_AMBISONIC_LAYOUT_SOFT,
+    /// Ambisonic normalization.
+    ambisonic_scaling = c.ALC_AMBISONIC_SCALING_SOFT,
+    /// Ambisonic order.
+    ambisonic_order = c.ALC_AMBISONIC_ORDER_SOFT,
+
+    /// Number of mono (3D) sources.
+    mono_sources = c.ALC_MONO_SOURCES,
+    /// Number of stereo sources.
+    stereo_sources = c.ALC_STEREO_SOURCES,
+    /// Maximum number of auxiliary source sends.
+    max_auxiliary_sends = c.ALC_MAX_AUXILIARY_SENDS,
+
+    /// Enabling HRTF.
+    hrtf = c.ALC_HRTF_SOFT,
+    /// The HRTF being used.
+    hrtf_id = c.ALC_HRTF_ID_SOFT,
+    /// Enabling gain limiter.
+    output_limiter = c.ALC_OUTPUT_LIMITER_SOFT,
+    /// The output mode.
+    output_mode = c.ALC_OUTPUT_MODE_SOFT,
+
+    /// Keys with boolean values.
+    const booleans = [_]Enum{ .hrtf, .output_limiter };
+    /// Keys with integral values.
+    const integers = [_]Enum{
+        .major_version, .minor_version, .efx_major_version, .efx_minor_version,
+        .channels_format, .sample_type, .frequency,
+        .ambisonic_layout, .ambisonic_scaling, .ambisonic_order,
+        .mono_sources, .stereo_sources, .max_auxiliary_sends,
+        .hrtf_id, .output_mode,
+    };
+    /// Keys with string values.
+    const strings = [_]Enum{
+        .no_error, .invalid_enum, .invalid_value,
+        .invalid_device, .invalid_context, .out_of_memory,
+        .device_specifier, .default_device_specifier,
+        .all_devices_specifier, .default_all_devices_specifier,
+        .capture_device_specifier, .capture_default_device_specifier,
+        .extensions, .hrtf_specifier,
+    };
+
+    /// Return type of the key's corresponding value.
+    pub fn getType(comptime self: Enum) type {
+        if (find(Enum, &Enum.booleans, self)) |_|
+            return bool;
+        if (find(Enum, &Enum.integers, self)) |_|
+            return i32;
+        if (find(Enum, &Enum.strings, self)) |_|
+            return [:0]const u8;
+        unreachable;
+    }
+};
+
+/// Format of audio channels.
+pub const ChannelsFormat = enum(i32) {
+    /// Monophonic sound.
+    mono = c.ALC_MONO_SOFT,
+    /// Stereophonic sound.
+    stereo = c.ALC_STEREO_SOFT,
+    /// 4.0 surround sound.
+    quad = c.ALC_QUAD_SOFT,
+    /// 5.1 surround sound.
+    x51 = c.ALC_5POINT1_SOFT,
+    /// 6.1 surround sound.
+    x61 = c.ALC_6POINT1_SOFT,
+    /// 7.1 surround sound.
+    x71 = c.ALC_7POINT1_SOFT,
+    /// Ambisonics.
+    b_format = c.ALC_BFORMAT3D_SOFT,
+};
+/// Sample format.
+pub const SampleType = enum(i32) {
+    i8 = c.ALC_BYTE_SOFT,
+    u8 = c.ALC_UNSIGNED_BYTE_SOFT,
+    i16 = c.ALC_SHORT_SOFT,
+    u16 = c.ALC_UNSIGNED_SHORT_SOFT,
+    i32 = c.ALC_INT_SOFT,
+    u32 = c.ALC_UNSIGNED_INT_SOFT,
+    f32 = c.ALC_FLOAT_SOFT,
+};
+
+/// Ambisonic format layout.
+pub const AmbisonicLayout = enum(i32) {
+    /// Furse-Malham ordering.
+    fu_ma = c.AL_FUMA_SOFT,
+    /// Ambisonic Channel Number ordering.
+    acn = c.AL_ACN_SOFT,
+};
+/// Ambisonic normalization method.
+pub const AmbisonicScaling = enum(i32) {
+    /// Furse-Malham format (maxN normalisation?).
+    fu_ma = c.AL_FUMA_SOFT,
+    /// Schmidt semi-normalisation.
+    sn3d = c.AL_SN3D_SOFT,
+    /// Full 3D normalisation.
+    n3d = c.AL_N3D_SOFT,
+};
 
-/// Context creation key to specify whether to enable HRTF
-/// (either `FALSE`, `TRUE` or `DONT_CARE`).
-pub const HRTF = c.ALC_HRTF_SOFT;
+/// Logical value.
+pub const Logical = enum(i32) {
+    false = c.ALC_FALSE,
+    true = c.ALC_TRUE,
+    null = c.ALC_DONT_CARE_SOFT,
+};
 
 /// Create and attach a context to the given device.
-pub fn createContext(device: *Device, attrlist: [:0]const i32) Error!*Context {
+pub fn createContext(device: *Device, attrlist: [:0]const i32) !*Context {
     if (c.alcCreateContext(device, attrlist.ptr)) |context|
         return context;
     return switch (c.alcGetError(device)) {
@@ -57,8 +206,8 @@ pub fn createContext(device: *Device, attrlist: [:0]const i32) Error!*Context {
 
 /// Make the given context the active process-wide context.
 /// Passing NULL clears the active context.
-pub fn makeContextCurrent(context: ?*Context) Error!void {
-    if (c.alcMakeContextCurrent(context) == TRUE)
+pub fn makeContextCurrent(context: ?*Context) !void {
+    if (c.alcMakeContextCurrent(context) == c.ALC_TRUE)
         return;
     if (c.alcGetError(null) == c.ALC_INVALID_CONTEXT)
         return Error.InvalidContext;
@@ -66,7 +215,7 @@ pub fn makeContextCurrent(context: ?*Context) Error!void {
 }
 
 /// Remove a context from its device and destroys it.
-pub fn destroyContext(context: *Context) Error!void {
+pub fn destroyContext(context: *Context) !void {
     c.alcDestroyContext(context);
     if (c.alcGetError(null) == c.ALC_INVALID_CONTEXT)
         return Error.InvalidContext;
@@ -78,7 +227,7 @@ pub fn getCurrentContext() ?*Context {
 }
 
 /// Return the device that a particular context is attached to.
-pub fn getContextsDevice(context: *Context) Error!*Device {
+pub fn getContextsDevice(context: *Context) !*Device {
     if (c.alcGetContextsDevice(context)) |device|
         return device;
     if (c.alcGetError(null) == c.ALC_INVALID_CONTEXT)
@@ -87,7 +236,7 @@ pub fn getContextsDevice(context: *Context) Error!*Device {
 }
 
 /// Open the named playback device.
-pub fn openDevice(name: ?[:0]const u8) Error!*Device {
+pub fn openDevice(name: ?[:0]const u8) !*Device {
     const name_ptr = if (name == null) null else name.?.ptr;
     if (c.alcOpenDevice(name_ptr)) |device|
         return device;
@@ -99,17 +248,32 @@ pub fn openDevice(name: ?[:0]const u8) Error!*Device {
 }
 
 /// Close the given playback device.
-pub fn closeDevice(device: *Device) Error!void {
-    if (c.alcCloseDevice(device) == TRUE)
+pub fn closeDevice(device: *Device) !void {
+    if (c.alcCloseDevice(device) == c.ALC_TRUE)
         return;
     if (c.alcGetError(device) == c.ALC_INVALID_DEVICE)
         return Error.InvalidDevice;
     unreachable;
 }
 
-pub fn getInt(device: *Device, param: c.ALCenum) Error!i32 {
-    var data: i32 = undefined;
-    c.alcGetIntegerv(device, param, 1, &data);
+/// Return information about the device.
+fn getInfo(comptime T: type, device: ?*Device, attr: Enum) !T {
+    const data = switch (T) {
+        bool => return switch (try getInfo(i32, device, attr)) {
+            c.ALC_FALSE => false,
+            c.ALC_TRUE => true,
+            else => unreachable,
+        },
+        i32 => return (try getInfo([1]i32, device, attr))[0],
+        [:0]const u8 => span(c.alcGetString(device, @enumToInt(attr))),
+        else => array: {
+            assert(@typeInfo(T).Array.child == i32);
+            var data: T = undefined;
+            c.alcGetIntegerv(device, @enumToInt(attr), data.len, &data);
+            break :array data;
+        },
+    };
+
     return switch (c.alcGetError(device)) {
         c.ALC_NO_ERROR => data,
         c.ALC_INVALID_VALUE => Error.InvalidValue,
@@ -119,3 +283,8 @@ pub fn getInt(device: *Device, param: c.ALCenum) Error!i32 {
         else => unreachable,
     };
 }
+
+/// Return information about the device.
+pub fn get(device: ?*Device, comptime attr: Enum) !attr.getType() {
+    return getInfo(attr.getType(), device, attr);
+}