diff options
Diffstat (limited to 'src/alc.zig')
-rw-r--r-- | src/alc.zig | 203 |
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); +} |