game-2026-01-30/libs/stb/src/stb_vorbis.zig
2026-01-30 23:28:18 +02:00

171 lines
5.0 KiB
Zig

const std = @import("std");
const assert = std.debug.assert;
const log = std.log.scoped(.stb_vorbis);
const c = @cImport({
@cDefine("STB_VORBIS_NO_INTEGER_CONVERSION", {});
@cDefine("STB_VORBIS_NO_STDIO", {});
@cDefine("STB_VORBIS_HEADER_ONLY", {});
@cInclude("stb_vorbis.c");
});
const STBVorbis = @This();
pub const Error = error {
NeedMoreData,
InvalidApiMixing,
OutOfMemory,
FeatureNotSupported,
TooManyChannels,
FileOpenFailure,
SeekWithoutLength,
UnexpectedEof,
SeekInvalid,
InvalidSetup,
InvalidStream,
MissingCapturePattern,
InvalidStreamStructureVersion,
ContinuedPacketFlagInvalid,
IncorrectStreamSerialNumber,
InvalidFirstPage,
BadPacketType,
CantFindLastPage,
SeekFailed,
OggSkeletonNotSupported,
Unknown
};
fn errorFromInt(err: c_int) ?Error {
return switch (err) {
c.VORBIS__no_error => null,
c.VORBIS_need_more_data => Error.NeedMoreData,
c.VORBIS_invalid_api_mixing => Error.InvalidApiMixing,
c.VORBIS_outofmem => Error.OutOfMemory,
c.VORBIS_feature_not_supported => Error.FeatureNotSupported,
c.VORBIS_too_many_channels => Error.TooManyChannels,
c.VORBIS_file_open_failure => Error.FileOpenFailure,
c.VORBIS_seek_without_length => Error.SeekWithoutLength,
c.VORBIS_unexpected_eof => Error.UnexpectedEof,
c.VORBIS_seek_invalid => Error.SeekInvalid,
c.VORBIS_invalid_setup => Error.InvalidSetup,
c.VORBIS_invalid_stream => Error.InvalidStream,
c.VORBIS_missing_capture_pattern => Error.MissingCapturePattern,
c.VORBIS_invalid_stream_structure_version => Error.InvalidStreamStructureVersion,
c.VORBIS_continued_packet_flag_invalid => Error.ContinuedPacketFlagInvalid,
c.VORBIS_incorrect_stream_serial_number => Error.IncorrectStreamSerialNumber,
c.VORBIS_invalid_first_page => Error.InvalidFirstPage,
c.VORBIS_bad_packet_type => Error.BadPacketType,
c.VORBIS_cant_find_last_page => Error.CantFindLastPage,
c.VORBIS_seek_failed => Error.SeekFailed,
c.VORBIS_ogg_skeleton_not_supported => Error.OggSkeletonNotSupported,
else => Error.Unknown
};
}
handle: *c.stb_vorbis,
pub fn init(data: []const u8, alloc_buffer: []u8) Error!STBVorbis {
const stb_vorbis_alloc: c.stb_vorbis_alloc = .{
.alloc_buffer = alloc_buffer.ptr,
.alloc_buffer_length_in_bytes = @intCast(alloc_buffer.len)
};
var error_code: c_int = -1;
const handle = c.stb_vorbis_open_memory(
data.ptr,
@intCast(data.len),
&error_code,
&stb_vorbis_alloc
);
if (handle == null) {
return errorFromInt(error_code) orelse Error.Unknown;
}
return STBVorbis{
.handle = handle.?
};
}
pub fn getMinimumAllocBufferSize(self: STBVorbis) u32 {
const info = self.getInfo();
return info.setup_memory_required + @max(info.setup_temp_memory_required, info.temp_memory_required);
}
fn getLastError(self: STBVorbis) ?Error {
const error_code = c.stb_vorbis_get_error(self.handle);
return errorFromInt(error_code);
}
pub fn seek(self: STBVorbis, sample_number: u32) !void {
const success = c.stb_vorbis_seek(self.handle, sample_number);
if (success != 1) {
return self.getLastError() orelse Error.Unknown;
}
}
pub fn getStreamLengthInSamples(self: STBVorbis) u32 {
return c.stb_vorbis_stream_length_in_samples(self.handle);
}
pub fn getStreamLengthInSeconds(self: STBVorbis) f32 {
return c.stb_vorbis_stream_length_in_seconds(self.handle);
}
pub fn getSamples(
self: STBVorbis,
channels: []const [*]f32,
max_samples_per_channel: u32
) u32 {
const samples_per_channel = c.stb_vorbis_get_samples_float(
self.handle,
@intCast(channels.len),
@constCast(@ptrCast(channels.ptr)),
@intCast(max_samples_per_channel)
);
return @intCast(samples_per_channel);
}
const Frame = struct {
channels: []const [*c]const f32,
samples_per_channel: u32
};
pub fn getFrame(self: STBVorbis) Frame {
var output: [*c][*c]f32 = null;
var channels: c_int = undefined;
const samples_per_channel = c.stb_vorbis_get_frame_float(
self.handle,
&channels,
&output
);
return Frame{
.channels = output[0..@intCast(channels)],
.samples_per_channel = @intCast(samples_per_channel)
};
}
pub const Info = struct {
sample_rate: u32,
channels: u32,
setup_memory_required: u32,
setup_temp_memory_required: u32,
temp_memory_required: u32,
max_frame_size: u32
};
pub fn getInfo(self: STBVorbis) Info {
const info = c.stb_vorbis_get_info(self.handle);
return Info{
.sample_rate = info.sample_rate,
.channels = @intCast(info.channels),
.setup_memory_required = info.setup_memory_required,
.setup_temp_memory_required = info.setup_temp_memory_required,
.temp_memory_required = info.temp_memory_required,
.max_frame_size = @intCast(info.max_frame_size),
};
}