diff options
-rw-r--r-- | build.zig | 11 | ||||
-rw-r--r-- | src/al.zig | 189 | ||||
-rw-r--r-- | src/alc.zig | 67 | ||||
-rw-r--r-- | src/cimport.zig | 6 | ||||
-rw-r--r-- | src/sf.zig | 35 | ||||
-rw-r--r-- | src/zeal.zig | 4 |
6 files changed, 159 insertions, 153 deletions
diff --git a/build.zig b/build.zig index 11c7deb..07007ad 100644 --- a/build.zig +++ b/build.zig @@ -35,16 +35,21 @@ fn addExampleStep(comptime name: []const u8, description: []const u8, b.step(name, description).dependOn(&cmd.step); } +/// Link given library, executable, or object with shared libraries. +pub fn link(lib_exe_obj: *LibExeObjStep) void { + lib_exe_obj.linkSystemLibrary("openal"); + lib_exe_obj.linkSystemLibrary("sndfile"); + lib_exe_obj.linkSystemLibrary("c"); +} + pub fn build(b: *Builder) void { // Standard release options allow the person running `zig build` to select // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. const mode = b.standardReleaseOptions(); const lib = b.addStaticLibrary("zeal", "src/zeal.zig"); - lib.linkSystemLibrary("openal"); - lib.linkSystemLibrary("sndfile"); - lib.linkSystemLibrary("c"); lib.setBuildMode(mode); + link(lib); lib.install(); var main_tests = b.addTest("src/zeal.zig"); diff --git a/src/al.zig b/src/al.zig index a5164d6..5193df2 100644 --- a/src/al.zig +++ b/src/al.zig @@ -20,10 +20,7 @@ const Child = meta.Child; const Tag = meta.Tag; const meta = @import("std").meta; -usingnamespace @cImport({ - @cInclude("AL/al.h"); - @cInclude("AL/alext.h"); -}); +const c = @import("cimport.zig"); pub const Error = error { /// Bad name (ID) passed to an OpenAL function. @@ -39,17 +36,17 @@ pub const Error = error { }; // FIXME: turn into enum -pub const FALSE = AL_FALSE; -pub const TRUE = AL_TRUE; -pub const AUTO = AL_AUTO_SOFT; +pub const FALSE = c.AL_FALSE; +pub const TRUE = c.AL_TRUE; +pub const AUTO = c.AL_AUTO_SOFT; pub const listener = struct { - const Property = enum(ALenum) { - gain = AL_GAIN, - position = AL_POSITION, - velocity = AL_VELOCITY, - orientation = AL_ORIENTATION, - meters_per_unit = AL_METERS_PER_UNIT, + const Property = enum(c.ALenum) { + gain = c.AL_GAIN, + position = c.AL_POSITION, + velocity = c.AL_VELOCITY, + orientation = c.AL_ORIENTATION, + meters_per_unit = c.AL_METERS_PER_UNIT, }; /// Set a property for the listener. @@ -57,20 +54,20 @@ pub const listener = struct { const param = @enumToInt(property); const T = @TypeOf(value); switch (T) { - f32 => alListenerf(param, value), - i32 => alListeneri(param, value), + f32 => c.alListenerf(param, value), + i32 => c.alListeneri(param, value), else => switch (Child(T)) { - f32 => alListenerfv(param, value[0..]), - i32 => alListeneriv(param, value[0..]), + f32 => c.alListenerfv(param, value[0..]), + i32 => c.alListeneriv(param, value[0..]), else => unreachable, } } - switch (alGetError()) { - AL_NO_ERROR => {}, - AL_INVALID_VALUE => return Error.InvalidValue, - AL_INVALID_ENUM => return Error.InvalidEnum, - AL_INVALID_OPERATION => return Error.InvalidOperation, + switch (c.alGetError()) { + c.AL_NO_ERROR => {}, + c.AL_INVALID_VALUE => return Error.InvalidValue, + c.AL_INVALID_ENUM => return Error.InvalidEnum, + c.AL_INVALID_OPERATION => return Error.InvalidOperation, else => unreachable, } } @@ -91,11 +88,11 @@ pub const buffer = struct { /// Generate one buffer for audio data and return its reference. pub fn create() Error!u32 { var reference: u32 = undefined; - alGenBuffers(1, &reference); - return switch (alGetError()) { - AL_NO_ERROR => reference, - AL_INVALID_VALUE => Error.InvalidValue, - AL_OUT_OF_MEMORY => Error.OutOfMemory, + c.alGenBuffers(1, &reference); + return switch (c.alGetError()) { + c.AL_NO_ERROR => reference, + c.AL_INVALID_VALUE => Error.InvalidValue, + c.AL_OUT_OF_MEMORY => Error.OutOfMemory, else => unreachable, }; } @@ -103,12 +100,12 @@ pub const buffer = struct { /// Free resources used by one buffer. /// Buffers attached to a source cannot be deleted. pub fn destroy(reference: *const u32) Error!void { - alDeleteBuffers(1, reference); - switch (alGetError()) { - AL_NO_ERROR => {}, - AL_INVALID_OPERATION => return Error.InvalidOperation, - AL_INVALID_NAME => return Error.InvalidName, - AL_INVALID_VALUE => return Error.InvalidValue, + c.alDeleteBuffers(1, reference); + switch (c.alGetError()) { + c.AL_NO_ERROR => {}, + c.AL_INVALID_OPERATION => return Error.InvalidOperation, + c.AL_INVALID_NAME => return Error.InvalidName, + c.AL_INVALID_VALUE => return Error.InvalidValue, else => unreachable, } } @@ -116,28 +113,28 @@ pub const buffer = struct { /// Fill a buffer with audio data. pub fn fill(reference: u32, data: Data, freq: i32) Error!void { const format = switch (data) { - .mono8 => AL_FORMAT_MONO8, - .mono16 => AL_FORMAT_MONO16, - .stereo8 => AL_FORMAT_STEREO8, - .stereo16 => AL_FORMAT_STEREO16, + .mono8 => c.AL_FORMAT_MONO8, + .mono16 => c.AL_FORMAT_MONO16, + .stereo8 => c.AL_FORMAT_STEREO8, + .stereo16 => c.AL_FORMAT_STEREO16, }; switch (data) { .mono8, .stereo8 => |slice| { const size = @intCast(c_int, slice.len); - alBufferData(reference, format, slice.ptr, size, freq); + c.alBufferData(reference, format, slice.ptr, size, freq); }, .mono16, .stereo16 => |slice| { const size = @intCast(c_int, slice.len) * 2; - alBufferData(reference, format, slice.ptr, size, freq); + c.alBufferData(reference, format, slice.ptr, size, freq); }, } - switch (alGetError()) { - AL_NO_ERROR => {}, - AL_OUT_OF_MEMORY => return Error.OutOfMemory, - AL_INVALID_VALUE => return Error.InvalidValue, - AL_INVALID_ENUM => return Error.InvalidEnum, + switch (c.alGetError()) { + c.AL_NO_ERROR => {}, + c.AL_OUT_OF_MEMORY => return Error.OutOfMemory, + c.AL_INVALID_VALUE => return Error.InvalidValue, + c.AL_INVALID_ENUM => return Error.InvalidEnum, else => unreachable, } } @@ -147,11 +144,11 @@ pub const source = struct { /// Generate one source for audio data and return its reference. pub fn create() Error!u32 { var reference: u32 = undefined; - alGenSources(1, &reference); - return switch (alGetError()) { - AL_NO_ERROR => reference, - AL_INVALID_VALUE => Error.InvalidValue, - AL_OUT_OF_MEMORY => Error.OutOfMemory, + c.alGenSources(1, &reference); + return switch (c.alGetError()) { + c.AL_NO_ERROR => reference, + c.AL_INVALID_VALUE => Error.InvalidValue, + c.AL_OUT_OF_MEMORY => Error.OutOfMemory, else => unreachable, }; } @@ -159,35 +156,35 @@ pub const source = struct { /// Free resources used by one source. /// Sources attached to a source cannot be deleted. pub fn destroy(reference: *const u32) Error!void { - alDeleteSources(1, reference); - switch (alGetError()) { - AL_NO_ERROR => {}, - AL_INVALID_OPERATION => return Error.InvalidOperation, - AL_INVALID_NAME => return Error.InvalidName, - AL_INVALID_VALUE => return Error.InvalidValue, + c.alDeleteSources(1, reference); + switch (c.alGetError()) { + c.AL_NO_ERROR => {}, + c.AL_INVALID_OPERATION => return Error.InvalidOperation, + c.AL_INVALID_NAME => return Error.InvalidName, + c.AL_INVALID_VALUE => return Error.InvalidValue, else => unreachable, } } - const Property = enum(ALenum) { - pitch = AL_PITCH, - gain = AL_GAIN, - position = AL_POSITION, - velocity = AL_VELOCITY, - direction = AL_DIRECTION, - relative = AL_SOURCE_RELATIVE, - looping = AL_LOOPING, - buffer = AL_BUFFER, - state = AL_SOURCE_STATE, - sec_offset = AL_SEC_OFFSET, - spatialize = AL_SOURCE_SPATIALIZE_SOFT, + const Property = enum(c.ALenum) { + pitch = c.AL_PITCH, + gain = c.AL_GAIN, + position = c.AL_POSITION, + velocity = c.AL_VELOCITY, + direction = c.AL_DIRECTION, + relative = c.AL_SOURCE_RELATIVE, + looping = c.AL_LOOPING, + buffer = c.AL_BUFFER, + state = c.AL_SOURCE_STATE, + sec_offset = c.AL_SEC_OFFSET, + spatialize = c.AL_SOURCE_SPATIALIZE_SOFT, }; pub const State = enum(i32) { - initial = AL_INITIAL, - playing = AL_PLAYING, - paused = AL_PAUSED, - stopped = AL_STOPPED, + initial = c.AL_INITIAL, + playing = c.AL_PLAYING, + paused = c.AL_PAUSED, + stopped = c.AL_STOPPED, }; /// Set a property for the source. @@ -195,24 +192,24 @@ pub const source = struct { const param = @enumToInt(property); const T = @TypeOf(value); switch (T) { - f32 => alSourcef(reference, param, value), - i32 => alSourcei(reference, param, value), + f32 => c.alSourcef(reference, param, value), + i32 => c.alSourcei(reference, param, value), else => switch (@typeInfo(T)) { - .Enum => alSourcei(reference, param, @enumToInt(value)), + .Enum => c.alSourcei(reference, param, @enumToInt(value)), else => switch (Child(T)) { - f32 => alSourcefv(reference, param, value[0..]), - i32 => alSourceiv(reference, param, value[0..]), + f32 => c.alSourcefv(reference, param, value[0..]), + i32 => c.alSourceiv(reference, param, value[0..]), else => unreachable, }, }, } - switch (alGetError()) { - AL_NO_ERROR => {}, - AL_INVALID_VALUE => return Error.InvalidValue, - AL_INVALID_ENUM => return Error.InvalidEnum, - AL_INVALID_NAME => return Error.InvalidName, - AL_INVALID_OPERATION => return Error.InvalidOperation, + switch (c.alGetError()) { + c.AL_NO_ERROR => {}, + c.AL_INVALID_VALUE => return Error.InvalidValue, + c.AL_INVALID_ENUM => return Error.InvalidEnum, + c.AL_INVALID_NAME => return Error.InvalidName, + c.AL_INVALID_OPERATION => return Error.InvalidOperation, else => unreachable, } } @@ -222,35 +219,35 @@ pub const source = struct { const param = @enumToInt(property); var value: T = undefined; switch (T) { - f32 => alGetSourcef(reference, param, &value), - i32 => alGetSourcei(reference, param, &value), + f32 => c.alGetSourcef(reference, param, &value), + i32 => c.alGetSourcei(reference, param, &value), else => switch (@typeInfo(T)) { .Enum => { var raw: i32 = undefined; - alGetSourcei(reference, param, &raw); + c.alGetSourcei(reference, param, &raw); value = @intToEnum(T, raw); }, else => unreachable, }, } - return switch (alGetError()) { - AL_NO_ERROR => value, - AL_INVALID_VALUE => return Error.InvalidValue, - AL_INVALID_ENUM => return Error.InvalidEnum, - AL_INVALID_NAME => return Error.InvalidName, - AL_INVALID_OPERATION => return Error.InvalidOperation, + return switch (c.alGetError()) { + c.AL_NO_ERROR => value, + c.AL_INVALID_VALUE => return Error.InvalidValue, + c.AL_INVALID_ENUM => return Error.InvalidEnum, + c.AL_INVALID_NAME => return Error.InvalidName, + c.AL_INVALID_OPERATION => return Error.InvalidOperation, else => unreachable, }; } /// Play the source. pub fn play(reference: u32) Error!void { - alSourcePlay(reference); - switch (alGetError()) { - AL_NO_ERROR => {}, - AL_INVALID_NAME => return Error.InvalidName, - AL_INVALID_OPERATION => return Error.InvalidOperation, + c.alSourcePlay(reference); + switch (c.alGetError()) { + c.AL_NO_ERROR => {}, + c.AL_INVALID_NAME => return Error.InvalidName, + c.AL_INVALID_OPERATION => return Error.InvalidOperation, else => unreachable, } } diff --git a/src/alc.zig b/src/alc.zig index ca83bf6..b493a78 100644 --- a/src/alc.zig +++ b/src/alc.zig @@ -16,15 +16,12 @@ // You should have received a copy of the GNU Lesser General Public License // along with zeal. If not, see <https://www.gnu.org/licenses/>. -usingnamespace @cImport({ - @cInclude("AL/alc.h"); - @cInclude("AL/alext.h"); -}); +const c = @import("cimport.zig"); /// Opaque device handle. -pub const Device = ALCdevice; +pub const Device = c.ALCdevice; /// Opaque context handle. -pub const Context = ALCcontext; +pub const Context = c.ALCcontext; pub const Error = error { /// Invalid device handle. @@ -39,21 +36,21 @@ pub const Error = error { OutOfMemory, }; -pub const FALSE = ALC_FALSE; -pub const TRUE = ALC_TRUE; -pub const DONT_CARE = ALC_DONT_CATE_SOFT; +pub const FALSE = c.ALC_FALSE; +pub const TRUE = c.ALC_TRUE; +pub const DONT_CARE = c.ALC_DONT_CATE_SOFT; /// Context creation key to specify whether to enable HRTF /// (either `FALSE`, `TRUE` or `DONT_CARE`). -pub const HRTF = ALC_HRTF_SOFT; +pub const HRTF = c.ALC_HRTF_SOFT; /// Create and attach a context to the given device. pub fn createContext(device: *Device, attrlist: [:0]const i32) Error!*Context { - if (alcCreateContext(device, attrlist.ptr)) |context| + if (c.alcCreateContext(device, attrlist.ptr)) |context| return context; - return switch (alcGetError(device)) { - ALC_INVALID_DEVICE => Error.InvalidDevice, - ALC_INVALID_VALUE => Error.InvalidValue, + return switch (c.alcGetError(device)) { + c.ALC_INVALID_DEVICE => Error.InvalidDevice, + c.ALC_INVALID_VALUE => Error.InvalidValue, else => unreachable, }; } @@ -61,30 +58,30 @@ 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 (alcMakeContextCurrent(context) == TRUE) + if (c.alcMakeContextCurrent(context) == TRUE) return; - if (alcGetError(null) == ALC_INVALID_CONTEXT) + if (c.alcGetError(null) == c.ALC_INVALID_CONTEXT) return Error.InvalidContext; unreachable; } /// Remove a context from its device and destroys it. pub fn destroyContext(context: *Context) Error!void { - alcDestroyContext(context); - if (alcGetError(null) == ALC_INVALID_CONTEXT) + c.alcDestroyContext(context); + if (c.alcGetError(null) == c.ALC_INVALID_CONTEXT) return Error.InvalidContext; } /// Return the currently active context. pub fn getCurrentContext() ?*Context { - return alcGetCurrentContext(); + return c.alcGetCurrentContext(); } /// Return the device that a particular context is attached to. pub fn getContextsDevice(context: *Context) Error!*Device { - if (alcGetContextsDevice(context)) |device| + if (c.alcGetContextsDevice(context)) |device| return device; - if (alcGetError(null) == ALC_INVALID_CONTEXT) + if (c.alcGetError(null) == c.ALC_INVALID_CONTEXT) return Error.InvalidContext; unreachable; } @@ -92,33 +89,33 @@ pub fn getContextsDevice(context: *Context) Error!*Device { /// Open the named playback device. pub fn openDevice(name: ?[:0]const u8) Error!*Device { const name_ptr = if (name == null) null else name.?.ptr; - if (alcOpenDevice(name_ptr)) |device| + if (c.alcOpenDevice(name_ptr)) |device| return device; - return switch (alcGetError(null)) { - ALC_INVALID_VALUE => Error.InvalidValue, - ALC_OUT_OF_MEMORY => Error.OutOfMemory, + return switch (c.alcGetError(null)) { + c.ALC_INVALID_VALUE => Error.InvalidValue, + c.ALC_OUT_OF_MEMORY => Error.OutOfMemory, else => unreachable, }; } /// Close the given playback device. pub fn closeDevice(device: *Device) Error!void { - if (alcCloseDevice(device) == TRUE) + if (c.alcCloseDevice(device) == TRUE) return; - if (alcGetError(device) == ALC_INVALID_DEVICE) + if (c.alcGetError(device) == c.ALC_INVALID_DEVICE) return Error.InvalidDevice; unreachable; } -pub fn getInt(device: *Device, param: ALCenum) Error!i32 { +pub fn getInt(device: *Device, param: c.ALCenum) Error!i32 { var data: i32 = undefined; - alcGetIntegerv(device, param, 1, &data); - return switch (alcGetError(device)) { - ALC_NO_ERROR => data, - ALC_INVALID_VALUE => Error.InvalidValue, - ALC_INVALID_ENUM => Error.InvalidEnum, - ALC_INVALID_DEVICE => Error.InvalidDevice, - ALC_INVALID_CONTEXT => Error.InvalidContext, + c.alcGetIntegerv(device, param, 1, &data); + return switch (c.alcGetError(device)) { + c.ALC_NO_ERROR => data, + c.ALC_INVALID_VALUE => Error.InvalidValue, + c.ALC_INVALID_ENUM => Error.InvalidEnum, + c.ALC_INVALID_DEVICE => Error.InvalidDevice, + c.ALC_INVALID_CONTEXT => Error.InvalidContext, else => unreachable, }; } diff --git a/src/cimport.zig b/src/cimport.zig new file mode 100644 index 0000000..dc19cc9 --- /dev/null +++ b/src/cimport.zig @@ -0,0 +1,6 @@ +usingnamespace @cImport({ + @cInclude("AL/al.h"); + @cInclude("AL/alc.h"); + @cInclude("AL/alext.h"); + @cInclude("sndfile.h"); +}); diff --git a/src/sf.zig b/src/sf.zig index 80cfd9e..96568b6 100644 --- a/src/sf.zig +++ b/src/sf.zig @@ -20,7 +20,7 @@ const Allocator = std.mem.Allocator; const assert = std.debug.assert; const std = @import("std"); -usingnamespace @cImport(@cInclude("sndfile.h")); +const c = @import("cimport.zig"); pub const Mode = enum { read, @@ -36,7 +36,7 @@ pub const Error = Allocator.Error || error { }; pub const SndFile = struct { - pimpl: *SNDFILE, + pimpl: *c.SNDFILE, frames: usize, sample_rate: c_int, channels: c_int, @@ -47,20 +47,21 @@ pub const SndFile = struct { /// Open the sound file at the specified path. pub fn open(path: [:0]const u8, mode: Mode) Error!SndFile { const c_mode = switch (mode) { - .read => SFM_READ, - .write => SFM_WRITE, - .read_write => SFM_RDWR, + .read => c.SFM_READ, + .write => c.SFM_WRITE, + .read_write => c.SFM_RDWR, }; - var info: SF_INFO = undefined; - const pimpl = sf_open(path.ptr, c_mode, &info); - _ = sf_command(pimpl, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE); + var info: c.SF_INFO = undefined; + const pimpl = c.sf_open(path.ptr, c_mode, &info); + _ = c.sf_command(pimpl, c.SFC_SET_SCALE_FLOAT_INT_READ, + null, c.SF_TRUE); return SndFile { - .pimpl = pimpl orelse return switch (sf_error(null)) { - SF_ERR_UNRECOGNISED_FORMAT => Error.UnrecognizedFormat, - SF_ERR_SYSTEM => Error.SystemError, - SF_ERR_MALFORMED_FILE => Error.MalformedFile, - SF_ERR_UNSUPPORTED_ENCODING => Error.UnsupportedEncoding, + .pimpl = pimpl orelse return switch (c.sf_error(null)) { + c.SF_ERR_UNRECOGNISED_FORMAT => Error.UnrecognizedFormat, + c.SF_ERR_SYSTEM => Error.SystemError, + c.SF_ERR_MALFORMED_FILE => Error.MalformedFile, + c.SF_ERR_UNSUPPORTED_ENCODING => Error.UnsupportedEncoding, else => unreachable, }, .frames = @intCast(usize, info.frames), @@ -74,17 +75,17 @@ pub const SndFile = struct { /// Read the requested number of frames. /// The returned memory is managed by the caller. - pub fn read(self: SndFile, allocator: *Allocator, + pub fn read(self: SndFile, allocator: Allocator, frames: usize) Error![]const i16 { const items = frames * @intCast(usize, self.channels); const memory = try allocator.alloc(i16, items); errdefer allocator.free(memory); - const n = sf_read_short(self.pimpl, memory.ptr, @intCast(i64, items)); + const n = c.sf_read_short(self.pimpl, memory.ptr, @intCast(i64, items)); return try allocator.realloc(memory, @intCast(usize, n)); } /// Read the entire file. The returned memory is managed by the caller. - pub fn readAll(self: SndFile, allocator: *Allocator) Error![]const i16 { + pub fn readAll(self: SndFile, allocator: Allocator) Error![]const i16 { return self.read(allocator, self.frames); } @@ -92,6 +93,6 @@ pub const SndFile = struct { /// Like std.os.close, this function does not return /// any indication of failure. pub fn close(self: SndFile) void { - assert(sf_close(self.pimpl) == 0); + assert(c.sf_close(self.pimpl) == 0); } }; diff --git a/src/zeal.zig b/src/zeal.zig index b3126ec..7dc82c5 100644 --- a/src/zeal.zig +++ b/src/zeal.zig @@ -99,12 +99,12 @@ pub const listener = struct { }; pub const Audio = struct { - allocator: *Allocator, + allocator: Allocator, data: al.Data, frequency: i32, /// Read audio from file. - pub fn read(allocator: *Allocator, path: [:0]const u8) sf.Error!Audio { + pub fn read(allocator: Allocator, path: [:0]const u8) sf.Error!Audio { const sound = try SndFile.open(path, sf.Mode.read); defer sound.close(); const data = try sound.readAll(allocator); |