Commit 9c18db9a authored by David Reid's avatar David Reid

Begin work on enabling the new DSP system.

DSP is broken with this commit.
parent 7e2d176a
...@@ -529,33 +529,34 @@ typedef int mal_result; ...@@ -529,33 +529,34 @@ typedef int mal_result;
#define MAL_SUCCESS 0 #define MAL_SUCCESS 0
#define MAL_ERROR -1 // A generic error. #define MAL_ERROR -1 // A generic error.
#define MAL_INVALID_ARGS -2 #define MAL_INVALID_ARGS -2
#define MAL_OUT_OF_MEMORY -3 #define MAL_INVALID_OPERATION -3
#define MAL_FORMAT_NOT_SUPPORTED -4 #define MAL_OUT_OF_MEMORY -4
#define MAL_NO_BACKEND -5 #define MAL_FORMAT_NOT_SUPPORTED -5
#define MAL_NO_DEVICE -6 #define MAL_NO_BACKEND -6
#define MAL_API_NOT_FOUND -7 #define MAL_NO_DEVICE -7
#define MAL_DEVICE_BUSY -8 #define MAL_API_NOT_FOUND -8
#define MAL_DEVICE_NOT_INITIALIZED -9 #define MAL_DEVICE_BUSY -9
#define MAL_DEVICE_ALREADY_STARTED -10 #define MAL_DEVICE_NOT_INITIALIZED -10
#define MAL_DEVICE_ALREADY_STARTING -11 #define MAL_DEVICE_ALREADY_STARTED -11
#define MAL_DEVICE_ALREADY_STOPPED -12 #define MAL_DEVICE_ALREADY_STARTING -12
#define MAL_DEVICE_ALREADY_STOPPING -13 #define MAL_DEVICE_ALREADY_STOPPED -13
#define MAL_FAILED_TO_MAP_DEVICE_BUFFER -14 #define MAL_DEVICE_ALREADY_STOPPING -14
#define MAL_FAILED_TO_UNMAP_DEVICE_BUFFER -15 #define MAL_FAILED_TO_MAP_DEVICE_BUFFER -15
#define MAL_FAILED_TO_INIT_BACKEND -16 #define MAL_FAILED_TO_UNMAP_DEVICE_BUFFER -16
#define MAL_FAILED_TO_READ_DATA_FROM_CLIENT -17 #define MAL_FAILED_TO_INIT_BACKEND -17
#define MAL_FAILED_TO_READ_DATA_FROM_DEVICE -18 #define MAL_FAILED_TO_READ_DATA_FROM_CLIENT -18
#define MAL_FAILED_TO_SEND_DATA_TO_CLIENT -19 #define MAL_FAILED_TO_READ_DATA_FROM_DEVICE -19
#define MAL_FAILED_TO_SEND_DATA_TO_DEVICE -20 #define MAL_FAILED_TO_SEND_DATA_TO_CLIENT -20
#define MAL_FAILED_TO_OPEN_BACKEND_DEVICE -21 #define MAL_FAILED_TO_SEND_DATA_TO_DEVICE -21
#define MAL_FAILED_TO_START_BACKEND_DEVICE -22 #define MAL_FAILED_TO_OPEN_BACKEND_DEVICE -22
#define MAL_FAILED_TO_STOP_BACKEND_DEVICE -23 #define MAL_FAILED_TO_START_BACKEND_DEVICE -23
#define MAL_FAILED_TO_CONFIGURE_BACKEND_DEVICE -24 #define MAL_FAILED_TO_STOP_BACKEND_DEVICE -24
#define MAL_FAILED_TO_CREATE_MUTEX -25 #define MAL_FAILED_TO_CONFIGURE_BACKEND_DEVICE -25
#define MAL_FAILED_TO_CREATE_EVENT -26 #define MAL_FAILED_TO_CREATE_MUTEX -26
#define MAL_FAILED_TO_CREATE_THREAD -27 #define MAL_FAILED_TO_CREATE_EVENT -27
#define MAL_INVALID_DEVICE_CONFIG -28 #define MAL_FAILED_TO_CREATE_THREAD -28
#define MAL_ACCESS_DENIED -29 #define MAL_INVALID_DEVICE_CONFIG -29
#define MAL_ACCESS_DENIED -30
typedef void (* mal_log_proc) (mal_context* pContext, mal_device* pDevice, const char* message); typedef void (* mal_log_proc) (mal_context* pContext, mal_device* pDevice, const char* message);
typedef void (* mal_recv_proc)(mal_device* pDevice, mal_uint32 frameCount, const void* pSamples); typedef void (* mal_recv_proc)(mal_device* pDevice, mal_uint32 frameCount, const void* pSamples);
...@@ -768,8 +769,6 @@ typedef struct ...@@ -768,8 +769,6 @@ typedef struct
{ {
mal_uint32 sampleRateIn; mal_uint32 sampleRateIn;
mal_uint32 sampleRateOut; mal_uint32 sampleRateOut;
mal_format formatIn;
mal_format formatOut;
mal_uint32 channels; mal_uint32 channels;
mal_src_algorithm algorithm; mal_src_algorithm algorithm;
mal_src_read_proc onRead; mal_src_read_proc onRead;
...@@ -809,6 +808,7 @@ typedef struct ...@@ -809,6 +808,7 @@ typedef struct
mal_channel channelMapOut[MAL_MAX_CHANNELS]; mal_channel channelMapOut[MAL_MAX_CHANNELS];
mal_channel_mix_mode channelMixMode; mal_channel_mix_mode channelMixMode;
mal_src_algorithm srcAlgorithm; mal_src_algorithm srcAlgorithm;
mal_bool32 allowDynamicSampleRate;
mal_dsp_read_proc onRead; mal_dsp_read_proc onRead;
void* pUserData; void* pUserData;
} mal_dsp_config; } mal_dsp_config;
...@@ -821,6 +821,7 @@ struct mal_dsp ...@@ -821,6 +821,7 @@ struct mal_dsp
mal_format_converter formatConverterOut; // For converting data to the requested output format. Used as the final step in the processing pipeline. mal_format_converter formatConverterOut; // For converting data to the requested output format. Used as the final step in the processing pipeline.
mal_channel_router channelRouter; // For channel conversion. mal_channel_router channelRouter; // For channel conversion.
mal_src src; // For sample rate conversion. mal_src src; // For sample rate conversion.
mal_bool32 isDynamicSampleRateAllowed : 1; // mal_dsp_set_input_sample_rate() and mal_dsp_set_output_sample_rate() will fail if this is set to false.
mal_bool32 isPreFormatConversionRequired : 1; mal_bool32 isPreFormatConversionRequired : 1;
mal_bool32 isPostFormatConversionRequired : 1; mal_bool32 isPostFormatConversionRequired : 1;
mal_bool32 isChannelRoutingRequired : 1; mal_bool32 isChannelRoutingRequired : 1;
...@@ -1911,12 +1912,16 @@ mal_uint64 mal_src_read_deinterleaved_ex(mal_src* pSRC, mal_uint64 frameCount, v ...@@ -1911,12 +1912,16 @@ mal_uint64 mal_src_read_deinterleaved_ex(mal_src* pSRC, mal_uint64 frameCount, v
mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP); mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP);
// Dynamically adjusts the input sample rate. // Dynamically adjusts the input sample rate.
//
// This will fail is the DSP was not initialized with allowDynamicSampleRate.
mal_result mal_dsp_set_input_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateOut); mal_result mal_dsp_set_input_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateOut);
// Dynamically adjusts the output sample rate. // Dynamically adjusts the output sample rate.
// //
// This is useful for dynamically adjust pitch. Keep in mind, however, that this will speed up or slow down the sound. If this // This is useful for dynamically adjust pitch. Keep in mind, however, that this will speed up or slow down the sound. If this
// is not acceptable you will need to use your own algorithm. // is not acceptable you will need to use your own algorithm.
//
// This will fail is the DSP was not initialized with allowDynamicSampleRate.
mal_result mal_dsp_set_output_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateOut); mal_result mal_dsp_set_output_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateOut);
// Reads a number of frames and runs them through the DSP processor. // Reads a number of frames and runs them through the DSP processor.
...@@ -17816,29 +17821,13 @@ mal_uint32 mal_src_cache_read_frames(mal_src_cache* pCache, mal_uint32 frameCoun ...@@ -17816,29 +17821,13 @@ mal_uint32 mal_src_cache_read_frames(mal_src_cache* pCache, mal_uint32 frameCoun
pFramesOut += framesToReadFromMemory * channels; pFramesOut += framesToReadFromMemory * channels;
pCache->iNextFrame = 0; pCache->iNextFrame = 0;
pCache->cachedFrameCount = 0;
if (pCache->pSRC->config.formatIn == mal_format_f32) {
// No need for a conversion - read straight into the cache.
mal_uint32 framesToReadFromClient = mal_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels;
if (framesToReadFromClient > MAL_SRC_CACHE_SIZE_IN_FRAMES) {
framesToReadFromClient = MAL_SRC_CACHE_SIZE_IN_FRAMES;
}
pCache->cachedFrameCount = pCache->pSRC->config.onRead(pCache->pSRC, framesToReadFromClient, pCache->pCachedFrames, pUserData);
} else {
// A format conversion is required which means we need to use an intermediary buffer.
mal_uint8 pIntermediaryBuffer[sizeof(pCache->pCachedFrames)];
mal_uint32 framesToReadFromClient = mal_min(mal_buffer_frame_capacity(pIntermediaryBuffer, channels, pCache->pSRC->config.formatIn), mal_buffer_frame_capacity(pCache->pCachedFrames, channels, mal_format_f32));
if (framesToReadFromClient > MAL_SRC_CACHE_SIZE_IN_FRAMES) {
framesToReadFromClient = MAL_SRC_CACHE_SIZE_IN_FRAMES;
}
pCache->cachedFrameCount = pCache->pSRC->config.onRead(pCache->pSRC, framesToReadFromClient, pIntermediaryBuffer, pUserData);
// Convert to f32. mal_uint32 framesToReadFromClient = mal_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels;
mal_pcm_convert(pCache->pCachedFrames, mal_format_f32, pIntermediaryBuffer, pCache->pSRC->config.formatIn, pCache->cachedFrameCount * channels, mal_dither_mode_none); if (framesToReadFromClient > MAL_SRC_CACHE_SIZE_IN_FRAMES) {
framesToReadFromClient = MAL_SRC_CACHE_SIZE_IN_FRAMES;
} }
pCache->cachedFrameCount = pCache->pSRC->config.onRead(pCache->pSRC, framesToReadFromClient, pCache->pCachedFrames, pUserData);
// Get out of this loop if nothing was able to be retrieved. // Get out of this loop if nothing was able to be retrieved.
if (pCache->cachedFrameCount == 0) { if (pCache->cachedFrameCount == 0) {
...@@ -17954,55 +17943,28 @@ mal_uint64 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint64 frameCount, ...@@ -17954,55 +17943,28 @@ mal_uint64 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint64 frameCount,
(void)flush; // Passthrough need not care about flushing. (void)flush; // Passthrough need not care about flushing.
// Fast path. No need for data conversion - just pass right through. if (frameCount <= UINT32_MAX) {
if (pSRC->config.formatIn == pSRC->config.formatOut) { return pSRC->config.onRead(pSRC, (mal_uint32)frameCount, pFramesOut, pUserData);
if (frameCount <= UINT32_MAX) { } else {
return pSRC->config.onRead(pSRC, (mal_uint32)frameCount, pFramesOut, pUserData); mal_uint64 totalFramesRead = 0;
} else { while (frameCount > 0) {
mal_uint64 totalFramesRead = 0; mal_uint32 framesToReadRightNow = UINT32_MAX;
while (frameCount > 0) { if (framesToReadRightNow > frameCount) {
mal_uint32 framesToReadRightNow = UINT32_MAX; framesToReadRightNow = (mal_uint32)frameCount;
if (framesToReadRightNow > frameCount) {
framesToReadRightNow = (mal_uint32)frameCount;
}
mal_uint32 framesRead = pSRC->config.onRead(pSRC, framesToReadRightNow, pFramesOut, pUserData);
if (framesRead == 0) {
break;
}
pFramesOut = (mal_uint8*)pFramesOut + (framesRead * pSRC->config.channels * mal_get_bytes_per_sample(pSRC->config.formatOut));
frameCount -= framesRead;
totalFramesRead += framesRead;
} }
return totalFramesRead; mal_uint32 framesRead = pSRC->config.onRead(pSRC, framesToReadRightNow, pFramesOut, pUserData);
} if (framesRead == 0) {
} break;
}
// Slower path. Need to do a format conversion.
mal_uint64 totalFramesRead = 0;
while (frameCount > 0) {
mal_uint8 pStagingBuffer[MAL_MAX_CHANNELS * 2048];
mal_uint32 stagingBufferSizeInFrames = sizeof(pStagingBuffer) / mal_get_bytes_per_sample(pSRC->config.formatIn) / pSRC->config.channels;
mal_uint32 framesToRead = stagingBufferSizeInFrames;
if (framesToRead > frameCount) {
framesToRead = (mal_uint32)frameCount;
}
mal_uint32 framesRead = pSRC->config.onRead(pSRC, framesToRead, pStagingBuffer, pUserData); pFramesOut = (mal_uint8*)pFramesOut + (framesRead * pSRC->config.channels * sizeof(float));
if (framesRead == 0) { frameCount -= framesRead;
break; totalFramesRead += framesRead;
} }
mal_pcm_convert(pFramesOut, pSRC->config.formatOut, pStagingBuffer, pSRC->config.formatIn, framesRead * pSRC->config.channels, mal_dither_mode_none); return totalFramesRead;
pFramesOut = (mal_uint8*)pFramesOut + (framesRead * pSRC->config.channels * mal_get_bytes_per_sample(pSRC->config.formatOut));
frameCount -= framesRead;
totalFramesRead += framesRead;
} }
return totalFramesRead;
} }
mal_uint64 mal_src_read_frames_linear(mal_src* pSRC, mal_uint64 frameCount, void* pFramesOut, mal_bool32 flush, void* pUserData) mal_uint64 mal_src_read_frames_linear(mal_src* pSRC, mal_uint64 frameCount, void* pFramesOut, mal_bool32 flush, void* pUserData)
...@@ -18069,9 +18031,10 @@ mal_uint64 mal_src_read_frames_linear(mal_src* pSRC, mal_uint64 frameCount, void ...@@ -18069,9 +18031,10 @@ mal_uint64 mal_src_read_frames_linear(mal_src* pSRC, mal_uint64 frameCount, void
} }
} }
mal_pcm_convert(pFramesOut, pSRC->config.formatOut, pFrame, mal_format_f32, 1 * pSRC->config.channels, mal_dither_mode_none); //mal_pcm_convert(pFramesOut, pSRC->config.formatOut, pFrame, mal_format_f32, 1 * pSRC->config.channels, mal_dither_mode_none);
mal_copy_memory(pFramesOut, pFrame, 1 * pSRC->config.channels * sizeof(float));
pFramesOut = (mal_uint8*)pFramesOut + (1 * pSRC->config.channels * mal_get_bytes_per_sample(pSRC->config.formatOut)); pFramesOut = (mal_uint8*)pFramesOut + (1 * pSRC->config.channels * sizeof(float));
frameCount -= 1; frameCount -= 1;
totalFramesRead += 1; totalFramesRead += 1;
...@@ -18806,7 +18769,7 @@ mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP) ...@@ -18806,7 +18769,7 @@ mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP)
// Notice how the Channel Routing and Sample Rate Conversion stages are swapped so that the SRC stage has less data to process. // Notice how the Channel Routing and Sample Rate Conversion stages are swapped so that the SRC stage has less data to process.
// First we need to determin what's required and what's not. // First we need to determin what's required and what's not.
if (pConfig->sampleRateIn != pConfig->sampleRateOut) { if (pConfig->sampleRateIn != pConfig->sampleRateOut || pConfig->allowDynamicSampleRate) {
pDSP->isSRCRequired = MAL_TRUE; pDSP->isSRCRequired = MAL_TRUE;
} }
if (pConfig->channelsIn != pConfig->channelsOut || !mal_channel_map_equal(pConfig->channelsIn, pConfig->channelMapIn, pConfig->channelMapOut)) { if (pConfig->channelsIn != pConfig->channelsOut || !mal_channel_map_equal(pConfig->channelsIn, pConfig->channelMapIn, pConfig->channelMapOut)) {
...@@ -18885,9 +18848,7 @@ mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP) ...@@ -18885,9 +18848,7 @@ mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP)
mal_zero_object(&srcConfig); mal_zero_object(&srcConfig);
srcConfig.sampleRateIn = pConfig->sampleRateIn; srcConfig.sampleRateIn = pConfig->sampleRateIn;
srcConfig.sampleRateOut = pConfig->sampleRateOut; srcConfig.sampleRateOut = pConfig->sampleRateOut;
srcConfig.formatIn = pConfig->formatIn; srcConfig.channels = (pConfig->channelsIn < pConfig->channelsOut) ? pConfig->channelsIn : pConfig->channelsOut;
srcConfig.formatOut = mal_format_f32;
srcConfig.channels = pConfig->channelsIn;
srcConfig.algorithm = pConfig->srcAlgorithm; srcConfig.algorithm = pConfig->srcAlgorithm;
srcConfig.onRead = mal_dsp__src_on_read; srcConfig.onRead = mal_dsp__src_on_read;
srcConfig.onReadDeinterleaved = mal_dsp__src_on_read_deinterleaved; srcConfig.onReadDeinterleaved = mal_dsp__src_on_read_deinterleaved;
...@@ -18916,7 +18877,7 @@ mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP) ...@@ -18916,7 +18877,7 @@ mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP)
#if 0
pDSP->isChannelMappingRequired = MAL_FALSE; pDSP->isChannelMappingRequired = MAL_FALSE;
if (pConfig->channelMapIn[0] != MAL_CHANNEL_NONE && pConfig->channelMapOut[0] != MAL_CHANNEL_NONE) { // <-- Channel mapping will be ignored if the first channel map is MAL_CHANNEL_NONE. if (pConfig->channelMapIn[0] != MAL_CHANNEL_NONE && pConfig->channelMapOut[0] != MAL_CHANNEL_NONE) { // <-- Channel mapping will be ignored if the first channel map is MAL_CHANNEL_NONE.
// When using channel mapping we need to figure out a shuffling table. The first thing to do is convert the input channel map // When using channel mapping we need to figure out a shuffling table. The first thing to do is convert the input channel map
...@@ -18976,6 +18937,7 @@ mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP) ...@@ -18976,6 +18937,7 @@ mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP)
} else { } else {
pDSP->isPassthrough = MAL_FALSE; pDSP->isPassthrough = MAL_FALSE;
} }
#endif
return MAL_SUCCESS; return MAL_SUCCESS;
} }
...@@ -18983,45 +18945,9 @@ mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP) ...@@ -18983,45 +18945,9 @@ mal_result mal_dsp_init(const mal_dsp_config* pConfig, mal_dsp* pDSP)
mal_result mal_dsp_refresh_sample_rate(mal_dsp* pDSP) mal_result mal_dsp_refresh_sample_rate(mal_dsp* pDSP)
{ {
// If we already have an SRC pipeline initialized we do _not_ want to re-create it. Instead we adjust it. If we didn't previously // The SRC stage will already have been initialized so we can just set it there.
// have an SRC pipeline in place we'll need to initialize it. mal_src_set_input_sample_rate(&pDSP->src, pDSP->src.config.sampleRateIn);
if (pDSP->isSRCRequired) { mal_src_set_output_sample_rate(&pDSP->src, pDSP->src.config.sampleRateOut);
if (pDSP->src.config.sampleRateIn != pDSP->src.config.sampleRateOut) {
mal_src_set_input_sample_rate(&pDSP->src, pDSP->src.config.sampleRateIn);
mal_src_set_output_sample_rate(&pDSP->src, pDSP->src.config.sampleRateOut);
} else {
pDSP->isSRCRequired = MAL_FALSE;
}
} else {
// We may need a new SRC pipeline.
if (pDSP->src.config.sampleRateIn != pDSP->src.config.sampleRateOut) {
pDSP->isSRCRequired = MAL_TRUE;
mal_src_config srcConfig;
srcConfig.sampleRateIn = pDSP->src.config.sampleRateIn;
srcConfig.sampleRateOut = pDSP->src.config.sampleRateOut;
srcConfig.formatIn = pDSP->src.config.formatIn;
srcConfig.formatOut = mal_format_f32;
srcConfig.channels = pDSP->channelRouter.config.channelsIn;
srcConfig.algorithm = pDSP->src.config.algorithm;
srcConfig.onRead = pDSP->src.config.onRead;
srcConfig.onReadDeinterleaved = pDSP->src.config.onReadDeinterleaved;
srcConfig.pUserData = pDSP->src.config.pUserData;
mal_result result = mal_src_init(&srcConfig, &pDSP->src);
if (result != MAL_SUCCESS) {
return result;
}
} else {
pDSP->isSRCRequired = MAL_FALSE;
}
}
// Update whether or not the pipeline is a passthrough.
if (pDSP->formatConverterIn.config.formatIn == pDSP->formatConverterOut.config.formatOut && pDSP->channelRouter.config.channelsIn == pDSP->channelRouter.config.channelsOut && pDSP->src.config.sampleRateIn == pDSP->src.config.sampleRateOut && !pDSP->isChannelMappingRequired) {
pDSP->isPassthrough = MAL_TRUE;
} else {
pDSP->isPassthrough = MAL_FALSE;
}
return MAL_SUCCESS; return MAL_SUCCESS;
} }
...@@ -19037,6 +18963,11 @@ mal_result mal_dsp_set_input_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateIn) ...@@ -19037,6 +18963,11 @@ mal_result mal_dsp_set_input_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateIn)
return MAL_INVALID_ARGS; return MAL_INVALID_ARGS;
} }
// Must have been initialized with allowDynamicSampleRate.
if (!pDSP->isDynamicSampleRateAllowed) {
return MAL_INVALID_OPERATION;
}
pDSP->src.config.sampleRateIn = sampleRateIn; pDSP->src.config.sampleRateIn = sampleRateIn;
return mal_dsp_refresh_sample_rate(pDSP); return mal_dsp_refresh_sample_rate(pDSP);
} }
...@@ -19052,6 +18983,11 @@ mal_result mal_dsp_set_output_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateOu ...@@ -19052,6 +18983,11 @@ mal_result mal_dsp_set_output_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateOu
return MAL_INVALID_ARGS; return MAL_INVALID_ARGS;
} }
// Must have been initialized with allowDynamicSampleRate.
if (!pDSP->isDynamicSampleRateAllowed) {
return MAL_INVALID_OPERATION;
}
pDSP->src.config.sampleRateOut = sampleRateOut; pDSP->src.config.sampleRateOut = sampleRateOut;
return mal_dsp_refresh_sample_rate(pDSP); return mal_dsp_refresh_sample_rate(pDSP);
} }
...@@ -19067,23 +19003,25 @@ mal_uint64 mal_dsp_read_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pFramesOu ...@@ -19067,23 +19003,25 @@ mal_uint64 mal_dsp_read_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pFramesOu
// Fast path. // Fast path.
if (pDSP->isPassthrough) { if (pDSP->isPassthrough) {
if (frameCount <= UINT32_MAX) { if (frameCount <= 0xFFFFFFFF) {
return (mal_uint32)pDSP->onRead(pDSP, (mal_uint32)frameCount, pFramesOut, pUserData); return (mal_uint32)pDSP->onRead(pDSP, (mal_uint32)frameCount, pFramesOut, pUserData);
} else { } else {
mal_uint8* pNextFramesOut = (mal_uint8*)pFramesOut;
mal_uint64 totalFramesRead = 0; mal_uint64 totalFramesRead = 0;
while (frameCount > 0) { while (totalFramesRead < frameCount) {
mal_uint32 framesToReadRightNow = UINT32_MAX; mal_uint64 framesRemaining = (frameCount - totalFramesRead);
if (framesToReadRightNow > frameCount) { mal_uint64 framesToReadRightNow = framesRemaining;
framesToReadRightNow = (mal_uint32)frameCount; if (framesToReadRightNow > 0xFFFFFFFF) {
framesToReadRightNow = 0xFFFFFFFF;
} }
mal_uint32 framesRead = pDSP->onRead(pDSP, framesToReadRightNow, pFramesOut, pUserData); mal_uint32 framesRead = pDSP->onRead(pDSP, (mal_uint32)framesToReadRightNow, pNextFramesOut, pUserData);
if (framesRead == 0) { if (framesRead == 0) {
break; break;
} }
pFramesOut = (mal_uint8*)pFramesOut + (framesRead * pDSP->channelRouter.config.channelsOut * mal_get_bytes_per_sample(pDSP->formatConverterOut.config.formatOut)); pNextFramesOut += framesRead * pDSP->channelRouter.config.channelsOut * mal_get_bytes_per_sample(pDSP->formatConverterOut.config.formatOut);
frameCount -= framesRead;
totalFramesRead += framesRead; totalFramesRead += framesRead;
} }
...@@ -19091,10 +19029,19 @@ mal_uint64 mal_dsp_read_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pFramesOu ...@@ -19091,10 +19029,19 @@ mal_uint64 mal_dsp_read_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pFramesOu
} }
} }
// Slower path. The real is done here. To do this all we need to do is read from the last stage in the pipeline.
mal_assert(pDSP->isPostFormatConversionRequired == MAL_TRUE);
mal_dsp_callback_data data;
data.pDSP = pDSP;
data.flush = flush;
data.pUserDataForClient = pUserData;
return mal_format_converter_read(&pDSP->formatConverterOut, frameCount, pFramesOut, &data);
#if 0
// Slower path - where the real work is done. // Slower path - where the real work is done.
mal_uint8 pFrames[2][MAL_MAX_CHANNELS * 512 * MAL_MAX_PCM_SAMPLE_SIZE_IN_BYTES]; mal_uint8 pFrames[2][MAL_MAX_CHANNELS * 512 * MAL_MAX_PCM_SAMPLE_SIZE_IN_BYTES];
mal_format pFramesFormat[2];
mal_uint64 totalFramesRead = 0; mal_uint64 totalFramesRead = 0;
while (frameCount > 0) { while (frameCount > 0) {
...@@ -19109,10 +19056,8 @@ mal_uint64 mal_dsp_read_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pFramesOu ...@@ -19109,10 +19056,8 @@ mal_uint64 mal_dsp_read_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pFramesOu
mal_uint32 framesRead = 0; mal_uint32 framesRead = 0;
if (pDSP->isSRCRequired) { if (pDSP->isSRCRequired) {
framesRead = (mal_uint32)mal_src_read_ex(&pDSP->src, framesToRead, pFrames[iFrames], flush, pUserData); framesRead = (mal_uint32)mal_src_read_ex(&pDSP->src, framesToRead, pFrames[iFrames], flush, pUserData);
pFramesFormat[iFrames] = pDSP->src.config.formatOut; // Should always be f32.
} else { } else {
framesRead = pDSP->onRead(pDSP, framesToRead, pFrames[iFrames], pUserData); framesRead = pDSP->onRead(pDSP, framesToRead, pFrames[iFrames], pUserData);
pFramesFormat[iFrames] = pDSP->formatConverterIn.config.formatIn;
} }
if (framesRead == 0) { if (framesRead == 0) {
...@@ -19122,28 +19067,21 @@ mal_uint64 mal_dsp_read_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pFramesOu ...@@ -19122,28 +19067,21 @@ mal_uint64 mal_dsp_read_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pFramesOu
// Channel mixing. The input format must be in f32 which may require a conversion. // Channel mixing. The input format must be in f32 which may require a conversion.
if (pDSP->channelRouter.config.channelsIn != pDSP->channelRouter.config.channelsOut) { if (pDSP->channelRouter.config.channelsIn != pDSP->channelRouter.config.channelsOut) {
if (pFramesFormat[iFrames] != mal_format_f32) {
mal_pcm_convert(pFrames[(iFrames + 1) % 2], mal_format_f32, pFrames[iFrames], pDSP->formatConverterIn.config.formatIn, framesRead * pDSP->channelRouter.config.channelsIn, mal_dither_mode_none);
iFrames = (iFrames + 1) % 2;
pFramesFormat[iFrames] = mal_format_f32;
}
mal_dsp_mix_channels((float*)(pFrames[(iFrames + 1) % 2]), pDSP->channelRouter.config.channelsOut, pDSP->channelRouter.config.channelMapOut, (const float*)(pFrames[iFrames]), pDSP->channelRouter.config.channelsIn, pDSP->channelRouter.config.channelMapIn, framesRead, pDSP->channelRouter.config.mixingMode); mal_dsp_mix_channels((float*)(pFrames[(iFrames + 1) % 2]), pDSP->channelRouter.config.channelsOut, pDSP->channelRouter.config.channelMapOut, (const float*)(pFrames[iFrames]), pDSP->channelRouter.config.channelsIn, pDSP->channelRouter.config.channelMapIn, framesRead, pDSP->channelRouter.config.mixingMode);
iFrames = (iFrames + 1) % 2; iFrames = (iFrames + 1) % 2;
pFramesFormat[iFrames] = mal_format_f32;
} }
// Channel mapping. // Channel mapping.
if (pDSP->isChannelMappingRequired) { if (pDSP->isChannelMappingRequired) {
for (mal_uint32 i = 0; i < framesRead; ++i) { for (mal_uint32 i = 0; i < framesRead; ++i) {
mal_rearrange_channels(pFrames[iFrames] + (i * pDSP->channelRouter.config.channelsOut * mal_get_bytes_per_sample(pFramesFormat[iFrames])), pDSP->channelRouter.config.channelsOut, pDSP->channelShuffleTable, pFramesFormat[iFrames]); mal_rearrange_channels(pFrames[iFrames] + (i * pDSP->channelRouter.config.channelsOut * mal_get_bytes_per_sample(mal_format_f32)), pDSP->channelRouter.config.channelsOut, pDSP->channelShuffleTable, mal_format_f32);
} }
} }
// Final conversion to output format. // Final conversion to output format.
mal_pcm_convert(pFramesOut, pDSP->formatConverterOut.config.formatOut, pFrames[iFrames], pFramesFormat[iFrames], framesRead * pDSP->channelRouter.config.channelsOut, mal_dither_mode_none); mal_pcm_convert(pFramesOut, pDSP->formatConverterOut.config.formatOut, pFrames[iFrames], mal_format_f32, framesRead * pDSP->channelRouter.config.channelsOut, mal_dither_mode_none);
pFramesOut = (mal_uint8*)pFramesOut + (framesRead * pDSP->channelRouter.config.channelsOut * mal_get_bytes_per_sample(pDSP->formatConverterOut.config.formatOut)); pFramesOut = (mal_uint8*)pFramesOut + (framesRead * pDSP->channelRouter.config.channelsOut * mal_get_bytes_per_sample(pDSP->formatConverterOut.config.formatOut));
frameCount -= framesRead; frameCount -= framesRead;
...@@ -19151,6 +19089,7 @@ mal_uint64 mal_dsp_read_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pFramesOu ...@@ -19151,6 +19089,7 @@ mal_uint64 mal_dsp_read_ex(mal_dsp* pDSP, mal_uint64 frameCount, void* pFramesOu
} }
return totalFramesRead; return totalFramesRead;
#endif
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment