From fe8614d4d6cb6586f831b19363ef3b857055591e Mon Sep 17 00:00:00 2001 From: alichraghi Date: Thu, 30 Jun 2022 20:31:54 +0430 Subject: [PATCH] audio: add soundio-sine-wave example --- audio/build.zig | 29 +++++++++++ audio/examples/soundio-sine-wave.zig | 77 ++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 audio/examples/soundio-sine-wave.zig diff --git a/audio/build.zig b/audio/build.zig index 07b7ba77..da5787fc 100644 --- a/audio/build.zig +++ b/audio/build.zig @@ -8,10 +8,16 @@ pub const pkg = std.build.Pkg{ .source = .{ .path = thisDir() ++ "/main.zig" }, }; +const soundio_pkg = std.build.Pkg{ + .name = "soundio", + .source = .{ .path = thisDir() ++ "/soundio/main.zig" }, +}; + pub const Options = struct {}; pub fn build(b: *Builder) void { const mode = b.standardReleaseOptions(); + const target = b.standardTargetOptions(.{}); const soundio_tests = b.addTest("soundio/main.zig"); soundio_tests.setBuildMode(mode); @@ -20,6 +26,29 @@ pub fn build(b: *Builder) void { const test_step = b.step("test", "Run library tests"); test_step.dependOn(&soundio_tests.step); + + inline for ([_][]const u8{ + "soundio-sine-wave", + }) |example| { + const example_exe = b.addExecutable("example-" ++ example, "examples/" ++ example ++ ".zig"); + example_exe.setBuildMode(mode); + example_exe.setTarget(target); + example_exe.addPackage(soundio_pkg); + link(b, example_exe, .{}); + example_exe.install(); + + const example_compile_step = b.step("example-" ++ example, "Compile '" ++ example ++ "' example"); + example_compile_step.dependOn(b.getInstallStep()); + + const example_run_cmd = example_exe.run(); + example_run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + example_run_cmd.addArgs(args); + } + + const example_run_step = b.step("run-example-" ++ example, "Run '" ++ example ++ "' example"); + example_run_step.dependOn(&example_run_cmd.step); + } } pub fn link(b: *Builder, step: *std.build.LibExeObjStep, options: Options) void { diff --git a/audio/examples/soundio-sine-wave.zig b/audio/examples/soundio-sine-wave.zig new file mode 100644 index 00000000..1f0da1ac --- /dev/null +++ b/audio/examples/soundio-sine-wave.zig @@ -0,0 +1,77 @@ +const std = @import("std"); +const soundio = @import("soundio"); +const c = soundio.c; +const SoundIo = soundio.SoundIo; +const OutStream = soundio.OutStream; + +var seconds_offset: f32 = 0; + +fn write_callback( + maybe_outstream: ?[*]c.SoundIoOutStream, + frame_count_min: c_int, + frame_count_max: c_int, +) callconv(.C) void { + _ = frame_count_min; + const outstream = OutStream{ .handle = @ptrCast(*c.SoundIoOutStream, maybe_outstream) }; + const layout = outstream.layout(); + const float_sample_rate = outstream.sampleRate(); + const seconds_per_frame = 1.0 / @intToFloat(f32, float_sample_rate); + var frames_left = frame_count_max; + + while (frames_left > 0) { + var frame_count = frames_left; + + var areas: [*]c.SoundIoChannelArea = undefined; + outstream.beginWrite( + @ptrCast([*]?[*]c.SoundIoChannelArea, &areas), + &frame_count, + ) catch |err| std.debug.panic("write failed: {s}", .{@errorName(err)}); + + if (frame_count == 0) break; + + const pitch = 440.0; + const radians_per_second = pitch * 2.0 * std.math.pi; + var frame: c_int = 0; + while (frame < frame_count) : (frame += 1) { + const sample = std.math.sin((seconds_offset + @intToFloat(f32, frame) * + seconds_per_frame) * radians_per_second); + { + var channel: usize = 0; + while (channel < @intCast(usize, layout.channelCount())) : (channel += 1) { + const channel_ptr = areas[channel].ptr; + const sample_ptr = &channel_ptr[@intCast(usize, areas[channel].step * frame)]; + @ptrCast(*f32, @alignCast(@alignOf(f32), sample_ptr)).* = sample; + } + } + } + seconds_offset += seconds_per_frame * @intToFloat(f32, frame_count); + outstream.endWrite() catch |err| std.debug.panic("end write failed: {s}", .{@errorName(err)}); + frames_left -= frame_count; + } +} + +pub fn main() !void { + const sio = try SoundIo.init(); + defer sio.deinit(); + try sio.connect(); + sio.flushEvents(); + + const default_output_index = sio.defaultOutputDeviceIndex().?; + if (default_output_index < 0) return error.NoOutputDeviceFound; + + const device = sio.getOutputDevice(default_output_index) orelse return error.OutOfMemory; + defer device.unref(); + + std.debug.print("Output device: {s}\n", .{device.name()}); + + const outstream = try device.createOutStream(); + defer outstream.deinit(); + + outstream.setFormat(.float32LE); + outstream.setWriteCallback(write_callback); + + try outstream.open(); + try outstream.start(); + + while (true) sio.waitEvents(); +}