mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Add untested support for interleaved streams to the new resampler.
This commit is contained in:
@@ -83,6 +83,7 @@ typedef struct
|
|||||||
double ratio; /* ratio = in/out */
|
double ratio; /* ratio = in/out */
|
||||||
mal_resampler_algorithm algorithm;
|
mal_resampler_algorithm algorithm;
|
||||||
mal_resampler_end_of_input_mode endOfInputMode;
|
mal_resampler_end_of_input_mode endOfInputMode;
|
||||||
|
mal_stream_layout layout; /* Interleaved or deinterleaved. */
|
||||||
mal_resampler_read_from_client_proc onRead;
|
mal_resampler_read_from_client_proc onRead;
|
||||||
void* pUserData;
|
void* pUserData;
|
||||||
} mal_resampler_config;
|
} mal_resampler_config;
|
||||||
@@ -394,10 +395,17 @@ typedef union
|
|||||||
mal_int16* s16[MAL_MAX_CHANNELS];
|
mal_int16* s16[MAL_MAX_CHANNELS];
|
||||||
} mal_resampler_deinterleaved_pointers;
|
} mal_resampler_deinterleaved_pointers;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
float* f32;
|
||||||
|
mal_int16* s16;
|
||||||
|
} mal_resampler_interleaved_pointers;
|
||||||
|
|
||||||
mal_uint64 mal_resampler_read(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames)
|
mal_uint64 mal_resampler_read(mal_resampler* pResampler, mal_uint64 frameCount, void** ppFrames)
|
||||||
{
|
{
|
||||||
mal_uint64 totalFramesRead;
|
mal_uint64 totalFramesRead;
|
||||||
mal_resampler_deinterleaved_pointers runningFramesOut;
|
mal_resampler_deinterleaved_pointers runningFramesOutDeinterleaved;
|
||||||
|
mal_resampler_interleaved_pointers runningFramesOutInterleaved;
|
||||||
mal_bool32 atEnd = MAL_FALSE;
|
mal_bool32 atEnd = MAL_FALSE;
|
||||||
|
|
||||||
if (pResampler == NULL) {
|
if (pResampler == NULL) {
|
||||||
@@ -422,9 +430,15 @@ mal_uint64 mal_resampler_read(mal_resampler* pResampler, mal_uint64 frameCount,
|
|||||||
|
|
||||||
|
|
||||||
/* Initialization of the running frame pointers. */
|
/* Initialization of the running frame pointers. */
|
||||||
|
if (pResampler->config.layout == mal_stream_layout_deinterleaved) {
|
||||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||||
runningFramesOut.f32[iChannel] = (float*)ppFrames[iChannel];
|
runningFramesOutDeinterleaved.f32[iChannel] = (float*)ppFrames[iChannel];
|
||||||
}
|
}
|
||||||
|
runningFramesOutInterleaved.f32 = NULL; /* Silences a warning. */
|
||||||
|
} else {
|
||||||
|
runningFramesOutInterleaved.f32 = (float*)ppFrames[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The backend read callbacks are only called for ranges that can be read entirely from cache. This simplifies each backend
|
The backend read callbacks are only called for ranges that can be read entirely from cache. This simplifies each backend
|
||||||
@@ -456,24 +470,61 @@ mal_uint64 mal_resampler_read(mal_resampler* pResampler, mal_uint64 frameCount,
|
|||||||
mal_uint16 iFirstSample = (mal_uint16)pResampler->windowTime + mal_resampler_window_length_left(pResampler);
|
mal_uint16 iFirstSample = (mal_uint16)pResampler->windowTime + mal_resampler_window_length_left(pResampler);
|
||||||
if (pResampler->config.format == mal_format_f32) {
|
if (pResampler->config.format == mal_format_f32) {
|
||||||
for (mal_uint16 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
for (mal_uint16 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||||
|
if (pResampler->config.layout == mal_stream_layout_deinterleaved) {
|
||||||
for (mal_uint16 iFrame = 0; iFrame < framesToReadRightNow; ++iFrame) {
|
for (mal_uint16 iFrame = 0; iFrame < framesToReadRightNow; ++iFrame) {
|
||||||
runningFramesOut.f32[iChannel][iFrame] = pResampler->cache.f32[pResampler->cacheStrideInFrames*iChannel + iFirstSample + iFrame];
|
runningFramesOutDeinterleaved.f32[iChannel][iFrame] = pResampler->cache.f32[pResampler->cacheStrideInFrames*iChannel + iFirstSample + iFrame];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (mal_uint16 iFrame = 0; iFrame < framesToReadRightNow; ++iFrame) {
|
||||||
|
runningFramesOutInterleaved.f32[iFrame*pResampler->config.channels + iChannel] = pResampler->cache.f32[pResampler->cacheStrideInFrames*iChannel + iFirstSample + iFrame];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (mal_uint16 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
for (mal_uint16 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||||
|
if (pResampler->config.layout == mal_stream_layout_deinterleaved) {
|
||||||
for (mal_uint16 iFrame = 0; iFrame < framesToReadRightNow; ++iFrame) {
|
for (mal_uint16 iFrame = 0; iFrame < framesToReadRightNow; ++iFrame) {
|
||||||
runningFramesOut.s16[iChannel][iFrame] = pResampler->cache.s16[pResampler->cacheStrideInFrames*iChannel + iFirstSample + iFrame];
|
runningFramesOutDeinterleaved.s16[iChannel][iFrame] = pResampler->cache.s16[pResampler->cacheStrideInFrames*iChannel + iFirstSample + iFrame];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (mal_uint16 iFrame = 0; iFrame < framesToReadRightNow; ++iFrame) {
|
||||||
|
runningFramesOutInterleaved.s16[iFrame*pResampler->config.channels + iChannel] = pResampler->cache.s16[pResampler->cacheStrideInFrames*iChannel + iFirstSample + iFrame];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Need to read from the backend. */
|
/*
|
||||||
|
Need to read from the backend. Input data is always from the cache. Output data is always to a deinterleaved buffer. When the stream layout
|
||||||
|
is set to deinterleaved, we need to read into a temporary buffer and then interleave.
|
||||||
|
*/
|
||||||
mal_uint64 framesJustRead;
|
mal_uint64 framesJustRead;
|
||||||
if (pResampler->config.format == mal_format_f32) {
|
if (pResampler->config.format == mal_format_f32) {
|
||||||
framesJustRead = pResampler->readF32(pResampler, framesToReadRightNow, runningFramesOut.f32);
|
if (pResampler->config.layout == mal_stream_layout_deinterleaved) {
|
||||||
|
framesJustRead = pResampler->readF32(pResampler, framesToReadRightNow, runningFramesOutDeinterleaved.f32);
|
||||||
} else {
|
} else {
|
||||||
framesJustRead = pResampler->readS16(pResampler, framesToReadRightNow, runningFramesOut.s16);
|
float buffer[mal_countof(pResampler->cache.f32)];
|
||||||
|
float* ppDeinterleavedFrames[MAL_MAX_CHANNELS];
|
||||||
|
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||||
|
ppDeinterleavedFrames[iChannel] = buffer + (pResampler->cacheStrideInFrames*iChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
framesJustRead = pResampler->readF32(pResampler, framesToReadRightNow, ppDeinterleavedFrames);
|
||||||
|
mal_interleave_pcm_frames(pResampler->config.format, pResampler->config.channels, framesJustRead, (const void**)ppDeinterleavedFrames, runningFramesOutInterleaved.f32);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pResampler->config.layout == mal_stream_layout_interleaved) {
|
||||||
|
framesJustRead = pResampler->readS16(pResampler, framesToReadRightNow, runningFramesOutDeinterleaved.s16);
|
||||||
|
} else {
|
||||||
|
mal_int16 buffer[mal_countof(pResampler->cache.s16)];
|
||||||
|
mal_int16* ppDeinterleavedFrames[MAL_MAX_CHANNELS];
|
||||||
|
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||||
|
ppDeinterleavedFrames[iChannel] = buffer + (pResampler->cacheStrideInFrames*iChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
framesJustRead = pResampler->readS16(pResampler, framesToReadRightNow, ppDeinterleavedFrames);
|
||||||
|
mal_interleave_pcm_frames(pResampler->config.format, pResampler->config.channels, framesJustRead, (const void**)ppDeinterleavedFrames, runningFramesOutInterleaved.s16);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (framesJustRead != framesToReadRightNow) {
|
if (framesJustRead != framesToReadRightNow) {
|
||||||
@@ -486,12 +537,20 @@ mal_uint64 mal_resampler_read(mal_resampler* pResampler, mal_uint64 frameCount,
|
|||||||
pResampler->windowTime += (framesToReadRightNow * pResampler->config.ratio);
|
pResampler->windowTime += (framesToReadRightNow * pResampler->config.ratio);
|
||||||
|
|
||||||
if (pResampler->config.format == mal_format_f32) {
|
if (pResampler->config.format == mal_format_f32) {
|
||||||
|
if (pResampler->config.layout == mal_stream_layout_interleaved) {
|
||||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||||
runningFramesOut.f32[iChannel] += framesToReadRightNow;
|
runningFramesOutDeinterleaved.f32[iChannel] += framesToReadRightNow;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
runningFramesOutInterleaved.f32 += framesToReadRightNow * pResampler->config.channels;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pResampler->config.layout == mal_stream_layout_interleaved) {
|
||||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||||
runningFramesOut.s16[iChannel] += framesToReadRightNow;
|
runningFramesOutDeinterleaved.s16[iChannel] += framesToReadRightNow;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
runningFramesOutInterleaved.s16 += framesToReadRightNow * pResampler->config.channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,12 +605,26 @@ mal_uint64 mal_resampler_read(mal_resampler* pResampler, mal_uint64 frameCount,
|
|||||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||||
clientDst.f32[iChannel] = pResampler->cache.f32 + (pResampler->cacheStrideInFrames*iChannel + pResampler->cacheLengthInFrames);
|
clientDst.f32[iChannel] = pResampler->cache.f32 + (pResampler->cacheStrideInFrames*iChannel + pResampler->cacheLengthInFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pResampler->config.layout == mal_stream_layout_deinterleaved) {
|
||||||
framesReadFromClient = pResampler->config.onRead(pResampler, framesToReadFromClient, clientDst.f32);
|
framesReadFromClient = pResampler->config.onRead(pResampler, framesToReadFromClient, clientDst.f32);
|
||||||
|
} else {
|
||||||
|
float pInterleavedFrames[mal_countof(pResampler->cache.f32)];
|
||||||
|
framesReadFromClient = pResampler->config.onRead(pResampler, framesToReadFromClient, (void**)&pInterleavedFrames);
|
||||||
|
mal_deinterleave_pcm_frames(pResampler->config.format, pResampler->config.channels, framesReadFromClient, pInterleavedFrames, (void**)clientDst.f32);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
for (mal_uint32 iChannel = 0; iChannel < pResampler->config.channels; ++iChannel) {
|
||||||
clientDst.s16[iChannel] = pResampler->cache.s16 + (pResampler->cacheStrideInFrames*iChannel + pResampler->cacheLengthInFrames);
|
clientDst.s16[iChannel] = pResampler->cache.s16 + (pResampler->cacheStrideInFrames*iChannel + pResampler->cacheLengthInFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pResampler->config.layout == mal_stream_layout_deinterleaved) {
|
||||||
framesReadFromClient = pResampler->config.onRead(pResampler, framesToReadFromClient, clientDst.s16);
|
framesReadFromClient = pResampler->config.onRead(pResampler, framesToReadFromClient, clientDst.s16);
|
||||||
|
} else {
|
||||||
|
mal_int16 pInterleavedFrames[mal_countof(pResampler->cache.s16)];
|
||||||
|
framesReadFromClient = pResampler->config.onRead(pResampler, framesToReadFromClient, (void**)&pInterleavedFrames);
|
||||||
|
mal_deinterleave_pcm_frames(pResampler->config.format, pResampler->config.channels, framesReadFromClient, pInterleavedFrames, (void**)clientDst.s16);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mal_assert(framesReadFromClient <= framesToReadFromClient);
|
mal_assert(framesReadFromClient <= framesToReadFromClient);
|
||||||
|
|||||||
Reference in New Issue
Block a user