sysaudio: improve backend selection; remove i8 sample support (#767)
* sysaudio: fix compilation errors * re-order backend selection * remove i8 samples support from backends and disable signedToSigned convertion for now * update sine-wave example
This commit is contained in:
parent
8fbc36999f
commit
ed05166348
8 changed files with 64 additions and 89 deletions
|
|
@ -44,14 +44,13 @@ pub fn main() !void {
|
||||||
const pitch = 440.0;
|
const pitch = 440.0;
|
||||||
const radians_per_second = pitch * 2.0 * std.math.pi;
|
const radians_per_second = pitch * 2.0 * std.math.pi;
|
||||||
var seconds_offset: f32 = 0.0;
|
var seconds_offset: f32 = 0.0;
|
||||||
fn writeCallback(_: ?*anyopaque, n_frame: usize) void {
|
fn writeCallback(_: ?*anyopaque, frames: usize) void {
|
||||||
const seconds_per_frame = 1.0 / @intToFloat(f32, player.sampleRate());
|
const seconds_per_frame = 1.0 / @intToFloat(f32, player.sampleRate());
|
||||||
var frame: usize = 0;
|
for (0..frames) |fi| {
|
||||||
while (frame < n_frame) : (frame += 1) {
|
const sample = std.math.sin((seconds_offset + @intToFloat(f32, fi) * seconds_per_frame) * radians_per_second);
|
||||||
const sample = std.math.sin((seconds_offset + @intToFloat(f32, frame) * seconds_per_frame) * radians_per_second);
|
player.writeAll(fi, sample);
|
||||||
player.writeAll(frame, sample);
|
|
||||||
}
|
}
|
||||||
seconds_offset = @mod(seconds_offset + seconds_per_frame * @intToFloat(f32, n_frame), 1.0);
|
seconds_offset = @mod(seconds_offset + seconds_per_frame * @intToFloat(f32, frames), 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deviceChange(_: ?*anyopaque) void {
|
fn deviceChange(_: ?*anyopaque) void {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,9 @@ pub fn Sdk(comptime deps: anytype) type {
|
||||||
_module = b.createModule(.{
|
_module = b.createModule(.{
|
||||||
.source_file = .{ .path = sdkPath("/src/main.zig") },
|
.source_file = .{ .path = sdkPath("/src/main.zig") },
|
||||||
.dependencies = &.{
|
.dependencies = &.{
|
||||||
.{ .name = "sysjs", .module = deps.sysjs.module(b) },
|
.{ .name = "sysjs", .module = b.createModule(.{
|
||||||
|
.source_file = .{ .path = "libs/mach-sysjs/src/main.zig" },
|
||||||
|
}) },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return _module.?;
|
return _module.?;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ const lib = struct {
|
||||||
var snd_pcm_state: *const fn (?*c.snd_pcm_t) callconv(.C) c.snd_pcm_state_t = undefined;
|
var snd_pcm_state: *const fn (?*c.snd_pcm_t) callconv(.C) c.snd_pcm_state_t = undefined;
|
||||||
var snd_pcm_pause: *const fn (?*c.snd_pcm_t, c_int) callconv(.C) c_int = undefined;
|
var snd_pcm_pause: *const fn (?*c.snd_pcm_t, c_int) callconv(.C) c_int = undefined;
|
||||||
var snd_pcm_writei: *const fn (?*c.snd_pcm_t, ?*const anyopaque, c.snd_pcm_uframes_t) callconv(.C) c.snd_pcm_sframes_t = undefined;
|
var snd_pcm_writei: *const fn (?*c.snd_pcm_t, ?*const anyopaque, c.snd_pcm_uframes_t) callconv(.C) c.snd_pcm_sframes_t = undefined;
|
||||||
var snd_pcm_recover: *const fn (?*c.snd_pcm_t, c_int, c_int) callconv(.C) c_int = undefined;
|
var snd_pcm_prepare: *const fn (?*c.snd_pcm_t) callconv(.C) c_int = undefined;
|
||||||
var snd_pcm_info_set_device: *const fn (?*c.snd_pcm_info_t, c_uint) callconv(.C) void = undefined;
|
var snd_pcm_info_set_device: *const fn (?*c.snd_pcm_info_t, c_uint) callconv(.C) void = undefined;
|
||||||
var snd_pcm_info_set_subdevice: *const fn (?*c.snd_pcm_info_t, c_uint) callconv(.C) void = undefined;
|
var snd_pcm_info_set_subdevice: *const fn (?*c.snd_pcm_info_t, c_uint) callconv(.C) void = undefined;
|
||||||
var snd_pcm_info_get_name: *const fn (?*const c.snd_pcm_info_t) callconv(.C) [*c]const u8 = undefined;
|
var snd_pcm_info_get_name: *const fn (?*const c.snd_pcm_info_t) callconv(.C) [*c]const u8 = undefined;
|
||||||
|
|
@ -71,7 +71,7 @@ const lib = struct {
|
||||||
snd_pcm_state = handle.lookup(@TypeOf(snd_pcm_state), "snd_pcm_state") orelse return error.SymbolLookup;
|
snd_pcm_state = handle.lookup(@TypeOf(snd_pcm_state), "snd_pcm_state") orelse return error.SymbolLookup;
|
||||||
snd_pcm_pause = handle.lookup(@TypeOf(snd_pcm_pause), "snd_pcm_pause") orelse return error.SymbolLookup;
|
snd_pcm_pause = handle.lookup(@TypeOf(snd_pcm_pause), "snd_pcm_pause") orelse return error.SymbolLookup;
|
||||||
snd_pcm_writei = handle.lookup(@TypeOf(snd_pcm_writei), "snd_pcm_writei") orelse return error.SymbolLookup;
|
snd_pcm_writei = handle.lookup(@TypeOf(snd_pcm_writei), "snd_pcm_writei") orelse return error.SymbolLookup;
|
||||||
snd_pcm_recover = handle.lookup(@TypeOf(snd_pcm_recover), "snd_pcm_recover") orelse return error.SymbolLookup;
|
snd_pcm_prepare = handle.lookup(@TypeOf(snd_pcm_prepare), "snd_pcm_prepare") orelse return error.SymbolLookup;
|
||||||
snd_pcm_info_set_device = handle.lookup(@TypeOf(snd_pcm_info_set_device), "snd_pcm_info_set_device") orelse return error.SymbolLookup;
|
snd_pcm_info_set_device = handle.lookup(@TypeOf(snd_pcm_info_set_device), "snd_pcm_info_set_device") orelse return error.SymbolLookup;
|
||||||
snd_pcm_info_set_subdevice = handle.lookup(@TypeOf(snd_pcm_info_set_subdevice), "snd_pcm_info_set_subdevice") orelse return error.SymbolLookup;
|
snd_pcm_info_set_subdevice = handle.lookup(@TypeOf(snd_pcm_info_set_subdevice), "snd_pcm_info_set_subdevice") orelse return error.SymbolLookup;
|
||||||
snd_pcm_info_get_name = handle.lookup(@TypeOf(snd_pcm_info_get_name), "snd_pcm_info_get_name") orelse return error.SymbolLookup;
|
snd_pcm_info_get_name = handle.lookup(@TypeOf(snd_pcm_info_get_name), "snd_pcm_info_get_name") orelse return error.SymbolLookup;
|
||||||
|
|
@ -402,10 +402,7 @@ pub const Context = struct {
|
||||||
|
|
||||||
var fmt_arr = std.ArrayList(main.Format).init(self.allocator);
|
var fmt_arr = std.ArrayList(main.Format).init(self.allocator);
|
||||||
inline for (std.meta.tags(main.Format)) |format| {
|
inline for (std.meta.tags(main.Format)) |format| {
|
||||||
if (lib.snd_pcm_format_mask_test(
|
if (lib.snd_pcm_format_mask_test(fmt_mask, toAlsaFormat(format)) != 0) {
|
||||||
fmt_mask,
|
|
||||||
toAlsaFormat(format) catch unreachable,
|
|
||||||
) != 0) {
|
|
||||||
try fmt_arr.append(format);
|
try fmt_arr.append(format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -465,7 +462,7 @@ pub const Context = struct {
|
||||||
|
|
||||||
if ((lib.snd_pcm_set_params(
|
if ((lib.snd_pcm_set_params(
|
||||||
pcm,
|
pcm,
|
||||||
toAlsaFormat(format) catch unreachable,
|
toAlsaFormat(format),
|
||||||
c.SND_PCM_ACCESS_RW_INTERLEAVED,
|
c.SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||||
@intCast(c_uint, device.channels.len),
|
@intCast(c_uint, device.channels.len),
|
||||||
sample_rate,
|
sample_rate,
|
||||||
|
|
@ -584,19 +581,16 @@ pub const Player = struct {
|
||||||
ch.*.ptr = self.sample_buffer.ptr + self.format.frameSize(i);
|
ch.*.ptr = self.sample_buffer.ptr + self.format.frameSize(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var underrun = false;
|
||||||
while (!self.aborted.load(.Unordered)) {
|
while (!self.aborted.load(.Unordered)) {
|
||||||
var frames_left = self.period_size;
|
if (!underrun) {
|
||||||
while (frames_left > 0) {
|
self.writeFn(self.user_data, self.period_size);
|
||||||
self.writeFn(self.user_data, frames_left);
|
}
|
||||||
const n = lib.snd_pcm_writei(self.pcm, self.sample_buffer.ptr, frames_left);
|
underrun = false;
|
||||||
if (n < 0) {
|
const n = lib.snd_pcm_writei(self.pcm, self.sample_buffer.ptr, self.period_size);
|
||||||
if (lib.snd_pcm_recover(self.pcm, @intCast(c_int, n), 1) < 0) {
|
if (n < 0) {
|
||||||
if (std.debug.runtime_safety) unreachable;
|
_ = lib.snd_pcm_prepare(self.pcm);
|
||||||
return;
|
underrun = true;
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
frames_left -= @intCast(c_uint, n);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -676,10 +670,9 @@ pub fn modeToStream(mode: main.Device.Mode) c_uint {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toAlsaFormat(format: main.Format) !c.snd_pcm_format_t {
|
pub fn toAlsaFormat(format: main.Format) c.snd_pcm_format_t {
|
||||||
return switch (format) {
|
return switch (format) {
|
||||||
.u8 => c.SND_PCM_FORMAT_U8,
|
.u8 => c.SND_PCM_FORMAT_U8,
|
||||||
.i8 => c.SND_PCM_FORMAT_S8,
|
|
||||||
.i16 => if (is_little) c.SND_PCM_FORMAT_S16_LE else c.SND_PCM_FORMAT_S16_BE,
|
.i16 => if (is_little) c.SND_PCM_FORMAT_S16_LE else c.SND_PCM_FORMAT_S16_BE,
|
||||||
.i24 => if (is_little) c.SND_PCM_FORMAT_S24_3LE else c.SND_PCM_FORMAT_S24_3BE,
|
.i24 => if (is_little) c.SND_PCM_FORMAT_S24_3LE else c.SND_PCM_FORMAT_S24_3BE,
|
||||||
.i24_4b => if (is_little) c.SND_PCM_FORMAT_S24_LE else c.SND_PCM_FORMAT_S24_BE,
|
.i24_4b => if (is_little) c.SND_PCM_FORMAT_S24_LE else c.SND_PCM_FORMAT_S24_BE,
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@ const std = @import("std");
|
||||||
pub const Backend = std.meta.Tag(BackendContext);
|
pub const Backend = std.meta.Tag(BackendContext);
|
||||||
pub const BackendContext = switch (builtin.os.tag) {
|
pub const BackendContext = switch (builtin.os.tag) {
|
||||||
.linux => union(enum) {
|
.linux => union(enum) {
|
||||||
pulseaudio: *@import("pulseaudio.zig").Context,
|
|
||||||
jack: *@import("jack.zig").Context,
|
|
||||||
pipewire: *@import("pipewire.zig").Context,
|
|
||||||
alsa: *@import("alsa.zig").Context,
|
alsa: *@import("alsa.zig").Context,
|
||||||
|
pipewire: *@import("pipewire.zig").Context,
|
||||||
|
jack: *@import("jack.zig").Context,
|
||||||
|
pulseaudio: *@import("pulseaudio.zig").Context,
|
||||||
dummy: *@import("dummy.zig").Context,
|
dummy: *@import("dummy.zig").Context,
|
||||||
},
|
},
|
||||||
.freebsd, .netbsd, .openbsd, .solaris => union(enum) {
|
.freebsd, .netbsd, .openbsd, .solaris => union(enum) {
|
||||||
pulseaudio: *@import("pulseaudio.zig").Context,
|
|
||||||
jack: *@import("jack.zig").Context,
|
|
||||||
pipewire: *@import("pipewire.zig").Context,
|
pipewire: *@import("pipewire.zig").Context,
|
||||||
|
jack: *@import("jack.zig").Context,
|
||||||
|
pulseaudio: *@import("pulseaudio.zig").Context,
|
||||||
dummy: *@import("dummy.zig").Context,
|
dummy: *@import("dummy.zig").Context,
|
||||||
},
|
},
|
||||||
.macos, .ios, .watchos, .tvos => union(enum) {
|
.macos, .ios, .watchos, .tvos => union(enum) {
|
||||||
|
|
@ -39,16 +39,16 @@ pub const BackendContext = switch (builtin.os.tag) {
|
||||||
};
|
};
|
||||||
pub const BackendPlayer = switch (builtin.os.tag) {
|
pub const BackendPlayer = switch (builtin.os.tag) {
|
||||||
.linux => union(enum) {
|
.linux => union(enum) {
|
||||||
pulseaudio: *@import("pulseaudio.zig").Player,
|
|
||||||
jack: *@import("jack.zig").Player,
|
|
||||||
pipewire: *@import("pipewire.zig").Player,
|
|
||||||
alsa: *@import("alsa.zig").Player,
|
alsa: *@import("alsa.zig").Player,
|
||||||
|
pipewire: *@import("pipewire.zig").Player,
|
||||||
|
jack: *@import("jack.zig").Player,
|
||||||
|
pulseaudio: *@import("pulseaudio.zig").Player,
|
||||||
dummy: *@import("dummy.zig").Player,
|
dummy: *@import("dummy.zig").Player,
|
||||||
},
|
},
|
||||||
.freebsd, .netbsd, .openbsd, .solaris => union(enum) {
|
.freebsd, .netbsd, .openbsd, .solaris => union(enum) {
|
||||||
pulseaudio: *@import("pulseaudio.zig").Player,
|
|
||||||
jack: *@import("jack.zig").Player,
|
|
||||||
pipewire: *@import("pipewire.zig").Player,
|
pipewire: *@import("pipewire.zig").Player,
|
||||||
|
jack: *@import("jack.zig").Player,
|
||||||
|
pulseaudio: *@import("pulseaudio.zig").Player,
|
||||||
dummy: *@import("dummy.zig").Player,
|
dummy: *@import("dummy.zig").Player,
|
||||||
},
|
},
|
||||||
.macos, .ios, .watchos, .tvos => union(enum) {
|
.macos, .ios, .watchos, .tvos => union(enum) {
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,7 @@ pub const Context = struct {
|
||||||
return error.OpeningDevice;
|
return error.OpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stream_desc = createStreamDesc(options.format, options.sample_rate, device.channels.len);
|
const stream_desc = try createStreamDesc(options.format, options.sample_rate, device.channels.len);
|
||||||
if (c.AudioUnitSetProperty(
|
if (c.AudioUnitSetProperty(
|
||||||
audio_unit,
|
audio_unit,
|
||||||
c.kAudioUnitProperty_StreamFormat,
|
c.kAudioUnitProperty_StreamFormat,
|
||||||
|
|
@ -487,7 +487,6 @@ fn createStreamDesc(format: main.Format, sample_rate: u24, ch_count: usize) !c.A
|
||||||
.mSampleRate = @intToFloat(f64, sample_rate),
|
.mSampleRate = @intToFloat(f64, sample_rate),
|
||||||
.mFormatID = c.kAudioFormatLinearPCM,
|
.mFormatID = c.kAudioFormatLinearPCM,
|
||||||
.mFormatFlags = switch (format) {
|
.mFormatFlags = switch (format) {
|
||||||
.i8 => c.kAudioFormatFlagIsSignedInteger,
|
|
||||||
.i16 => c.kAudioFormatFlagIsSignedInteger,
|
.i16 => c.kAudioFormatFlagIsSignedInteger,
|
||||||
.i24 => c.kAudioFormatFlagIsSignedInteger,
|
.i24 => c.kAudioFormatFlagIsSignedInteger,
|
||||||
.i32 => c.kAudioFormatFlagIsSignedInteger,
|
.i32 => c.kAudioFormatFlagIsSignedInteger,
|
||||||
|
|
@ -500,7 +499,6 @@ fn createStreamDesc(format: main.Format, sample_rate: u24, ch_count: usize) !c.A
|
||||||
.mBytesPerFrame = format.frameSize(ch_count),
|
.mBytesPerFrame = format.frameSize(ch_count),
|
||||||
.mChannelsPerFrame = @intCast(c_uint, ch_count),
|
.mChannelsPerFrame = @intCast(c_uint, ch_count),
|
||||||
.mBitsPerChannel = switch (format) {
|
.mBitsPerChannel = switch (format) {
|
||||||
.i8 => 8,
|
|
||||||
.i16 => 16,
|
.i16 => 16,
|
||||||
.i24 => 24,
|
.i24 => 24,
|
||||||
.i32 => 32,
|
.i32 => 32,
|
||||||
|
|
|
||||||
|
|
@ -213,24 +213,17 @@ pub const Player = struct {
|
||||||
f32 => floatToUnsigned(u8, sample),
|
f32 => floatToUnsigned(u8, sample),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
.i8 => std.mem.bytesAsValue(i8, ptr[0..@sizeOf(i8)]).* = switch (@TypeOf(sample)) {
|
|
||||||
i8 => sample,
|
|
||||||
u8 => unsignedToSigned(i8, sample),
|
|
||||||
i16, i24, i32 => signedToSigned(i8, sample),
|
|
||||||
f32 => floatToSigned(i8, sample),
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.i16 => std.mem.bytesAsValue(i16, ptr[0..@sizeOf(i16)]).* = switch (@TypeOf(sample)) {
|
.i16 => std.mem.bytesAsValue(i16, ptr[0..@sizeOf(i16)]).* = switch (@TypeOf(sample)) {
|
||||||
i16 => sample,
|
i16 => sample,
|
||||||
u8 => unsignedToSigned(i16, sample),
|
u8 => unsignedToSigned(i16, sample),
|
||||||
i8, i24, i32 => signedToSigned(i16, sample),
|
// i8, i24, i32 => signedToSigned(i16, sample),
|
||||||
f32 => floatToSigned(i16, sample),
|
f32 => floatToSigned(i16, sample),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
.i24 => std.mem.bytesAsValue(i24, ptr[0..@sizeOf(i24)]).* = switch (@TypeOf(sample)) {
|
.i24 => std.mem.bytesAsValue(i24, ptr[0..@sizeOf(i24)]).* = switch (@TypeOf(sample)) {
|
||||||
i24 => sample,
|
i24 => sample,
|
||||||
u8 => unsignedToSigned(i24, sample),
|
u8 => unsignedToSigned(i24, sample),
|
||||||
i8, i16, i32 => signedToSigned(i24, sample),
|
// i8, i16, i32 => signedToSigned(i24, sample),
|
||||||
f32 => floatToSigned(i24, sample),
|
f32 => floatToSigned(i24, sample),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
|
|
@ -238,7 +231,7 @@ pub const Player = struct {
|
||||||
.i32 => std.mem.bytesAsValue(i32, ptr[0..@sizeOf(i32)]).* = switch (@TypeOf(sample)) {
|
.i32 => std.mem.bytesAsValue(i32, ptr[0..@sizeOf(i32)]).* = switch (@TypeOf(sample)) {
|
||||||
i32 => sample,
|
i32 => sample,
|
||||||
u8 => unsignedToSigned(i32, sample),
|
u8 => unsignedToSigned(i32, sample),
|
||||||
i8, i16, i24 => signedToSigned(i32, sample),
|
// i8, i16, i24 => signedToSigned(i32, sample),
|
||||||
f32 => floatToSigned(i32, sample),
|
f32 => floatToSigned(i32, sample),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
|
|
@ -377,7 +370,6 @@ pub const Channel = struct {
|
||||||
|
|
||||||
pub const Format = enum {
|
pub const Format = enum {
|
||||||
u8,
|
u8,
|
||||||
i8,
|
|
||||||
i16,
|
i16,
|
||||||
i24,
|
i24,
|
||||||
i24_4b,
|
i24_4b,
|
||||||
|
|
@ -386,7 +378,7 @@ pub const Format = enum {
|
||||||
|
|
||||||
pub fn size(self: Format) u8 {
|
pub fn size(self: Format) u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.u8, .i8 => 1,
|
.u8 => 1,
|
||||||
.i16 => 2,
|
.i16 => 2,
|
||||||
.i24 => 3,
|
.i24 => 3,
|
||||||
.i24_4b, .i32, .f32 => 4,
|
.i24_4b, .i32, .f32 => 4,
|
||||||
|
|
@ -395,7 +387,7 @@ pub const Format = enum {
|
||||||
|
|
||||||
pub fn validSize(self: Format) u8 {
|
pub fn validSize(self: Format) u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.u8, .i8 => 1,
|
.u8 => 1,
|
||||||
.i16 => 2,
|
.i16 => 2,
|
||||||
.i24, .i24_4b => 3,
|
.i24, .i24_4b => 3,
|
||||||
.i32, .f32 => 4,
|
.i32, .f32 => 4,
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,7 @@ pub const Context = struct {
|
||||||
const sample_rate = device.sample_rate.clamp(options.sample_rate);
|
const sample_rate = device.sample_rate.clamp(options.sample_rate);
|
||||||
|
|
||||||
const sample_spec = c.pa_sample_spec{
|
const sample_spec = c.pa_sample_spec{
|
||||||
.format = toPAFormat(format) catch unreachable,
|
.format = toPAFormat(format),
|
||||||
.rate = sample_rate,
|
.rate = sample_rate,
|
||||||
.channels = @intCast(u5, device.channels.len),
|
.channels = @intCast(u5, device.channels.len),
|
||||||
};
|
};
|
||||||
|
|
@ -459,33 +459,28 @@ pub const Player = struct {
|
||||||
var self = @ptrCast(*Player, @alignCast(@alignOf(*Player), user_data.?));
|
var self = @ptrCast(*Player, @alignCast(@alignOf(*Player), user_data.?));
|
||||||
|
|
||||||
var frames_left = nbytes;
|
var frames_left = nbytes;
|
||||||
while (frames_left > 0) {
|
if (lib.pa_stream_begin_write(
|
||||||
var chunk_size = frames_left;
|
self.stream,
|
||||||
if (lib.pa_stream_begin_write(
|
@ptrCast(
|
||||||
self.stream,
|
[*c]?*anyopaque,
|
||||||
@ptrCast(
|
@alignCast(@alignOf([*c]?*anyopaque), &self.write_ptr),
|
||||||
[*c]?*anyopaque,
|
),
|
||||||
@alignCast(@alignOf([*c]?*anyopaque), &self.write_ptr),
|
&frames_left,
|
||||||
),
|
) != 0) {
|
||||||
&chunk_size,
|
if (std.debug.runtime_safety) unreachable;
|
||||||
) != 0) {
|
return;
|
||||||
if (std.debug.runtime_safety) unreachable;
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (self.channels, 0..) |*ch, i| {
|
for (self.channels, 0..) |*ch, i| {
|
||||||
ch.*.ptr = self.write_ptr + self.format.frameSize(i);
|
ch.*.ptr = self.write_ptr + self.format.frameSize(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
const frames = chunk_size / self.format.frameSize(self.channels.len);
|
const frames = frames_left / self.format.frameSize(self.channels.len);
|
||||||
self.writeFn(self.user_data, frames);
|
self.writeFn(self.user_data, frames);
|
||||||
|
|
||||||
if (lib.pa_stream_write(self.stream, self.write_ptr, chunk_size, null, 0, c.PA_SEEK_RELATIVE) != 0) {
|
if (lib.pa_stream_write(self.stream, self.write_ptr, frames_left, null, 0, c.PA_SEEK_RELATIVE) != 0) {
|
||||||
if (std.debug.runtime_safety) unreachable;
|
if (std.debug.runtime_safety) unreachable;
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
frames_left -= chunk_size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -616,7 +611,7 @@ pub fn fromPAChannelPos(pos: c.pa_channel_position_t) !main.Channel.Id {
|
||||||
c.PA_CHANNEL_POSITION_SIDE_RIGHT => .side_right,
|
c.PA_CHANNEL_POSITION_SIDE_RIGHT => .side_right,
|
||||||
|
|
||||||
// TODO: .front_center?
|
// TODO: .front_center?
|
||||||
c.PA_CHANNEL_POSITION_AUX0...c.PA_CHANNEL_POSITION_AUX31 => error.Invalid,
|
c.PA_CHANNEL_POSITION_AUX0...c.PA_CHANNEL_POSITION_AUX31 => .front_center,
|
||||||
|
|
||||||
c.PA_CHANNEL_POSITION_TOP_CENTER => .top_center,
|
c.PA_CHANNEL_POSITION_TOP_CENTER => .top_center,
|
||||||
c.PA_CHANNEL_POSITION_TOP_FRONT_LEFT => .top_front_left,
|
c.PA_CHANNEL_POSITION_TOP_FRONT_LEFT => .top_front_left,
|
||||||
|
|
@ -630,7 +625,7 @@ pub fn fromPAChannelPos(pos: c.pa_channel_position_t) !main.Channel.Id {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toPAFormat(format: main.Format) !c.pa_sample_format_t {
|
pub fn toPAFormat(format: main.Format) c.pa_sample_format_t {
|
||||||
return switch (format) {
|
return switch (format) {
|
||||||
.u8 => c.PA_SAMPLE_U8,
|
.u8 => c.PA_SAMPLE_U8,
|
||||||
.i16 => if (is_little) c.PA_SAMPLE_S16LE else c.PA_SAMPLE_S16BE,
|
.i16 => if (is_little) c.PA_SAMPLE_S16LE else c.PA_SAMPLE_S16BE,
|
||||||
|
|
@ -638,8 +633,6 @@ pub fn toPAFormat(format: main.Format) !c.pa_sample_format_t {
|
||||||
.i24_4b => if (is_little) c.PA_SAMPLE_S24_32LE else c.PA_SAMPLE_S24_32BE,
|
.i24_4b => if (is_little) c.PA_SAMPLE_S24_32LE else c.PA_SAMPLE_S24_32BE,
|
||||||
.i32 => if (is_little) c.PA_SAMPLE_S32LE else c.PA_SAMPLE_S32BE,
|
.i32 => if (is_little) c.PA_SAMPLE_S32LE else c.PA_SAMPLE_S32BE,
|
||||||
.f32 => if (is_little) c.PA_SAMPLE_FLOAT32LE else c.PA_SAMPLE_FLOAT32BE,
|
.f32 => if (is_little) c.PA_SAMPLE_FLOAT32LE else c.PA_SAMPLE_FLOAT32BE,
|
||||||
|
|
||||||
.i8 => error.Invalid,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,7 @@ pub const Context = struct {
|
||||||
var fmt_arr = std.ArrayList(main.Format).init(self.allocator);
|
var fmt_arr = std.ArrayList(main.Format).init(self.allocator);
|
||||||
var closest_match: ?*win32.WAVEFORMATEX = null;
|
var closest_match: ?*win32.WAVEFORMATEX = null;
|
||||||
for (std.meta.tags(main.Format)) |format| {
|
for (std.meta.tags(main.Format)) |format| {
|
||||||
setWaveFormatFormat(wf, format) catch continue;
|
setWaveFormatFormat(wf, format);
|
||||||
if (audio_client.?.IsFormatSupported(
|
if (audio_client.?.IsFormatSupported(
|
||||||
.SHARED,
|
.SHARED,
|
||||||
@ptrCast(?*const win32.WAVEFORMATEX, @alignCast(@alignOf(*win32.WAVEFORMATEX), wf)),
|
@ptrCast(?*const win32.WAVEFORMATEX, @alignCast(@alignOf(*win32.WAVEFORMATEX), wf)),
|
||||||
|
|
@ -417,7 +417,7 @@ pub const Context = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setWaveFormatFormat(wf: *win32.WAVEFORMATEXTENSIBLE, format: main.Format) !void {
|
fn setWaveFormatFormat(wf: *win32.WAVEFORMATEXTENSIBLE, format: main.Format) void {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
.u8, .i16, .i24, .i24_4b, .i32 => {
|
.u8, .i16, .i24, .i24_4b, .i32 => {
|
||||||
wf.SubFormat = win32.CLSID_KSDATAFORMAT_SUBTYPE_PCM.*;
|
wf.SubFormat = win32.CLSID_KSDATAFORMAT_SUBTYPE_PCM.*;
|
||||||
|
|
@ -425,7 +425,6 @@ pub const Context = struct {
|
||||||
.f32 => {
|
.f32 => {
|
||||||
wf.SubFormat = win32.CLSID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT.*;
|
wf.SubFormat = win32.CLSID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT.*;
|
||||||
},
|
},
|
||||||
.i8 => return error.Invalid,
|
|
||||||
}
|
}
|
||||||
wf.Format.wBitsPerSample = format.sizeBits();
|
wf.Format.wBitsPerSample = format.sizeBits();
|
||||||
wf.Samples.wValidBitsPerSample = format.validSizeBits();
|
wf.Samples.wValidBitsPerSample = format.validSizeBits();
|
||||||
|
|
@ -488,7 +487,7 @@ pub const Context = struct {
|
||||||
.wValidBitsPerSample = format.validSizeBits(),
|
.wValidBitsPerSample = format.validSizeBits(),
|
||||||
},
|
},
|
||||||
.dwChannelMask = toChannelMask(device.channels),
|
.dwChannelMask = toChannelMask(device.channels),
|
||||||
.SubFormat = toSubFormat(format) catch return error.OpeningDevice,
|
.SubFormat = toSubFormat(format),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!self.is_wine and audio_client3 != null) {
|
if (!self.is_wine and audio_client3 != null) {
|
||||||
|
|
@ -608,7 +607,7 @@ pub const Context = struct {
|
||||||
return .{ .wasapi = player };
|
return .{ .wasapi = player };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toSubFormat(format: main.Format) !win32.Guid {
|
fn toSubFormat(format: main.Format) win32.Guid {
|
||||||
return switch (format) {
|
return switch (format) {
|
||||||
.u8,
|
.u8,
|
||||||
.i16,
|
.i16,
|
||||||
|
|
@ -617,7 +616,6 @@ pub const Context = struct {
|
||||||
.i32,
|
.i32,
|
||||||
=> win32.CLSID_KSDATAFORMAT_SUBTYPE_PCM.*,
|
=> win32.CLSID_KSDATAFORMAT_SUBTYPE_PCM.*,
|
||||||
.f32 => win32.CLSID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT.*,
|
.f32 => win32.CLSID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT.*,
|
||||||
else => error.Invalid,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue