@@ -25407,8 +25438,8 @@ static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 ch
...
@@ -25407,8 +25438,8 @@ static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 ch
#endif
#endif
pDataFormat->numChannels = channels;
pDataFormat->numChannels = channels;
((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate) * 1000; /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */
((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate * 1000); /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */
if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED || resultSL == SL_RESULT_PARAMETER_INVALID) {
/* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
/* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
pcm.formatType = SL_DATAFORMAT_PCM;
pcm.formatType = SL_DATAFORMAT_PCM;
pcm.numChannels = 1;
pcm.numChannels = 1;
((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */
((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */
pcm.bitsPerSample = 16;
pcm.bitsPerSample = 16;
pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */
pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */
We need to calcualte the right vector from our forward and up vectors. This is done with
a cross product.
*/
axisZ = ma_vec3f_normalize(pListener->direction); /* Normalization required here because we can't trust the caller. */
axisX = ma_vec3f_normalize(ma_vec3f_cross(axisZ, pListener->config.worldUp)); /* Normalization required here because the world up vector may not be perpendicular with the forward vector. */
/*
The calculation of axisX above can result in a zero-length vector if the listener is
looking straight up on the Y axis. We'll need to fall back to a +X in this case so that
the calculations below don't fall apart. This is where a quaternion based listener and
sound orientation would come in handy.
*/
if (ma_vec3f_len2(axisX) == 0) {
axisX = ma_vec3f_init_3f(1, 0, 0);
}
axisY = ma_vec3f_cross(axisX, axisZ); /* No normalization is required here because axisX and axisZ are unit length and perpendicular. */
/*
We need to swap the X axis if we're left handed because otherwise the cross product above
will have resulted in it pointing in the wrong direction (right handed was assumed in the
cross products above).
*/
if (pListener->config.handedness == ma_handedness_left) {
if (pListener == NULL || pSpatializer->config.positioning == ma_positioning_relative) {
/* There's no listener or we're using relative positioning. */
if (pRelativePos != NULL) {
*pRelativePos = pSpatializer->position;
}
if (pRelativeDir != NULL) {
*pRelativeDir = pSpatializer->direction;
}
} else {
ma_vec3f v;
ma_vec3f axisX;
ma_vec3f axisY;
ma_vec3f axisZ;
float m[4][4];
/*
We need to calcualte the right vector from our forward and up vectors. This is done with
a cross product.
*/
axisZ = ma_vec3f_normalize(pListener->direction); /* Normalization required here because we can't trust the caller. */
axisX = ma_vec3f_normalize(ma_vec3f_cross(axisZ, pListener->config.worldUp)); /* Normalization required here because the world up vector may not be perpendicular with the forward vector. */
/*
The calculation of axisX above can result in a zero-length vector if the listener is
looking straight up on the Y axis. We'll need to fall back to a +X in this case so that
the calculations below don't fall apart. This is where a quaternion based listener and
sound orientation would come in handy.
*/
if (ma_vec3f_len2(axisX) == 0) {
axisX = ma_vec3f_init_3f(1, 0, 0);
}
axisY = ma_vec3f_cross(axisX, axisZ); /* No normalization is required here because axisX and axisZ are unit length and perpendicular. */
/*
We need to swap the X axis if we're left handed because otherwise the cross product above
will have resulted in it pointing in the wrong direction (right handed was assumed in the
cross products above).
*/
if (pListener->config.handedness == ma_handedness_left) {
ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */
ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */
floatdopplerFactor;/* Set to 0 to disable doppler effect. This will run on a fast path. */
floatdopplerFactor;/* Set to 0 to disable doppler effect. */
floatdirectionalAttenuationFactor;/* Set to 0 to disable directional attenuation. */
ma_uint32gainSmoothTimeInFrames;/* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */
ma_uint32gainSmoothTimeInFrames;/* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */
#define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1) /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */
#define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1) /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */
#ifndef MA_MAX_DEVICE_NAME_LENGTH
#define MA_MAX_DEVICE_NAME_LENGTH 255
#endif
typedefstruct
typedefstruct
{
{
/* Basic info. This is the only information guaranteed to be filled in during device enumeration. */
/* Basic info. This is the only information guaranteed to be filled in during device enumeration. */
ma_device_idid;
ma_device_idid;
charname[256];
charname[MA_MAX_DEVICE_NAME_LENGTH+1];/* +1 for null terminator. */
ma_bool32isDefault;
ma_bool32isDefault;
ma_uint32nativeDataFormatCount;
ma_uint32nativeDataFormatCount;
...
@@ -2469,7 +2501,7 @@ callbacks defined in this structure.
...
@@ -2469,7 +2501,7 @@ callbacks defined in this structure.
Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which
Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which
physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the
physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the
given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration
given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration
needs to stop and the `onContextEnumerateDevices()` function return with a success code.
needs to stop and the `onContextEnumerateDevices()` function returns with a success code.
Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID,
Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID,
and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the
and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the
...
@@ -2511,6 +2543,9 @@ callback. When the device is stopped, the `ma_device_get_state() == ma_device_st
...
@@ -2511,6 +2543,9 @@ callback. When the device is stopped, the `ma_device_get_state() == ma_device_st
which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback,
which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback,
look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to
look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to
wake up the audio thread.
wake up the audio thread.
If the backend supports an optimized retrieval of device information from an initialized `ma_device` object, it should implement the
`onDeviceGetInfo()` callback. This is optional, in which case it will fall back to `onContextGetDeviceInfo()` which is less efficient.
#define MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM 0x00000001 /* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */
typedefenum
#define MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE 0x00000002 /* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage. */
{
#define MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC 0x00000004 /* When set, the resource manager will load the data source asynchronously. */
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM=0x00000001,/* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */
#define MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT 0x00000008 /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE=0x00000002,/* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage. */
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC=0x00000004,/* When set, the resource manager will load the data source asynchronously. */
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT=0x00000008/* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */
#define MA_RESOURCE_MANAGER_JOB_CUSTOM 0x00000100 /* Number your custom job codes as (MA_RESOURCE_MANAGER_JOB_CUSTOM + 0), (MA_RESOURCE_MANAGER_JOB_CUSTOM + 1), etc. */
MA_RESOURCE_MANAGER_JOB_CUSTOM=0x00000100/* Number your custom job codes as (MA_RESOURCE_MANAGER_JOB_CUSTOM + 0), (MA_RESOURCE_MANAGER_JOB_CUSTOM + 1), etc. */
}ma_resource_manager_job_type;
/*
/*
...
@@ -5804,7 +5938,10 @@ ma_resource_manager_job_queue_post(). ma_resource_manager_job_queue_next() will
...
@@ -5804,7 +5938,10 @@ ma_resource_manager_job_queue_post(). ma_resource_manager_job_queue_next() will
This flag should always be used for platforms that do not support multithreading.
This flag should always be used for platforms that do not support multithreading.
/* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */
/* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */
MA_ATOMIC(1,ma_uint8)inputNodeInputBusIndex;/* The index of the input bus on the input. Required for detaching. */
MA_ATOMIC(1,ma_uint8)inputNodeInputBusIndex;/* The index of the input bus on the input. Required for detaching. */
MA_ATOMIC(4,ma_uint32)flags;/* Some state flags for tracking the read state of the output buffer. */
MA_ATOMIC(4,ma_uint32)flags;/* Some state flags for tracking the read state of the output buffer. A combination of MA_NODE_OUTPUT_BUS_FLAG_*. */
MA_ATOMIC(4,ma_uint32)refCount;/* Reference count for some thread-safety when detaching. */
MA_ATOMIC(4,ma_uint32)refCount;/* Reference count for some thread-safety when detaching. */
MA_ATOMIC(4,ma_bool32)isAttached;/* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */
MA_ATOMIC(4,ma_bool32)isAttached;/* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */
MA_ATOMIC(4,ma_spinlock)lock;/* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
MA_ATOMIC(4,ma_spinlock)lock;/* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
#define MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT 0x00000010 /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */
#define MA_SOUND_FLAG_NO_PITCH 0x00000020 /* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */
MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT=0x00000010,/* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */
MA_SOUND_FLAG_NO_PITCH=0x00000020,/* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */