summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--examples/hrtf.zig3
-rw-r--r--examples/play.zig5
-rw-r--r--src/al.zig73
-rw-r--r--src/sf.zig1
-rw-r--r--src/zeal.zig41
5 files changed, 89 insertions, 34 deletions
diff --git a/examples/hrtf.zig b/examples/hrtf.zig
index d90adff..2db3d78 100644
--- a/examples/hrtf.zig
+++ b/examples/hrtf.zig
@@ -56,7 +56,8 @@ pub fn main() !void {
     const source = try Source.init();
     defer source.deinit() catch unreachable;
     try source.setSpatialize(al.TRUE);
-    try source.play(buffer);
+    try source.bind(buffer);
+    try source.play();
     defer print("\n", .{});
     while (try source.isPlaying()) {
         const offset = try source.getSecOffset();
diff --git a/examples/play.zig b/examples/play.zig
index 2ad1db9..210972c 100644
--- a/examples/play.zig
+++ b/examples/play.zig
@@ -49,10 +49,11 @@ pub fn main() !void {
 
     const source = try Source.init();
     defer source.deinit() catch unreachable;
-    try source.play(buffer);
+    try source.bind(buffer);
+    try source.play();
     defer print("\n", .{});
     while (try source.isPlaying()) {
         sleep(10_000_000);
-        defer print("\r{d:.1} s", .{ source.getSecOffset() });
+        print("\r{d:.1} s", .{ source.getSecOffset() });
     }
 }
diff --git a/src/al.zig b/src/al.zig
index bbde02e..a5164d6 100644
--- a/src/al.zig
+++ b/src/al.zig
@@ -16,7 +16,9 @@
 // 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 Child = @import("std").meta.Child;
+const Child = meta.Child;
+const Tag = meta.Tag;
+const meta = @import("std").meta;
 
 usingnamespace @cImport({
     @cInclude("AL/al.h");
@@ -36,21 +38,23 @@ pub const Error = error {
     OutOfMemory,
 };
 
+// FIXME: turn into enum
 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 {
+    const Property = enum(ALenum) {
+        gain = AL_GAIN,
+        position = AL_POSITION,
+        velocity = AL_VELOCITY,
+        orientation = AL_ORIENTATION,
+        meters_per_unit = AL_METERS_PER_UNIT,
+    };
+
     /// Set a property for the listener.
-    pub fn set(param: ALenum, value: anytype) Error!void {
+    pub fn set(property: Property, value: anytype) Error!void {
+        const param = @enumToInt(property);
         const T = @TypeOf(value);
         switch (T) {
             f32 => alListenerf(param, value),
@@ -165,17 +169,42 @@ pub const source = struct {
         }
     }
 
+    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,
+    };
+
+    pub const State = enum(i32) {
+        initial = AL_INITIAL,
+        playing = AL_PLAYING,
+        paused = AL_PAUSED,
+        stopped = AL_STOPPED,
+    };
+
     /// Set a property for the source.
-    pub fn set(reference: u32, param: ALenum, value: anytype) Error!void {
+    pub fn set(reference: u32, property: Property, value: anytype) Error!void {
+        const param = @enumToInt(property);
         const T = @TypeOf(value);
         switch (T) {
             f32 => alSourcef(reference, param, value),
             i32 => alSourcei(reference, param, value),
-            else => switch (Child(T)) {
-                f32 => alSourcefv(reference, param, value[0..]),
-                i32 => alSourceiv(reference, param, value[0..]),
-                else => unreachable,
-            }
+            else => switch (@typeInfo(T)) {
+                .Enum => alSourcei(reference, param, @enumToInt(value)),
+                else => switch (Child(T)) {
+                    f32 => alSourcefv(reference, param, value[0..]),
+                    i32 => alSourceiv(reference, param, value[0..]),
+                    else => unreachable,
+                },
+            },
         }
 
         switch (alGetError()) {
@@ -189,12 +218,20 @@ pub const source = struct {
     }
 
     /// Get a scalar property from the source.
-    pub fn get(comptime T: type, reference: u32, param: ALenum) Error!T {
+    pub fn get(comptime T: type, reference: u32, property: Property) Error!T {
+        const param = @enumToInt(property);
         var value: T = undefined;
         switch (T) {
             f32 => alGetSourcef(reference, param, &value),
             i32 => alGetSourcei(reference, param, &value),
-            else => unreachable,
+            else => switch (@typeInfo(T)) {
+                .Enum => {
+                    var raw: i32 = undefined;
+                    alGetSourcei(reference, param, &raw);
+                    value = @intToEnum(T, raw);
+                },
+                else => unreachable,
+            },
         }
 
         return switch (alGetError()) {
diff --git a/src/sf.zig b/src/sf.zig
index dca1cec..80cfd9e 100644
--- a/src/sf.zig
+++ b/src/sf.zig
@@ -78,6 +78,7 @@ pub const SndFile = struct {
                 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));
         return try allocator.realloc(memory, @intCast(usize, n));
     }
diff --git a/src/zeal.zig b/src/zeal.zig
index 1749e28..b3126ec 100644
--- a/src/zeal.zig
+++ b/src/zeal.zig
@@ -80,13 +80,21 @@ pub const Context = struct {
 };
 
 pub const listener = struct {
+    pub fn setMetersPerUnit(factor: f32) Error!void {
+        try al.listener.set(.meters_per_unit, factor);
+    }
+
     pub fn setPosition(position: [3]f32) Error!void {
-        try al.listener.set(al.POSITION, position);
+        try al.listener.set(.position, position);
+    }
+
+    pub fn setVelocity(velocity: [3]f32) Error!void {
+        try al.listener.set(.velocity, velocity);
     }
 
     pub fn setOrientation(at: [3]f32, up: [3]f32) Error!void {
         const orientation = [_]f32{ at[0], at[1], at[2], up[0], up[1], up[2] };
-        try al.listener.set(al.ORIENTATION, orientation);
+        try al.listener.set(.orientation, orientation);
     }
 };
 
@@ -125,6 +133,7 @@ pub const Buffer = struct {
 
     pub fn init(audio: Audio) Error!Buffer {
         const reference = try al.buffer.create();
+        errdefer al.buffer.destroy(&reference) catch unreachable;
         try al.buffer.fill(reference, audio.data, audio.frequency);
         return Buffer{ .reference = reference };
     }
@@ -146,30 +155,36 @@ pub const Source = struct {
         try al.source.destroy(&self.reference);
     }
 
+    pub fn bind(self: Source, buffer: Buffer) Error!void {
+        try al.source.set(self.reference, .buffer,
+                          @intCast(i32, buffer.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 al.source.set(self.reference, al.SOURCE_SPATIALIZE, value);
+        try al.source.set(self.reference, .spatialize, value);
     }
 
-    pub fn setPosition(self: Source, position: [3]f32) Error!void {
-        try al.source.set(self.reference, al.POSITION, position);
+    fn getState(self: Source) Error!al.source.State {
+        return try al.source.get(al.source.State, self.reference, .state);
     }
 
     pub fn isPlaying(self: Source) Error!bool {
-        const state = try al.source.get(i32, self.reference, al.SOURCE_STATE);
-        return state == al.PLAYING;
+        return (try self.getState()) == .playing;
     }
 
-    pub fn getSecOffset(self: Source) Error!f32 {
-        return try al.source.get(f32, self.reference, al.SEC_OFFSET);
+    pub fn play(self: Source) Error!void {
+        try al.source.play(self.reference);
     }
 
-    pub fn play(self: Source, buffer: Buffer) Error!void {
-        try al.source.set(self.reference, al.BUFFER,
-                          @intCast(i32, buffer.reference));
-        try al.source.play(self.reference);
+    pub fn setPosition(self: Source, position: [3]f32) Error!void {
+        try al.source.set(self.reference, .position, position);
+    }
+
+    pub fn getSecOffset(self: Source) Error!f32 {
+        return try al.source.get(f32, self.reference, .sec_offset);
     }
 };