mirror of
https://github.com/mackron/miniaudio.git
synced 2026-07-22 12:52:43 +02:00
Rework of the attenuation model system.
Support for custom attenuation models has been added.
Attenuation models are now a callback rather than an enumerator. The
callback takes a user data pointer in case the standard distance/rolloff
variables do not suffice. The following APIs have changed in order to
accommodate this:
ma_spatializer_set_attenuation_model()
ma_sound_set_attenuation_model()
ma_sound_group_set_attenuation_model()
These now take an extra parameter for the user data pointer. For stock
attenuation models this should always be set to NULL:
ma_sound_set_attenuation_model(&sound,
ma_attenuation_model_linear, NULL);
To plug in a custom model, just implement a callback and plug it in:
float your_custom_attenuation_model(
void* pUserData,
float distance,
float minDistance,
float maxDistance,
float rolloff)
{
// Return a value between 0 (silence) and 1 (full volume).
}
...
ma_sound_set_attenuation_model(&sound,
your_custom_attenuation_model, &userDataIfRequiredByYourModel);
Previously, setting the attenuation model to none would disable
spatialization completely. This behaviour has changed and now
spatialization will still be applied in this case. You should use
`ma_sound_set_spatialization_enabled(&sound, MA_FALSE)` instead if you
want to disable spatialization.
This commit is contained in:
+81
-42
@@ -1616,10 +1616,10 @@ default the attenuation model is set to `ma_attenuation_model_inverse` which is
|
||||
OpenAL's `AL_INVERSE_DISTANCE_CLAMPED`. Configure the attenuation model like so:
|
||||
|
||||
```c
|
||||
ma_sound_set_attenuation_model(&sound, ma_attenuation_model_inverse);
|
||||
ma_sound_set_attenuation_model(&sound, ma_attenuation_model_inverse, NULL);
|
||||
```
|
||||
|
||||
The supported attenuation models include the following:
|
||||
The supported stock attenuation models include the following:
|
||||
|
||||
+----------------------------------+----------------------------------------------+
|
||||
| ma_attenuation_model_none | No distance attenuation. |
|
||||
@@ -1631,6 +1631,26 @@ The supported attenuation models include the following:
|
||||
| ma_attenuation_model_exponential | Exponential attenuation. |
|
||||
+----------------------------------+----------------------------------------------+
|
||||
|
||||
The second parameter is a user data pointer which for stock attenuation models should always be set
|
||||
to null. A custom attenuation model can be plugged in like so:
|
||||
|
||||
```c
|
||||
float your_custom_attenuation_model(void* pUserData, float distance, float minDistance, float maxDistance, float rolloff)
|
||||
{
|
||||
// This is just linear attenuation. You would plug in your own model here.
|
||||
if (minDistance >= maxDistance) {
|
||||
return 1; // To avoid division by zero. Do not attenuate.
|
||||
}
|
||||
|
||||
return 1 - rolloff * (ma_clamp(distance, minDistance, maxDistance) - minDistance) / (maxDistance - minDistance);
|
||||
}
|
||||
|
||||
ma_sound_set_attenuation_model(&sound, your_custom_attenuation_model, &userDataIfRequiredByYourModel);
|
||||
```
|
||||
|
||||
The attenuation model cannot be changed while the sound is processing. You should set the
|
||||
attenuation model once at initialization time before the sound is started.
|
||||
|
||||
To control how quickly a sound rolls off as it moves away from the listener, you need to configure
|
||||
the rolloff:
|
||||
|
||||
@@ -5753,13 +5773,22 @@ typedef struct
|
||||
ma_spinlock lock;
|
||||
} ma_atomic_vec3f;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ma_attenuation_model_none, /* No distance attenuation and no spatialization. */
|
||||
ma_attenuation_model_inverse, /* Equivalent to OpenAL's AL_INVERSE_DISTANCE_CLAMPED. */
|
||||
ma_attenuation_model_linear, /* Linear attenuation. Equivalent to OpenAL's AL_LINEAR_DISTANCE_CLAMPED. */
|
||||
ma_attenuation_model_exponential /* Exponential attenuation. Equivalent to OpenAL's AL_EXPONENT_DISTANCE_CLAMPED. */
|
||||
} ma_attenuation_model;
|
||||
|
||||
/* Callback for attenuation models. The user data is unused for all stock models. */
|
||||
typedef float (* ma_attenuation_model)(void* pUserData, float distance, float minDistance, float maxDistance, float rolloff);
|
||||
|
||||
/* No distance attenuation. */
|
||||
MA_API float ma_attenuation_model_none(void* pUserData, float distance, float minDistance, float maxDistance, float rolloff);
|
||||
|
||||
/* Equivalent to OpenAL's AL_INVERSE_DISTANCE_CLAMPED. */
|
||||
MA_API float ma_attenuation_model_inverse(void* pUserData, float distance, float minDistance, float maxDistance, float rolloff);
|
||||
|
||||
/* Linear attenuation. Equivalent to OpenAL's AL_LINEAR_DISTANCE_CLAMPED. */
|
||||
MA_API float ma_attenuation_model_linear(void* pUserData, float distance, float minDistance, float maxDistance, float rolloff);
|
||||
|
||||
/* Exponential attenuation. Equivalent to OpenAL's AL_EXPONENT_DISTANCE_CLAMPED. */
|
||||
MA_API float ma_attenuation_model_exponential(void* pUserData, float distance, float minDistance, float maxDistance, float rolloff);
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -5829,6 +5858,7 @@ typedef struct
|
||||
ma_uint32 channelsOut;
|
||||
ma_channel* pChannelMapIn;
|
||||
ma_attenuation_model attenuationModel;
|
||||
void* pAttenuationUserData;
|
||||
ma_positioning positioning;
|
||||
ma_handedness handedness; /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */
|
||||
float minGain;
|
||||
@@ -5854,6 +5884,7 @@ typedef struct
|
||||
ma_uint32 channelsOut;
|
||||
ma_channel* pChannelMapIn;
|
||||
ma_attenuation_model attenuationModel;
|
||||
void* pAttenuationUserData;
|
||||
ma_positioning positioning;
|
||||
ma_handedness handedness; /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */
|
||||
float minGain;
|
||||
@@ -5889,7 +5920,7 @@ MA_API ma_result ma_spatializer_set_master_volume(ma_spatializer* pSpatializer,
|
||||
MA_API ma_result ma_spatializer_get_master_volume(const ma_spatializer* pSpatializer, float* pVolume);
|
||||
MA_API ma_uint32 ma_spatializer_get_input_channels(const ma_spatializer* pSpatializer);
|
||||
MA_API ma_uint32 ma_spatializer_get_output_channels(const ma_spatializer* pSpatializer);
|
||||
MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel);
|
||||
MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel, void* pAttenuationUserData);
|
||||
MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer* pSpatializer);
|
||||
MA_API void ma_spatializer_set_positioning(ma_spatializer* pSpatializer, ma_positioning positioning);
|
||||
MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer* pSpatializer);
|
||||
@@ -12180,7 +12211,7 @@ MA_API void ma_sound_set_direction(ma_sound* pSound, float x, float y, float z);
|
||||
MA_API ma_vec3f ma_sound_get_direction(const ma_sound* pSound);
|
||||
MA_API void ma_sound_set_velocity(ma_sound* pSound, float x, float y, float z);
|
||||
MA_API ma_vec3f ma_sound_get_velocity(const ma_sound* pSound);
|
||||
MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_model attenuationModel);
|
||||
MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_model attenuationModel, void* pAttenuationUserData);
|
||||
MA_API ma_attenuation_model ma_sound_get_attenuation_model(const ma_sound* pSound);
|
||||
MA_API void ma_sound_set_positioning(ma_sound* pSound, ma_positioning positioning);
|
||||
MA_API ma_positioning ma_sound_get_positioning(const ma_sound* pSound);
|
||||
@@ -12251,7 +12282,7 @@ MA_API void ma_sound_group_set_direction(ma_sound_group* pGroup, float x, float
|
||||
MA_API ma_vec3f ma_sound_group_get_direction(const ma_sound_group* pGroup);
|
||||
MA_API void ma_sound_group_set_velocity(ma_sound_group* pGroup, float x, float y, float z);
|
||||
MA_API ma_vec3f ma_sound_group_get_velocity(const ma_sound_group* pGroup);
|
||||
MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_attenuation_model attenuationModel);
|
||||
MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_attenuation_model attenuationModel, void* pAttenuationUserData);
|
||||
MA_API ma_attenuation_model ma_sound_group_get_attenuation_model(const ma_sound_group* pGroup);
|
||||
MA_API void ma_sound_group_set_positioning(ma_sound_group* pGroup, ma_positioning positioning);
|
||||
MA_API ma_positioning ma_sound_group_get_positioning(const ma_sound_group* pGroup);
|
||||
@@ -60034,9 +60065,20 @@ static ma_vec3f ma_get_channel_direction(ma_channel channel)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static float ma_attenuation_inverse(float distance, float minDistance, float maxDistance, float rolloff)
|
||||
MA_API float ma_attenuation_model_none(void* pUserData, float distance, float minDistance, float maxDistance, float rolloff)
|
||||
{
|
||||
(void)pUserData;
|
||||
(void)distance;
|
||||
(void)minDistance;
|
||||
(void)maxDistance;
|
||||
(void)rolloff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
MA_API float ma_attenuation_model_inverse(void* pUserData, float distance, float minDistance, float maxDistance, float rolloff)
|
||||
{
|
||||
(void)pUserData;
|
||||
|
||||
if (minDistance >= maxDistance) {
|
||||
return 1; /* To avoid division by zero. Do not attenuate. */
|
||||
}
|
||||
@@ -60044,8 +60086,10 @@ static float ma_attenuation_inverse(float distance, float minDistance, float max
|
||||
return minDistance / (minDistance + rolloff * (ma_clamp(distance, minDistance, maxDistance) - minDistance));
|
||||
}
|
||||
|
||||
static float ma_attenuation_linear(float distance, float minDistance, float maxDistance, float rolloff)
|
||||
MA_API float ma_attenuation_model_linear(void* pUserData, float distance, float minDistance, float maxDistance, float rolloff)
|
||||
{
|
||||
(void)pUserData;
|
||||
|
||||
if (minDistance >= maxDistance) {
|
||||
return 1; /* To avoid division by zero. Do not attenuate. */
|
||||
}
|
||||
@@ -60053,8 +60097,10 @@ static float ma_attenuation_linear(float distance, float minDistance, float maxD
|
||||
return 1 - rolloff * (ma_clamp(distance, minDistance, maxDistance) - minDistance) / (maxDistance - minDistance);
|
||||
}
|
||||
|
||||
static float ma_attenuation_exponential(float distance, float minDistance, float maxDistance, float rolloff)
|
||||
MA_API float ma_attenuation_model_exponential(void* pUserData, float distance, float minDistance, float maxDistance, float rolloff)
|
||||
{
|
||||
(void)pUserData;
|
||||
|
||||
if (minDistance >= maxDistance) {
|
||||
return 1; /* To avoid division by zero. Do not attenuate. */
|
||||
}
|
||||
@@ -60063,6 +60109,8 @@ static float ma_attenuation_exponential(float distance, float minDistance, float
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Doppler Effect calculation taken from the OpenAL spec, with two main differences:
|
||||
|
||||
@@ -60573,6 +60621,7 @@ MA_API ma_result ma_spatializer_init_preallocated(const ma_spatializer_config* p
|
||||
pSpatializer->channelsIn = pConfig->channelsIn;
|
||||
pSpatializer->channelsOut = pConfig->channelsOut;
|
||||
pSpatializer->attenuationModel = pConfig->attenuationModel;
|
||||
pSpatializer->pAttenuationUserData = pConfig->pAttenuationUserData;
|
||||
pSpatializer->positioning = pConfig->positioning;
|
||||
pSpatializer->handedness = pConfig->handedness;
|
||||
pSpatializer->minGain = pConfig->minGain;
|
||||
@@ -60718,6 +60767,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer,
|
||||
pChannelMapIn = pSpatializer->pChannelMapIn;
|
||||
pChannelMapOut = pListener->config.pChannelMapOut;
|
||||
|
||||
#if 0
|
||||
/* If we're not spatializing we need to run an optimized path. */
|
||||
if (ma_atomic_load_i32(&pSpatializer->attenuationModel) == ma_attenuation_model_none) {
|
||||
if (ma_spatializer_listener_is_enabled(pListener)) {
|
||||
@@ -60737,7 +60787,9 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer,
|
||||
the correct thinking so might need to review this later.
|
||||
*/
|
||||
pSpatializer->dopplerPitch = 1;
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
Let's first determine which listener the sound is closest to. Need to keep in mind that we
|
||||
might not have a world or any listeners, in which case we just spatializer based on the
|
||||
@@ -60780,24 +60832,10 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer,
|
||||
distance = ma_vec3f_len(relativePos);
|
||||
|
||||
/* We've gathered the data, so now we can apply some spatialization. */
|
||||
switch (ma_spatializer_get_attenuation_model(pSpatializer)) {
|
||||
case ma_attenuation_model_inverse:
|
||||
{
|
||||
gain = ma_attenuation_inverse(distance, minDistance, maxDistance, rolloff);
|
||||
} break;
|
||||
case ma_attenuation_model_linear:
|
||||
{
|
||||
gain = ma_attenuation_linear(distance, minDistance, maxDistance, rolloff);
|
||||
} break;
|
||||
case ma_attenuation_model_exponential:
|
||||
{
|
||||
gain = ma_attenuation_exponential(distance, minDistance, maxDistance, rolloff);
|
||||
} break;
|
||||
case ma_attenuation_model_none:
|
||||
default:
|
||||
{
|
||||
gain = 1;
|
||||
} break;
|
||||
if (pSpatializer->attenuationModel != NULL) {
|
||||
gain = pSpatializer->attenuationModel(pSpatializer->pAttenuationUserData, distance, minDistance, maxDistance, rolloff);
|
||||
} else {
|
||||
gain = ma_attenuation_model_none(NULL, distance, minDistance, maxDistance, rolloff);
|
||||
}
|
||||
|
||||
/* Normalize the position. */
|
||||
@@ -61048,13 +61086,14 @@ MA_API ma_uint32 ma_spatializer_get_output_channels(const ma_spatializer* pSpati
|
||||
return pSpatializer->channelsOut;
|
||||
}
|
||||
|
||||
MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel)
|
||||
MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel, void* pAttenuationUserData)
|
||||
{
|
||||
if (pSpatializer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ma_atomic_exchange_i32(&pSpatializer->attenuationModel, attenuationModel);
|
||||
pSpatializer->attenuationModel = attenuationModel;
|
||||
pSpatializer->pAttenuationUserData = pAttenuationUserData;
|
||||
}
|
||||
|
||||
MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer* pSpatializer)
|
||||
@@ -61063,7 +61102,7 @@ MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatia
|
||||
return ma_attenuation_model_none;
|
||||
}
|
||||
|
||||
return (ma_attenuation_model)ma_atomic_load_i32(&pSpatializer->attenuationModel);
|
||||
return pSpatializer->attenuationModel;
|
||||
}
|
||||
|
||||
MA_API void ma_spatializer_set_positioning(ma_spatializer* pSpatializer, ma_positioning positioning)
|
||||
@@ -88507,13 +88546,13 @@ MA_API ma_vec3f ma_sound_get_velocity(const ma_sound* pSound)
|
||||
return ma_spatializer_get_velocity(&pSound->engineNode.spatializer);
|
||||
}
|
||||
|
||||
MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_model attenuationModel)
|
||||
MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_model attenuationModel, void* pAttenuationUserData)
|
||||
{
|
||||
if (pSound == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ma_spatializer_set_attenuation_model(&pSound->engineNode.spatializer, attenuationModel);
|
||||
ma_spatializer_set_attenuation_model(&pSound->engineNode.spatializer, attenuationModel, pAttenuationUserData);
|
||||
}
|
||||
|
||||
MA_API ma_attenuation_model ma_sound_get_attenuation_model(const ma_sound* pSound)
|
||||
@@ -89213,9 +89252,9 @@ MA_API ma_vec3f ma_sound_group_get_velocity(const ma_sound_group* pGroup)
|
||||
return ma_sound_get_velocity(pGroup);
|
||||
}
|
||||
|
||||
MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_attenuation_model attenuationModel)
|
||||
MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_attenuation_model attenuationModel, void* pAttenuationUserData)
|
||||
{
|
||||
ma_sound_set_attenuation_model(pGroup, attenuationModel);
|
||||
ma_sound_set_attenuation_model(pGroup, attenuationModel, pAttenuationUserData);
|
||||
}
|
||||
|
||||
MA_API ma_attenuation_model ma_sound_group_get_attenuation_model(const ma_sound_group* pGroup)
|
||||
|
||||
Reference in New Issue
Block a user