Files
Odin/vendor/miniaudio/engine.odin
2022-04-29 21:13:25 +02:00

342 lines
26 KiB
Odin

package miniaudio
import "core:c"
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/************************************************************************************************************************************************************
Engine
************************************************************************************************************************************************************/
/* Sound flags. */
sound_flags :: enum c.int {
STREAM = 0x00000001, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM */
DECODE = 0x00000002, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE */
ASYNC = 0x00000004, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC */
WAIT_INIT = 0x00000008, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT */
NO_DEFAULT_ATTACHMENT = 0x00000010, /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */
NO_PITCH = 0x00000020, /* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */
NO_SPATIALIZATION = 0x00000040, /* Disable spatialization. */
}
ENGINE_MAX_LISTENERS :: 4
LISTENER_INDEX_CLOSEST :: 255
engine_node_type :: enum c.int {
sound,
group,
}
engine_node_config :: struct {
pEngine: ^engine,
type: engine_node_type,
channelsIn: u32,
channelsOut: u32,
sampleRate: u32, /* Only used when the type is set to ma_engine_node_type_sound. */
isPitchDisabled: b8, /* Pitching can be explicitly disable with MA_SOUND_FLAG_NO_PITCH to optimize processing. */
isSpatializationDisabled: b8, /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */
pinnedListenerIndex: u8, /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */
}
/* Base node object for both ma_sound and ma_sound_group. */
engine_node :: struct {
baseNode: node_base, /* Must be the first member for compatiblity with the ma_node API. */
pEngine: ^engine, /* A pointer to the engine. Set based on the value from the config. */
sampleRate: u32, /* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */
fader: fader,
resampler: linear_resampler, /* For pitch shift. */
spatializer: spatializer,
panner: panner,
pitch: f32, /*atomic*/
oldPitch: f32, /* For determining whether or not the resampler needs to be updated to reflect the new pitch. The resampler will be updated on the mixing thread. */
oldDopplerPitch: f32, /* For determining whether or not the resampler needs to be updated to take a new doppler pitch into account. */
isPitchDisabled: b32, /*atomic*/ /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */
isSpatializationDisabled: b32, /*atomic*/ /* Set to false by default. When set to false, will not have spatialisation applied. */
pinnedListenerIndex: u32, /*atomic*/ /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */
/* Memory management. */
_ownsHeap: b8,
_pHeap: rawptr,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
engine_node_config_init :: proc(pEngine: ^engine, type: engine_node_type, flags: u32) -> engine_node_config ---
engine_node_get_heap_size :: proc(pConfig: ^engine_node_config, pHeapSizeInBytes: ^c.size_t) -> result ---
engine_node_init_preallocated :: proc(pConfig: ^engine_node_config, pHeap: rawptr, pEngineNode: ^engine_node) -> result ---
engine_node_init :: proc(pConfig: ^engine_node_config, pAllocationCallbacks: ^allocation_callbacks, pEngineNode: ^engine_node) -> result ---
engine_node_uninit :: proc(pEngineNode: ^engine_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
SOUND_SOURCE_CHANNEL_COUNT :: 0xFFFFFFFF
sound_config :: struct {
pFilePath: cstring, /* Set this to load from the resource manager. */
pFilePathW: [^]c.wchar_t, /* Set this to load from the resource manager. */
pDataSource: ^data_source, /* Set this to load from an existing data source. */
pInitialAttachment: ^node, /* If set, the sound will be attached to an input of this node. This can be set to a ma_sound. If set to NULL, the sound will be attached directly to the endpoint unless MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT is set in `flags`. */
initialAttachmentInputBusIndex: u32, /* The index of the input bus of pInitialAttachment to attach the sound to. */
channelsIn: u32, /* Ignored if using a data source as input (the data source's channel count will be used always). Otherwise, setting to 0 will cause the engine's channel count to be used. */
channelsOut: u32, /* Set this to 0 (default) to use the engine's channel count. Set to MA_SOUND_SOURCE_CHANNEL_COUNT to use the data source's channel count (only used if using a data source as input). */
flags: u32, /* A combination of MA_SOUND_FLAG_* flags. */
initialSeekPointInPCMFrames: u64, /* Initializes the sound such that it's seeked to this location by default. */
rangeBegInPCMFrames: u64,
rangeEndInPCMFrames: u64,
loopPointBegInPCMFrames: u64,
loopPointEndInPCMFrames: u64,
isLooping: b32,
pDoneFence: ^fence, /* Released when the resource manager has finished decoding the entire sound. Not used with streams. */
}
sound :: struct {
engineNode: engine_node, /* Must be the first member for compatibility with the ma_node API. */
pDataSource: ^data_source,
seekTarget: u64, /*atomic*/ /* The PCM frame index to seek to in the mixing thread. Set to (~(ma_uint64)0) to not perform any seeking. */
atEnd: b32, /*atomic*/
ownsDataSource: b8,
/*
We're declaring a resource manager data source object here to save us a malloc when loading a
sound via the resource manager, which I *think* will be the most common scenario.
*/
pResourceManagerDataSource: ^resource_manager_data_source,
}
/* Structure specifically for sounds played with ma_engine_play_sound(). Making this a separate structure to reduce overhead. */
sound_inlined :: struct {
sound: sound,
pNext: ^sound_inlined,
pPrev: ^sound_inlined,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
sound_config_init :: proc() -> sound_config ---
sound_init_from_file :: proc(pEngine: ^engine, pFilePath: cstring, flags: u32, pGroup: ^sound_group, pDoneFence: ^fence, pSound: ^sound) -> result ---
sound_init_from_file_w :: proc(pEngine: ^engine, pFilePath: [^]c.wchar_t, flags: u32, pGroup: ^sound_group, pDoneFence: ^fence, pSound: ^sound) -> result ---
sound_init_copy :: proc(pEngine: ^engine, pExistingSound: ^sound, flags: u32, pGroup: ^sound_group, pSound: ^sound) -> result ---
sound_init_from_data_source :: proc(pEngine: ^engine, pDataSource: ^data_source, flags: u32, pGroup: ^sound_group, pSound: ^sound) -> result ---
sound_init_ex :: proc(pEngine: ^engine, pConfig: ^sound_config, pSound: ^sound) -> result ---
sound_uninit :: proc(pSound: ^sound) ---
sound_get_engine :: proc(pSound: ^sound) -> ^engine ---
sound_get_data_source :: proc(pSound: ^sound) -> ^data_source ---
sound_start :: proc(pSound: ^sound) -> result ---
sound_stop :: proc(pSound: ^sound) -> result ---
sound_set_volume :: proc(pSound: ^sound, volume: f32) ---
sound_get_volume :: proc(pSound: ^sound) -> f32 ---
sound_set_pan :: proc(pSound: ^sound, pan: f32) ---
sound_get_pan :: proc(pSound: ^sound) -> f32 ---
sound_set_pan_mode :: proc(pSound: ^sound, panMode: pan_mode) ---
sound_get_pan_mode :: proc(pSound: ^sound) -> pan_mode ---
sound_set_pitch :: proc(pSound: ^sound, pitch: f32) ---
sound_get_pitch :: proc(pSound: ^sound) -> f32 ---
sound_set_spatialization_enabled :: proc(pSound: ^sound, enabled: b32) ---
sound_is_spatialization_enabled :: proc(pSound: ^sound) -> b32 ---
sound_set_pinned_listener_index :: proc(pSound: ^sound, listenerIndex: u32) ---
sound_get_pinned_listener_index :: proc(pSound: ^sound) -> u32 ---
sound_get_listener_index :: proc(pSound: ^sound) -> u32 ---
sound_get_direction_to_listener :: proc(pSound: ^sound) -> vec3f ---
sound_set_position :: proc(pSound: ^sound, x, y, z: f32) ---
sound_get_position :: proc(pSound: ^sound) -> vec3f ---
sound_set_direction :: proc(pSound: ^sound, x, y, z: f32) ---
sound_get_direction :: proc(pSound: ^sound) -> vec3f ---
sound_set_velocity :: proc(pSound: ^sound, x, y, z: f32) ---
sound_get_velocity :: proc(pSound: ^sound) -> vec3f ---
sound_set_attenuation_model :: proc(pSound: ^sound, attenuationModel: attenuation_model) ---
sound_get_attenuation_model :: proc(pSound: ^sound) -> attenuation_model ---
sound_set_positioning :: proc(pSound: ^sound, positioning: positioning) ---
sound_get_positioning :: proc(pSound: ^sound) -> positioning ---
sound_set_rolloff :: proc(pSound: ^sound, rolloff: f32) ---
sound_get_rolloff :: proc(pSound: ^sound) -> f32 ---
sound_set_min_gain :: proc(pSound: ^sound, minGain: f32) ---
sound_get_min_gain :: proc(pSound: ^sound) -> f32 ---
sound_set_max_gain :: proc(pSound: ^sound, maxGain: f32) ---
sound_get_max_gain :: proc(pSound: ^sound) -> f32 ---
sound_set_min_distance :: proc(pSound: ^sound, minDistance: f32) ---
sound_get_min_distance :: proc(pSound: ^sound) -> f32 ---
sound_set_max_distance :: proc(pSound: ^sound, maxDistance: f32) ---
sound_get_max_distance :: proc(pSound: ^sound) -> f32 ---
sound_set_cone :: proc(pSound: ^sound, innerAngleInRadians, outerAngleInRadians, outerGain: f32) ---
sound_get_cone :: proc(pSound: ^sound, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) ---
sound_set_doppler_factor :: proc(pSound: ^sound, dopplerFactor: f32) ---
sound_get_doppler_factor :: proc(pSound: ^sound) -> f32 ---
sound_set_directional_attenuation_factor :: proc(pSound: ^sound, directionalAttenuationFactor: f32) ---
sound_get_directional_attenuation_factor :: proc(pSound: ^sound) -> f32 ---
sound_set_fade_in_pcm_frames :: proc(pSound: ^sound, volumeBeg, volumeEnd: f32, fadeLengthInFrames: u64) ---
sound_set_fade_in_milliseconds :: proc(pSound: ^sound, volumeBeg, volumeEnd: f32, fadeLengthInMilliseconds: u64) ---
sound_get_current_fade_volume :: proc(pSound: ^sound) -> f32 ---
sound_set_start_time_in_pcm_frames :: proc(pSound: ^sound, absoluteGlobalTimeInFrames: u64) ---
sound_set_start_time_in_milliseconds :: proc(pSound: ^sound, absoluteGlobalTimeInMilliseconds: u64) ---
sound_set_stop_time_in_pcm_frames :: proc(pSound: ^sound, absoluteGlobalTimeInFrames: u64) ---
sound_set_stop_time_in_milliseconds :: proc(pSound: ^sound, absoluteGlobalTimeInMilliseconds: u64) ---
sound_is_playing :: proc(pSound: ^sound) -> b32 ---
sound_get_time_in_pcm_frames :: proc(pSound: ^sound) -> u64 ---
sound_set_looping :: proc(pSound: ^sound, isLooping: b32) ---
sound_is_looping :: proc(pSound: ^sound) -> b32 ---
sound_at_end :: proc(pSound: ^sound) -> b32 ---
sound_seek_to_pcm_frame :: proc(pSound: ^sound, frameIndex: u64) -> result --- /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */
sound_get_data_format :: proc(pSound: ^sound, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: ^channel, channelMapCap: c.size_t) -> result ---
sound_get_cursor_in_pcm_frames :: proc(pSound: ^sound, pCursor: ^u64) -> result ---
sound_get_length_in_pcm_frames :: proc(pSound: ^sound, pLength: ^u64) -> result ---
sound_get_cursor_in_seconds :: proc(pSound: ^sound, pCursor: ^f32) -> result ---
sound_get_length_in_seconds :: proc(pSound: ^sound, pLength: ^f32) -> result ---
}
/* A sound group is just a sound. */
sound_group_config :: distinct sound_config
sound_group :: distinct sound
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
sound_group_config_init :: proc() -> sound_group_config ---
sound_group_init :: proc(pEngine: ^engine, flags: u32, pParentGroup, pGroup: ^sound_group) -> result ---
sound_group_init_ex :: proc(pEngine: ^engine, pConfig: ^sound_group_config, pGroup: ^sound_group) -> result ---
sound_group_uninit :: proc(pGroup: ^sound_group) ---
sound_group_get_engine :: proc(pGroup: ^sound_group) -> ^engine ---
sound_group_start :: proc(pGroup: ^sound_group) -> result ---
sound_group_stop :: proc(pGroup: ^sound_group) -> result ---
sound_group_set_volume :: proc(pGroup: ^sound_group, volume: f32) ---
sound_group_get_volume :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_pan :: proc(pGroup: ^sound_group, pan: f32) ---
sound_group_get_pan :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_pan_mode :: proc(pGroup: ^sound_group, panMode: pan_mode) ---
sound_group_get_pan_mode :: proc(pGroup: ^sound_group) -> pan_mode ---
sound_group_set_pitch :: proc(pGroup: ^sound_group, pitch: f32) ---
sound_group_get_pitch :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_spatialization_enabled :: proc(pGroup: ^sound_group, enabled: b32) ---
sound_group_is_spatialization_enabled :: proc(pGroup: ^sound_group) -> b32 ---
sound_group_set_pinned_listener_index :: proc(pGroup: ^sound_group, listenerIndex: u32) ---
sound_group_get_pinned_listener_index :: proc(pGroup: ^sound_group) -> u32 ---
sound_group_get_listener_index :: proc(pGroup: ^sound_group) -> u32 ---
sound_group_get_direction_to_listener :: proc(pGroup: ^sound_group) -> vec3f ---
sound_group_set_position :: proc(pGroup: ^sound_group, x, y, z: f32) ---
sound_group_get_position :: proc(pGroup: ^sound_group) -> vec3f ---
sound_group_set_direction :: proc(pGroup: ^sound_group, x, y, z: f32) ---
sound_group_get_direction :: proc(pGroup: ^sound_group) -> vec3f ---
sound_group_set_velocity :: proc(pGroup: ^sound_group, x, y, z: f32) ---
sound_group_get_velocity :: proc(pGroup: ^sound_group) -> vec3f ---
sound_group_set_attenuation_model :: proc(pGroup: ^sound_group, attenuationModel: attenuation_model) ---
sound_group_get_attenuation_model :: proc(pGroup: ^sound_group) -> attenuation_model ---
sound_group_set_positioning :: proc(pGroup: ^sound_group, positioning: positioning) ---
sound_group_get_positioning :: proc(pGroup: ^sound_group) -> positioning ---
sound_group_set_rolloff :: proc(pGroup: ^sound_group, rolloff: f32) ---
sound_group_get_rolloff :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_min_gain :: proc(pGroup: ^sound_group, minGain: f32) ---
sound_group_get_min_gain :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_max_gain :: proc(pGroup: ^sound_group, maxGain: f32) ---
sound_group_get_max_gain :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_min_distance :: proc(pGroup: ^sound_group, minDistance: f32) ---
sound_group_get_min_distance :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_max_distance :: proc(pGroup: ^sound_group, maxDistance: f32) ---
sound_group_get_max_distance :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_cone :: proc(pGroup: ^sound_group, innerAngleInRadians, outerAngleInRadians, outerGain: f32) ---
sound_group_get_cone :: proc(pGroup: ^sound_group, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) ---
sound_group_set_doppler_factor :: proc(pGroup: ^sound_group, dopplerFactor: f32) ---
sound_group_get_doppler_factor :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_directional_attenuation_factor :: proc(pGroup: ^sound_group, directionalAttenuationFactor: f32) ---
sound_group_get_directional_attenuation_factor :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_fade_in_pcm_frames :: proc(pGroup: ^sound_group, volumeBeg, volumeEnd: f32, fadeLengthInFrames: u64) ---
sound_group_set_fade_in_milliseconds :: proc(pGroup: ^sound_group, volumeBeg, volumeEnd: f32, fadeLengthInMilliseconds: u64) ---
sound_group_get_current_fade_volume :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_start_time_in_pcm_frames :: proc(pGroup: ^sound_group, absoluteGlobalTimeInFrames: u64) ---
sound_group_set_start_time_in_milliseconds :: proc(pGroup: ^sound_group, absoluteGlobalTimeInMilliseconds: u64) ---
sound_group_set_stop_time_in_pcm_frames :: proc(pGroup: ^sound_group, absoluteGlobalTimeInFrames: u64) ---
sound_group_set_stop_time_in_milliseconds :: proc(pGroup: ^sound_group, absoluteGlobalTimeInMilliseconds: u64) ---
sound_group_is_playing :: proc(pGroup: ^sound_group) -> b32 ---
sound_group_get_time_in_pcm_frames :: proc(pGroup: ^sound_group) -> u64 ---
}
engine_config :: struct {
pResourceManager: ^resource_manager, /* Can be null in which case a resource manager will be created for you. */
pContext: ^context_type,
pDevice: ^device, /* If set, the caller is responsible for calling ma_engine_data_callback() in the device's data callback. */
pPlaybackDeviceID: ^device_id, /* The ID of the playback device to use with the default listener. */
pLog: ^log, /* When set to NULL, will use the context's log. */
listenerCount: u32, /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */
channels: u32, /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */
sampleRate: u32, /* The sample rate. When set to 0 will use the native channel count of the device. */
periodSizeInFrames: u32, /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/
periodSizeInMilliseconds: u32, /* Used if periodSizeInFrames is unset. */
gainSmoothTimeInFrames: u32, /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */
gainSmoothTimeInMilliseconds: u32, /* When set to 0, gainSmoothTimeInFrames will be used. If both are set to 0, a default value will be used. */
allocationCallbacks: allocation_callbacks,
noAutoStart: b32, /* When set to true, requires an explicit call to ma_engine_start(). This is false by default, meaning the engine will be started automatically in ma_engine_init(). */
noDevice: b32, /* When set to true, don't create a default device. ma_engine_read_pcm_frames() can be called manually to read data. */
monoExpansionMode: mono_expansion_mode, /* Controls how the mono channel should be expanded to other channels when spatialization is disabled on a sound. */
pResourceManagerVFS: ^vfs, /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */
}
engine :: struct {
nodeGraph: node_graph, /* An engine is a node graph. It should be able to be plugged into any ma_node_graph API (with a cast) which means this must be the first member of this struct. */
pResourceManager: ^resource_manager,
pDevice: ^device, /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */
pLog: ^log,
sampleRate: u32,
listenerCount: u32,
listeners: [ENGINE_MAX_LISTENERS]spatializer_listener,
allocationCallbacks: allocation_callbacks,
ownsResourceManager: b8,
ownsDevice: b8,
inlinedSoundLock: spinlock, /* For synchronizing access so the inlined sound list. */
pInlinedSoundHead: ^sound_inlined, /* The first inlined sound. Inlined sounds are tracked in a linked list. */
inlinedSoundCount: u32, /*atomic*/ /* The total number of allocated inlined sound objects. Used for debugging. */
gainSmoothTimeInFrames: u32, /* The number of frames to interpolate the gain of spatialized sounds across. */
monoExpansionMode: mono_expansion_mode,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
engine_config_init :: proc() -> engine_config ---
engine_init :: proc(pConfig: ^engine_config, pEngine: ^engine) -> result ---
engine_uninit :: proc(pEngine: ^engine) ---
engine_read_pcm_frames :: proc(pEngine: ^engine, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
engine_get_node_graph :: proc(pEngine: ^engine) -> ^node_graph ---
engine_get_resource_manager :: proc(pEngine: ^engine) -> ^resource_manager ---
engine_get_device :: proc(pEngine: ^engine) -> ^device ---
engine_get_log :: proc(pEngine: ^engine) -> ^log ---
engine_get_endpoint :: proc(pEngine: ^engine) -> ^node ---
engine_get_time :: proc(pEngine: ^engine) -> u64 ---
engine_set_time :: proc(pEngine: ^engine, globalTime: u64) -> result ---
engine_get_channels :: proc(pEngine: ^engine) -> u32 ---
engine_get_sample_rate :: proc(pEngine: ^engine) -> u32 ---
engine_start :: proc(pEngine: ^engine) -> result ---
engine_stop :: proc(pEngine: ^engine) -> result ---
engine_set_volume :: proc(pEngine: ^engine, volume: f32) -> result ---
engine_set_gain_db :: proc(pEngine: ^engine, gainDB: f32) -> result ---
engine_get_listener_count :: proc(pEngine: ^engine) -> u32 ---
engine_find_closest_listener :: proc(pEngine: ^engine, absolutePosX, absolutePosY, absolutePosZ: f32) -> u32 ---
engine_listener_set_position :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) ---
engine_listener_get_position :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f ---
engine_listener_set_direction :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) ---
engine_listener_get_direction :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f ---
engine_listener_set_velocity :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) ---
engine_listener_get_velocity :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f ---
engine_listener_set_cone :: proc(pEngine: ^engine, listenerIndex: u32, innerAngleInRadians, outerAngleInRadians, outerGain: f32) ---
engine_listener_get_cone :: proc(pEngine: ^engine, listenerIndex: u32, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) ---
engine_listener_set_world_up :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) ---
engine_listener_get_world_up :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f ---
engine_listener_set_enabled :: proc(pEngine: ^engine, listenerIndex: u32, isEnabled: b32) ---
engine_listener_is_enabled :: proc(pEngine: ^engine, listenerIndex: u32) -> b32 ---
engine_play_sound_ex :: proc(pEngine: ^engine, pFilePath: cstring, pNode: ^node, nodeInputBusIndex: u32) -> result ---
engine_play_sound :: proc(pEngine: ^engine, pFilePath: cstring, pGroup: ^sound_group) -> result --- /* Fire and forget. */
}