Optimize sounds by applying volume via the gainer.

By using the gainer to apply the master volume, we can essentially get
master volume control for free by premultiplying the per-channel
volumes by the master volume before processing.
This commit is contained in:
David Reid
2022-11-24 14:17:16 +10:00
parent 50f3e12e52
commit 72f1fe386b
+44 -10
View File
@@ -4908,7 +4908,7 @@ MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesO
MA_API ma_result ma_gainer_set_gain(ma_gainer* pGainer, float newGain); MA_API ma_result ma_gainer_set_gain(ma_gainer* pGainer, float newGain);
MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains); MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains);
MA_API ma_result ma_gainer_set_master_volume(ma_gainer* pGainer, float volume); MA_API ma_result ma_gainer_set_master_volume(ma_gainer* pGainer, float volume);
MA_API ma_result ma_gainer_get_master_volume(ma_gainer* pGainer, float* pVolume); MA_API ma_result ma_gainer_get_master_volume(const ma_gainer* pGainer, float* pVolume);
@@ -5113,7 +5113,7 @@ MA_API ma_result ma_spatializer_init(const ma_spatializer_config* pConfig, const
MA_API void ma_spatializer_uninit(ma_spatializer* pSpatializer, const ma_allocation_callbacks* pAllocationCallbacks); MA_API void ma_spatializer_uninit(ma_spatializer* pSpatializer, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_spatializer_listener* pListener, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount); MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_spatializer_listener* pListener, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
MA_API ma_result ma_spatializer_set_master_volume(ma_spatializer* pSpatializer, float volume); MA_API ma_result ma_spatializer_set_master_volume(ma_spatializer* pSpatializer, float volume);
MA_API ma_result ma_spatializer_get_master_volume(ma_spatializer* pSpatializer, float* pVolume); 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_input_channels(const ma_spatializer* pSpatializer);
MA_API ma_uint32 ma_spatializer_get_output_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);
@@ -47795,7 +47795,7 @@ static /*__attribute__((noinline))*/ ma_result ma_gainer_process_pcm_frames_inte
/* Initialize the running gain. */ /* Initialize the running gain. */
for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) { for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) {
float t = pGainer->pOldGains[iChannel] - pGainer->pNewGains[iChannel] * pGainer->masterVolume; float t = (pGainer->pOldGains[iChannel] - pGainer->pNewGains[iChannel]) * pGainer->masterVolume;
pRunningGainDelta[iChannel] = t * d; pRunningGainDelta[iChannel] = t * d;
pRunningGain[iChannel] = (pGainer->pOldGains[iChannel] * pGainer->masterVolume) + (t * a); pRunningGain[iChannel] = (pGainer->pOldGains[iChannel] * pGainer->masterVolume) + (t * a);
} }
@@ -48120,7 +48120,7 @@ MA_API ma_result ma_gainer_set_master_volume(ma_gainer* pGainer, float volume)
return MA_SUCCESS; return MA_SUCCESS;
} }
MA_API ma_result ma_gainer_get_master_volume(ma_gainer* pGainer, float* pVolume) MA_API ma_result ma_gainer_get_master_volume(const ma_gainer* pGainer, float* pVolume)
{ {
if (pGainer == NULL || pVolume == NULL) { if (pGainer == NULL || pVolume == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
@@ -49633,7 +49633,7 @@ MA_API ma_result ma_spatializer_set_master_volume(ma_spatializer* pSpatializer,
return ma_gainer_set_master_volume(&pSpatializer->gainer, volume); return ma_gainer_set_master_volume(&pSpatializer->gainer, volume);
} }
MA_API ma_result ma_spatializer_get_master_volume(ma_spatializer* pSpatializer, float* pVolume) MA_API ma_result ma_spatializer_get_master_volume(const ma_spatializer* pSpatializer, float* pVolume)
{ {
if (pSpatializer == NULL) { if (pSpatializer == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
@@ -72294,6 +72294,33 @@ static ma_uint64 ma_engine_node_get_required_input_frame_count(const ma_engine_n
return inputFrameCount; return inputFrameCount;
} }
static ma_result ma_engine_node_set_volume(ma_engine_node* pEngineNode, float volume)
{
if (pEngineNode == NULL) {
return MA_INVALID_ARGS;
}
/* We should always have an active spatializer because it can be enabled and disabled dynamically. We can just use that for hodling our volume. */
ma_spatializer_set_master_volume(&pEngineNode->spatializer, volume);
return MA_SUCCESS;
}
static ma_result ma_engine_node_get_volume(const ma_engine_node* pEngineNode, float* pVolume)
{
if (pVolume == NULL) {
return MA_INVALID_ARGS;
}
*pVolume = 0.0f;
if (pEngineNode == NULL) {
return MA_INVALID_ARGS;
}
return ma_spatializer_get_master_volume(&pEngineNode->spatializer, pVolume);
}
static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
{ {
ma_uint32 frameCountIn; ma_uint32 frameCountIn;
@@ -72419,13 +72446,17 @@ static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNo
ma_spatializer_process_pcm_frames(&pEngineNode->spatializer, &pEngineNode->pEngine->listeners[iListener], pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut); ma_spatializer_process_pcm_frames(&pEngineNode->spatializer, &pEngineNode->pEngine->listeners[iListener], pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut);
} else { } else {
/* No spatialization, but we still need to do channel conversion. */ /* No spatialization, but we still need to do channel conversion and master volume. */
float volume;
ma_engine_node_get_volume(pEngineNode, &volume); /* Should never fail. */
if (channelsIn == channelsOut) { if (channelsIn == channelsOut) {
/* No channel conversion required. Just copy straight to the output buffer. */ /* No channel conversion required. Just copy straight to the output buffer. */
ma_copy_pcm_frames(pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut, ma_format_f32, channelsOut); ma_copy_and_apply_volume_factor_f32(pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut * channelsOut, volume);
} else { } else {
/* Channel conversion required. TODO: Add support for channel maps here. */ /* Channel conversion required. TODO: Add support for channel maps here. */
ma_channel_map_apply_f32(pRunningFramesOut, NULL, channelsOut, pWorkingBuffer, NULL, channelsIn, framesJustProcessedOut, ma_channel_mix_mode_simple, pEngineNode->monoExpansionMode); ma_channel_map_apply_f32(pRunningFramesOut, NULL, channelsOut, pWorkingBuffer, NULL, channelsIn, framesJustProcessedOut, ma_channel_mix_mode_simple, pEngineNode->monoExpansionMode);
ma_apply_volume_factor_f32(pRunningFramesOut, framesJustProcessedOut * channelsOut, volume);
} }
} }
@@ -74175,17 +74206,20 @@ MA_API void ma_sound_set_volume(ma_sound* pSound, float volume)
return; return;
} }
/* The volume is controlled via the output bus. */ ma_engine_node_set_volume(&pSound->engineNode, volume);
ma_node_set_output_bus_volume(pSound, 0, volume);
} }
MA_API float ma_sound_get_volume(const ma_sound* pSound) MA_API float ma_sound_get_volume(const ma_sound* pSound)
{ {
float volume = 0;
if (pSound == NULL) { if (pSound == NULL) {
return 0; return 0;
} }
return ma_node_get_output_bus_volume(pSound, 0); ma_engine_node_get_volume(&pSound->engineNode, &volume);
return volume;
} }
MA_API void ma_sound_set_pan(ma_sound* pSound, float pan) MA_API void ma_sound_set_pan(ma_sound* pSound, float pan)