mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-14 14:23:43 +00:00
401 lines
13 KiB
Odin
401 lines
13 KiB
Odin
package miniaudio
|
|
|
|
import "core:c"
|
|
|
|
MINIAUDIO_SHARED :: #config(MINIAUDIO_SHARED, false)
|
|
|
|
when MINIAUDIO_SHARED {
|
|
#panic("Shared linking for miniaudio is not supported yet")
|
|
}
|
|
|
|
@(private)
|
|
LIB :: "lib/miniaudio.lib" when ODIN_OS == .Windows else "lib/miniaudio.a"
|
|
|
|
when !#exists(LIB) {
|
|
// Windows library is shipped with the compiler, so a Windows specific message should not be needed.
|
|
#panic("Could not find the compiled miniaudio library, it can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/miniaudio/src\"`")
|
|
}
|
|
|
|
foreign import lib { LIB }
|
|
|
|
BINDINGS_VERSION_MAJOR :: 0
|
|
BINDINGS_VERSION_MINOR :: 11
|
|
BINDINGS_VERSION_REVISION :: 24
|
|
BINDINGS_VERSION :: [3]u32{BINDINGS_VERSION_MAJOR, BINDINGS_VERSION_MINOR, BINDINGS_VERSION_REVISION}
|
|
BINDINGS_VERSION_STRING :: "0.11.24"
|
|
|
|
@(init)
|
|
version_check :: proc "contextless" () {
|
|
v: [3]u32
|
|
version(&v.x, &v.y, &v.z)
|
|
if v != BINDINGS_VERSION {
|
|
buf: [1024]byte
|
|
n := copy(buf[:], "miniaudio version mismatch: ")
|
|
n += copy(buf[n:], "bindings are for version ")
|
|
n += copy(buf[n:], BINDINGS_VERSION_STRING)
|
|
n += copy(buf[n:], ", but version ")
|
|
n += copy(buf[n:], string(version_string()))
|
|
n += copy(buf[n:], " is linked, make sure to compile the correct miniaudio version by going to `vendor/miniaudio/src` ")
|
|
|
|
when ODIN_OS == .Windows {
|
|
n += copy(buf[n:], "and executing `build.bat`")
|
|
} else {
|
|
n += copy(buf[n:], "and executing `make`")
|
|
}
|
|
|
|
panic_contextless(string(buf[:n]))
|
|
}
|
|
}
|
|
|
|
|
|
handle :: distinct rawptr
|
|
|
|
/* SIMD alignment in bytes. Currently set to 32 bytes in preparation for future AVX optimizations. */
|
|
SIMD_ALIGNMENT :: 32
|
|
|
|
log_level :: enum c.int {
|
|
LOG_LEVEL_DEBUG = 4,
|
|
LOG_LEVEL_INFO = 3,
|
|
LOG_LEVEL_WARNING = 2,
|
|
LOG_LEVEL_ERROR = 1,
|
|
}
|
|
|
|
|
|
channel :: enum u8 {
|
|
NONE = 0,
|
|
MONO = 1,
|
|
FRONT_LEFT = 2,
|
|
FRONT_RIGHT = 3,
|
|
FRONT_CENTER = 4,
|
|
LFE = 5,
|
|
BACK_LEFT = 6,
|
|
BACK_RIGHT = 7,
|
|
FRONT_LEFT_CENTER = 8,
|
|
FRONT_RIGHT_CENTER = 9,
|
|
BACK_CENTER = 10,
|
|
SIDE_LEFT = 11,
|
|
SIDE_RIGHT = 12,
|
|
TOP_CENTER = 13,
|
|
TOP_FRONT_LEFT = 14,
|
|
TOP_FRONT_CENTER = 15,
|
|
TOP_FRONT_RIGHT = 16,
|
|
TOP_BACK_LEFT = 17,
|
|
TOP_BACK_CENTER = 18,
|
|
TOP_BACK_RIGHT = 19,
|
|
AUX_0 = 20,
|
|
AUX_1 = 21,
|
|
AUX_2 = 22,
|
|
AUX_3 = 23,
|
|
AUX_4 = 24,
|
|
AUX_5 = 25,
|
|
AUX_6 = 26,
|
|
AUX_7 = 27,
|
|
AUX_8 = 28,
|
|
AUX_9 = 29,
|
|
AUX_10 = 30,
|
|
AUX_11 = 31,
|
|
AUX_12 = 32,
|
|
AUX_13 = 33,
|
|
AUX_14 = 34,
|
|
AUX_15 = 35,
|
|
AUX_16 = 36,
|
|
AUX_17 = 37,
|
|
AUX_18 = 38,
|
|
AUX_19 = 39,
|
|
AUX_20 = 40,
|
|
AUX_21 = 41,
|
|
AUX_22 = 42,
|
|
AUX_23 = 43,
|
|
AUX_24 = 44,
|
|
AUX_25 = 45,
|
|
AUX_26 = 46,
|
|
AUX_27 = 47,
|
|
AUX_28 = 48,
|
|
AUX_29 = 49,
|
|
AUX_30 = 50,
|
|
AUX_31 = 51,
|
|
POSITION_COUNT,
|
|
LEFT = FRONT_LEFT,
|
|
RIGHT = FRONT_RIGHT,
|
|
}
|
|
|
|
result :: enum c.int {
|
|
SUCCESS = 0,
|
|
ERROR = -1, /* A generic error. */
|
|
INVALID_ARGS = -2,
|
|
INVALID_OPERATION = -3,
|
|
OUT_OF_MEMORY = -4,
|
|
OUT_OF_RANGE = -5,
|
|
ACCESS_DENIED = -6,
|
|
DOES_NOT_EXIST = -7,
|
|
ALREADY_EXISTS = -8,
|
|
TOO_MANY_OPEN_FILES = -9,
|
|
INVALID_FILE = -10,
|
|
TOO_BIG = -11,
|
|
PATH_TOO_LONG = -12,
|
|
NAME_TOO_LONG = -13,
|
|
NOT_DIRECTORY = -14,
|
|
IS_DIRECTORY = -15,
|
|
DIRECTORY_NOT_EMPTY = -16,
|
|
AT_END = -17,
|
|
NO_SPACE = -18,
|
|
BUSY = -19,
|
|
IO_ERROR = -20,
|
|
INTERRUPT = -21,
|
|
UNAVAILABLE = -22,
|
|
ALREADY_IN_USE = -23,
|
|
BAD_ADDRESS = -24,
|
|
BAD_SEEK = -25,
|
|
BAD_PIPE = -26,
|
|
DEADLOCK = -27,
|
|
TOO_MANY_LINKS = -28,
|
|
NOT_IMPLEMENTED = -29,
|
|
NO_MESSAGE = -30,
|
|
BAD_MESSAGE = -31,
|
|
NO_DATA_AVAILABLE = -32,
|
|
INVALID_DATA = -33,
|
|
TIMEOUT = -34,
|
|
NO_NETWORK = -35,
|
|
NOT_UNIQUE = -36,
|
|
NOT_SOCKET = -37,
|
|
NO_ADDRESS = -38,
|
|
BAD_PROTOCOL = -39,
|
|
PROTOCOL_UNAVAILABLE = -40,
|
|
PROTOCOL_NOT_SUPPORTED = -41,
|
|
PROTOCOL_FAMILY_NOT_SUPPORTED = -42,
|
|
ADDRESS_FAMILY_NOT_SUPPORTED = -43,
|
|
SOCKET_NOT_SUPPORTED = -44,
|
|
CONNECTION_RESET = -45,
|
|
ALREADY_CONNECTED = -46,
|
|
NOT_CONNECTED = -47,
|
|
CONNECTION_REFUSED = -48,
|
|
NO_HOST = -49,
|
|
IN_PROGRESS = -50,
|
|
CANCELLED = -51,
|
|
MEMORY_ALREADY_MAPPED = -52,
|
|
|
|
/* General non-standard errors. */
|
|
CRC_MISMATCH = -100,
|
|
|
|
/* General miniaudio-specific errors. */
|
|
FORMAT_NOT_SUPPORTED = -200,
|
|
DEVICE_TYPE_NOT_SUPPORTED = -201,
|
|
SHARE_MODE_NOT_SUPPORTED = -202,
|
|
NO_BACKEND = -203,
|
|
NO_DEVICE = -204,
|
|
API_NOT_FOUND = -205,
|
|
INVALID_DEVICE_CONFIG = -206,
|
|
LOOP = -207,
|
|
BACKEND_NOT_ENABLED = -208,
|
|
|
|
/* State errors. */
|
|
DEVICE_NOT_INITIALIZED = -300,
|
|
DEVICE_ALREADY_INITIALIZED = -301,
|
|
DEVICE_NOT_STARTED = -302,
|
|
DEVICE_NOT_STOPPED = -303,
|
|
|
|
/* Operation errors. */
|
|
FAILED_TO_INIT_BACKEND = -400,
|
|
FAILED_TO_OPEN_BACKEND_DEVICE = -401,
|
|
FAILED_TO_START_BACKEND_DEVICE = -402,
|
|
FAILED_TO_STOP_BACKEND_DEVICE = -403,
|
|
}
|
|
|
|
|
|
MIN_CHANNELS :: 1
|
|
MAX_CHANNELS :: 254
|
|
|
|
MAX_FILTER_ORDER :: 8
|
|
|
|
|
|
stream_format :: enum c.int {
|
|
pcm = 0,
|
|
}
|
|
|
|
stream_layout :: enum c.int {
|
|
interleaved = 0,
|
|
deinterleaved,
|
|
}
|
|
|
|
dither_mode :: enum c.int {
|
|
none = 0,
|
|
rectangle,
|
|
triangle,
|
|
}
|
|
|
|
format :: enum c.int {
|
|
/*
|
|
I like to keep these explicitly defined because they're used as a key into a lookup table. When items are
|
|
added to this, make sure there are no gaps and that they're added to the lookup table in ma_get_bytes_per_sample().
|
|
*/
|
|
unknown = 0, /* Mainly used for indicating an error, but also used as the default for the output format for decoders. */
|
|
u8 = 1,
|
|
s16 = 2, /* Seems to be the most widely supported format. */
|
|
s24 = 3, /* Tightly packed. 3 bytes per sample. */
|
|
s32 = 4,
|
|
f32 = 5,
|
|
}
|
|
|
|
standard_sample_rate :: enum u32 {
|
|
/* Standard rates need to be in priority order. */
|
|
rate_48000 = 48000, /* Most common */
|
|
rate_44100 = 44100,
|
|
|
|
rate_32000 = 32000, /* Lows */
|
|
rate_24000 = 24000,
|
|
rate_22050 = 22050,
|
|
|
|
rate_88200 = 88200, /* Highs */
|
|
rate_96000 = 96000,
|
|
rate_176400 = 176400,
|
|
rate_192000 = 192000,
|
|
|
|
rate_16000 = 16000, /* Extreme lows */
|
|
rate_11025 = 11025,
|
|
rate_8000 = 8000,
|
|
|
|
rate_352800 = 352800, /* Extreme highs */
|
|
rate_384000 = 384000,
|
|
|
|
rate_min = rate_8000,
|
|
rate_max = rate_384000,
|
|
rate_count = 14, /* Need to maintain the count manually. Make sure this is updated if items are added to enum. */
|
|
}
|
|
|
|
|
|
channel_mix_mode :: enum c.int {
|
|
rectangular = 0, /* Simple averaging based on the plane(s) the channel is sitting on. */
|
|
simple, /* Drop excess channels; zeroed out extra channels. */
|
|
custom_weights, /* Use custom weights specified in ma_channel_converter_config. */
|
|
default = rectangular,
|
|
}
|
|
|
|
standard_channel_map :: enum c.int {
|
|
microsoft,
|
|
alsa,
|
|
rfc3551, /* Based off AIFF. */
|
|
flac,
|
|
vorbis,
|
|
sound4, /* FreeBSD's sound(4). */
|
|
sndio, /* www.sndio.org/tips.html */
|
|
webaudio = flac, /* https://webaudio.github.io/web-audio-api/#ChannelOrdering. Only 1, 2, 4 and 6 channels are defined, but can fill in the gaps with logical assumptions. */
|
|
default = microsoft,
|
|
}
|
|
|
|
performance_profile :: enum c.int {
|
|
low_latency = 0,
|
|
conservative,
|
|
}
|
|
|
|
|
|
allocation_callbacks :: struct {
|
|
pUserData: rawptr,
|
|
onMalloc: proc "c" (sz: c.size_t, pUserData: rawptr) -> rawptr,
|
|
onRealloc: proc "c" (p: rawptr, sz: c.size_t, pUserData: rawptr) -> rawptr,
|
|
onFree: proc "c" (p: rawptr, pUserData: rawptr),
|
|
}
|
|
|
|
lcg :: struct {
|
|
state: u32,
|
|
}
|
|
|
|
|
|
/* Spinlocks are 32-bit for compatibility reasons. */
|
|
spinlock :: distinct u32
|
|
|
|
NO_THREADING :: false
|
|
|
|
when !NO_THREADING {
|
|
/* Thread priorities should be ordered such that the default priority of the worker thread is 0. */
|
|
thread_priority :: enum c.int {
|
|
idle = -5,
|
|
lowest = -4,
|
|
low = -3,
|
|
normal = -2,
|
|
high = -1,
|
|
highest = 0,
|
|
realtime = 1,
|
|
default = 0,
|
|
}
|
|
} /* NO_THREADING */
|
|
|
|
|
|
@(default_calling_convention="c", link_prefix="ma_")
|
|
foreign lib {
|
|
version :: proc(pMajor, pMinor, pRevision: ^u32) ---
|
|
version_string :: proc() -> cstring ---
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************************************************************************************************
|
|
|
|
Miscellaneous Helpers
|
|
|
|
************************************************************************************************************************************************************/
|
|
|
|
@(default_calling_convention="c", link_prefix="ma_")
|
|
foreign lib {
|
|
/*
|
|
Retrieves a human readable description of the given result code.
|
|
*/
|
|
result_description :: proc(result: result) -> cstring ---
|
|
|
|
/*
|
|
malloc()
|
|
*/
|
|
malloc :: proc(sz: c.size_t, pAllocationCallbacks: ^allocation_callbacks) -> rawptr ---
|
|
|
|
/*
|
|
calloc()
|
|
*/
|
|
calloc :: proc(sz: c.size_t, pAllocationCallbacks: ^allocation_callbacks) -> rawptr ---
|
|
|
|
/*
|
|
realloc()
|
|
*/
|
|
realloc :: proc(p: rawptr, sz: c.size_t, pAllocationCallbacks: ^allocation_callbacks) -> rawptr ---
|
|
|
|
/*
|
|
free()
|
|
*/
|
|
free :: proc(p: rawptr, pAllocationCallbacks: ^allocation_callbacks) ---
|
|
|
|
/*
|
|
Performs an aligned malloc, with the assumption that the alignment is a power of 2.
|
|
*/
|
|
aligned_malloc :: proc(sz, alignment: c.size_t, pAllocationCallbacks: ^allocation_callbacks) -> rawptr ---
|
|
|
|
/*
|
|
Free's an aligned malloc'd buffer.
|
|
*/
|
|
aligned_free :: proc(p: rawptr, pAllocationCallbacks: ^allocation_callbacks) ---
|
|
|
|
/*
|
|
Retrieves a friendly name for a format.
|
|
*/
|
|
get_format_name :: proc(format: format) -> cstring ---
|
|
|
|
/*
|
|
Blends two frames in floating point format.
|
|
*/
|
|
blend_f32 :: proc(pOut, pInA, pInB: [^]f32, factor: f32, channels: u32) ---
|
|
|
|
/*
|
|
Retrieves the size of a sample in bytes for the given format.
|
|
|
|
This API is efficient and is implemented using a lookup table.
|
|
|
|
Thread Safety: SAFE
|
|
This API is pure.
|
|
*/
|
|
get_bytes_per_sample :: proc(format: format) -> u32 ---
|
|
|
|
/*
|
|
Converts a log level to a string.
|
|
*/
|
|
log_level_to_string :: proc(logLevel: u32) -> cstring ---
|
|
}
|
|
|
|
get_bytes_per_frame :: #force_inline proc "c" (format: format, channels: u32) -> u32 { return get_bytes_per_sample(format) * channels }
|