Commit 95ea6c6b authored by David Reid's avatar David Reid

Add untested conversion routines for all supported formats.

parent a5edf715
...@@ -356,6 +356,10 @@ typedef struct ...@@ -356,6 +356,10 @@ typedef struct
mal_log_proc onLogCallback; mal_log_proc onLogCallback;
} mal_device_config; } mal_device_config;
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4201) // nonstandard extension used: nameless struct/union
#endif
typedef struct typedef struct
{ {
mal_backend backend; // DirectSound, ALSA, etc. mal_backend backend; // DirectSound, ALSA, etc.
...@@ -586,6 +590,9 @@ struct mal_device ...@@ -586,6 +590,9 @@ struct mal_device
} null_device; } null_device;
}; };
}; };
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
// Initializes a context. // Initializes a context.
// //
...@@ -1523,99 +1530,93 @@ static mal_result mal_post_error(mal_device* pDevice, const char* message, mal_r ...@@ -1523,99 +1530,93 @@ static mal_result mal_post_error(mal_device* pDevice, const char* message, mal_r
} }
// Converts sample data from one format to f32. // Conversion functions.
static void mal_samples_to_f32(float* pSamplesOut, const void* pSamplesIn, mal_uint32 sampleCount, mal_format formatIn) void mal_pcm_u8_to_s16(short* pOut, const unsigned char* pIn, unsigned int count);
void mal_pcm_u8_to_s24(void* pOut, const unsigned char* pIn, unsigned int count);
void mal_pcm_u8_to_s32(int* pOut, const unsigned char* pIn, unsigned int count);
void mal_pcm_u8_to_f32(float* pOut, const unsigned char* pIn, unsigned int count);
void mal_pcm_s16_to_u8(unsigned char* pOut, const short* pIn, unsigned int count);
void mal_pcm_s16_to_s24(void* pOut, const short* pIn, unsigned int count);
void mal_pcm_s16_to_s32(int* pOut, const short* pIn, unsigned int count);
void mal_pcm_s16_to_f32(float* pOut, const short* pIn, unsigned int count);
void mal_pcm_s24_to_u8(unsigned char* pOut, const void* pIn, unsigned int count);
void mal_pcm_s24_to_s16(short* pOut, const void* pIn, unsigned int count);
void mal_pcm_s24_to_s32(int* pOut, const void* pIn, unsigned int count);
void mal_pcm_s24_to_f32(float* pOut, const void* pIn, unsigned int count);
void mal_pcm_s32_to_u8(unsigned char* pOut, const int* pIn, unsigned int count);
void mal_pcm_s32_to_s16(short* pOut, const int* pIn, unsigned int count);
void mal_pcm_s32_to_s24(void* pOut, const int* pIn, unsigned int count);
void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count);
void mal_pcm_f32_to_u8(unsigned char* pOut, const float* pIn, unsigned int count);
void mal_pcm_f32_to_s16(short* pOut, const float* pIn, unsigned int count);
void mal_pcm_f32_to_s24(void* pOut, const float* pIn, unsigned int count);
void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count);
static void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_format formatIn, unsigned int count)
{ {
mal_assert(pSamplesOut != NULL); if (formatOut == formatIn) {
mal_assert(pSamplesIn != NULL); memcpy(pOut, pIn, count * mal_get_sample_size_in_bytes(formatOut));
mal_assert(sampleCount > 0); }
// TODO: Optimize me.
switch (formatIn) switch (formatIn)
{ {
case mal_format_f32: case mal_format_u8:
{ {
memcpy(pSamplesOut, pSamplesIn, sampleCount * sizeof(float)); switch (formatOut)
{
case mal_format_s16: mal_pcm_u8_to_s16(pOut, pIn, count); return;
case mal_format_s24: mal_pcm_u8_to_s24(pOut, pIn, count); return;
case mal_format_s32: mal_pcm_u8_to_s32(pOut, pIn, count); return;
case mal_format_f32: mal_pcm_u8_to_f32(pOut, pIn, count); return;
default: break;
}
} break; } break;
case mal_format_s16: case mal_format_s16:
{ {
mal_int16* pSamplesInS16 = (mal_int16*)pSamplesIn; switch (formatOut)
for (mal_uint32 i = 0; i < sampleCount; ++i) { {
mal_uint32 sign = (pSamplesInS16[i] & 0x8000) >> 15; case mal_format_u8: mal_pcm_s16_to_u8( pOut, pIn, count); return;
pSamplesOut[i] = (pSamplesInS16[i] / (float)(0x7FFF + sign)); case mal_format_s24: mal_pcm_s16_to_s24(pOut, pIn, count); return;
case mal_format_s32: mal_pcm_s16_to_s32(pOut, pIn, count); return;
case mal_format_f32: mal_pcm_s16_to_f32(pOut, pIn, count); return;
default: break;
} }
} break; } break;
case mal_format_s32: case mal_format_s24:
{ {
mal_int32* pSamplesInS32 = (mal_int32*)pSamplesIn; switch (formatOut)
for (mal_uint32 i = 0; i < sampleCount; ++i) { {
mal_uint32 sign = (pSamplesInS32[i] & 0x80000000) >> 31; case mal_format_u8: mal_pcm_s24_to_u8( pOut, pIn, count); return;
pSamplesOut[i] = (pSamplesInS32[i] / (float)(0x7FFFFFFF + sign)); case mal_format_s16: mal_pcm_s24_to_s16(pOut, pIn, count); return;
case mal_format_s32: mal_pcm_s24_to_s32(pOut, pIn, count); return;
case mal_format_f32: mal_pcm_s24_to_f32(pOut, pIn, count); return;
default: break;
} }
} break; } break;
default: break; case mal_format_s32:
}
}
// Converts sample data from f32 to another format.
static void mal_samples_from_f32(void* pSamplesOut, const float* pSamplesIn, mal_uint32 sampleCount, mal_format formatOut)
{
mal_assert(pSamplesOut != NULL);
mal_assert(pSamplesIn != NULL);
mal_assert(sampleCount > 0);
// TODO: Optimize me.
switch (formatOut)
{
case mal_format_f32:
{
memcpy(pSamplesOut, pSamplesIn, sampleCount * sizeof(float));
} break;
case mal_format_s16:
{ {
mal_int16* pSamplesOutS16 = (mal_int16*)pSamplesOut; switch (formatOut)
{
// This unroll is just me trying something... I realize it's a bit out of place. case mal_format_u8: mal_pcm_s32_to_u8( pOut, pIn, count); return;
mal_uint32 i = 0; case mal_format_s16: mal_pcm_s32_to_s16(pOut, pIn, count); return;
for (; i+3 < sampleCount; i += 4) { case mal_format_s24: mal_pcm_s32_to_s24(pOut, pIn, count); return;
float samplesIn[4]; case mal_format_f32: mal_pcm_s32_to_f32(pOut, pIn, count); return;
samplesIn[0] = mal_clip_f32(pSamplesIn[i+0]); default: break;
samplesIn[1] = mal_clip_f32(pSamplesIn[i+1]);
samplesIn[2] = mal_clip_f32(pSamplesIn[i+2]);
samplesIn[3] = mal_clip_f32(pSamplesIn[i+3]);
mal_uint32 signs[4];
signs[0] = ((*((mal_uint32*)&pSamplesIn[i+0])) & 0x80000000) >> 31;
signs[1] = ((*((mal_uint32*)&pSamplesIn[i+1])) & 0x80000000) >> 31;
signs[2] = ((*((mal_uint32*)&pSamplesIn[i+2])) & 0x80000000) >> 31;
signs[3] = ((*((mal_uint32*)&pSamplesIn[i+3])) & 0x80000000) >> 31;
pSamplesOutS16[i+0] = (mal_int16)(samplesIn[0] * (32767 + signs[0]));
pSamplesOutS16[i+1] = (mal_int16)(samplesIn[1] * (32767 + signs[1]));
pSamplesOutS16[i+2] = (mal_int16)(samplesIn[2] * (32767 + signs[2]));
pSamplesOutS16[i+3] = (mal_int16)(samplesIn[3] * (32767 + signs[3]));
}
for (i ; i < sampleCount; i += 1) {
float sampleIn = mal_clip_f32(pSamplesIn[i]);
mal_uint32 sign = ((*((mal_uint32*)&pSamplesIn[i])) & 0x80000000) >> 31;
pSamplesOutS16[i] = (mal_int16)(sampleIn * (0x7FFF + sign));
} }
} break; } break;
case mal_format_s32: case mal_format_f32:
{ {
mal_int32* pSamplesOutS32 = (mal_int32*)pSamplesOut; switch (formatOut)
for (mal_uint32 i = 0; i < sampleCount; ++i) { {
float sampleIn = mal_clip_f32(pSamplesIn[i]); case mal_format_u8: mal_pcm_f32_to_u8( pOut, pIn, count); return;
case mal_format_s16: mal_pcm_f32_to_s16(pOut, pIn, count); return;
mal_uint32 sign = ((*((mal_uint32*)&pSamplesIn[i])) & 0x80000000) >> 31; case mal_format_s24: mal_pcm_f32_to_s24(pOut, pIn, count); return;
pSamplesOutS32[i] = (mal_int32)(sampleIn * (0x7FFFFFFF + sign)); case mal_format_s32: mal_pcm_f32_to_s32(pOut, pIn, count); return;
default: break;
} }
} break; } break;
...@@ -1636,16 +1637,6 @@ static inline mal_uint32 mal_device__read_frames_from_client(mal_device* pDevice ...@@ -1636,16 +1637,6 @@ static inline mal_uint32 mal_device__read_frames_from_client(mal_device* pDevice
return 0; return 0;
} }
if (pDevice->flags & MAL_DEVICE_FLAG_USING_FOREIGN_FORMAT) {
if (pDevice->format == mal_format_u8 ||
pDevice->format == mal_format_s16 ||
pDevice->format == mal_format_s24 ||
pDevice->format == mal_format_s32) {
return 0;
}
}
mal_uint32 framesRead = 0; mal_uint32 framesRead = 0;
mal_send_proc onSend = pDevice->onSend; mal_send_proc onSend = pDevice->onSend;
if (onSend) { if (onSend) {
...@@ -1668,11 +1659,7 @@ static inline mal_uint32 mal_device__read_frames_from_client(mal_device* pDevice ...@@ -1668,11 +1659,7 @@ static inline mal_uint32 mal_device__read_frames_from_client(mal_device* pDevice
mal_uint32 samplesJustRead = framesJustRead * pDevice->channels; mal_uint32 samplesJustRead = framesJustRead * pDevice->channels;
if (pDevice->flags & MAL_DEVICE_FLAG_USING_FOREIGN_FORMAT) { if (pDevice->flags & MAL_DEVICE_FLAG_USING_FOREIGN_FORMAT) {
if (pDevice->format == mal_format_f32) { mal_pcm_convert((mal_uint8*)pSamples + (framesRead * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)), pDevice->internalFormat, scratchBuffer, pDevice->format, samplesJustRead);
mal_samples_from_f32((mal_uint8*)pSamples + (framesRead * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)), (float*)scratchBuffer, samplesJustRead, pDevice->internalFormat);
} else {
// TODO: Implement the rest.
}
} }
framesRemaining -= framesJustRead; framesRemaining -= framesJustRead;
...@@ -1702,15 +1689,6 @@ static inline void mal_device__send_frames_to_client(mal_device* pDevice, mal_ui ...@@ -1702,15 +1689,6 @@ static inline void mal_device__send_frames_to_client(mal_device* pDevice, mal_ui
return; return;
} }
if (pDevice->flags & MAL_DEVICE_FLAG_USING_FOREIGN_FORMAT) {
if (pDevice->format == mal_format_u8 ||
pDevice->format == mal_format_s16 ||
pDevice->format == mal_format_s24 ||
pDevice->format == mal_format_s32) {
return;
}
}
mal_recv_proc onRecv = pDevice->onRecv; mal_recv_proc onRecv = pDevice->onRecv;
if (onRecv) { if (onRecv) {
if ((pDevice->flags & (MAL_DEVICE_FLAG_USING_FOREIGN_FORMAT | MAL_DEVICE_FLAG_USING_FOREIGN_CHANNELS | MAL_DEVICE_FLAG_USING_FOREIGN_SAMPLE_RATE)) == 0) { if ((pDevice->flags & (MAL_DEVICE_FLAG_USING_FOREIGN_FORMAT | MAL_DEVICE_FLAG_USING_FOREIGN_CHANNELS | MAL_DEVICE_FLAG_USING_FOREIGN_SAMPLE_RATE)) == 0) {
...@@ -1729,11 +1707,7 @@ static inline void mal_device__send_frames_to_client(mal_device* pDevice, mal_ui ...@@ -1729,11 +1707,7 @@ static inline void mal_device__send_frames_to_client(mal_device* pDevice, mal_ui
mal_uint32 samplesToSend = framesToSend * pDevice->channels; mal_uint32 samplesToSend = framesToSend * pDevice->channels;
if (pDevice->flags & MAL_DEVICE_FLAG_USING_FOREIGN_FORMAT) { if (pDevice->flags & MAL_DEVICE_FLAG_USING_FOREIGN_FORMAT) {
if (pDevice->format == mal_format_f32) { mal_pcm_convert(scratchBuffer, pDevice->format, (mal_uint8*)pSamples + (framesSent * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)), pDevice->internalFormat, samplesToSend);
mal_samples_to_f32((float*)scratchBuffer, (mal_uint8*)pSamples + (framesSent * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)), samplesToSend, pDevice->internalFormat);
} else {
// TODO: Implement the rest.
}
} }
onRecv(pDevice, framesToSend, scratchBuffer); onRecv(pDevice, framesToSend, scratchBuffer);
...@@ -4567,7 +4541,6 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type ...@@ -4567,7 +4541,6 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type
mal_ALCuint frequencyAL = pConfig->sampleRate; mal_ALCuint frequencyAL = pConfig->sampleRate;
mal_uint32 channelsAL = 0; mal_uint32 channelsAL = 0;
mal_format internalFormat = pConfig->format;
// OpenAL supports only mono and stereo. // OpenAL supports only mono and stereo.
mal_ALCenum formatAL = 0; mal_ALCenum formatAL = 0;
...@@ -4581,9 +4554,9 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type ...@@ -4581,9 +4554,9 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type
formatAL = MAL_AL_FORMAT_MONO16; formatAL = MAL_AL_FORMAT_MONO16;
} }
} else if (pConfig->format == mal_format_s32) { } else if (pConfig->format == mal_format_s32) {
return MAL_FORMAT_NOT_SUPPORTED; formatAL = MAL_AL_FORMAT_MONO16;
} else if (pConfig->format == mal_format_s24) { } else if (pConfig->format == mal_format_s24) {
return MAL_FORMAT_NOT_SUPPORTED; formatAL = MAL_AL_FORMAT_MONO16;
} else if (pConfig->format == mal_format_s16) { } else if (pConfig->format == mal_format_s16) {
formatAL = MAL_AL_FORMAT_MONO16; formatAL = MAL_AL_FORMAT_MONO16;
} else if (pConfig->format == mal_format_u8) { } else if (pConfig->format == mal_format_u8) {
...@@ -4599,9 +4572,9 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type ...@@ -4599,9 +4572,9 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type
formatAL = MAL_AL_FORMAT_STEREO16; formatAL = MAL_AL_FORMAT_STEREO16;
} }
} else if (pConfig->format == mal_format_s32) { } else if (pConfig->format == mal_format_s32) {
return MAL_FORMAT_NOT_SUPPORTED; formatAL = MAL_AL_FORMAT_STEREO16;
} else if (pConfig->format == mal_format_s24) { } else if (pConfig->format == mal_format_s24) {
return MAL_FORMAT_NOT_SUPPORTED; formatAL = MAL_AL_FORMAT_STEREO16;
} else if (pConfig->format == mal_format_s16) { } else if (pConfig->format == mal_format_s16) {
formatAL = MAL_AL_FORMAT_STEREO16; formatAL = MAL_AL_FORMAT_STEREO16;
} else if (pConfig->format == mal_format_u8) { } else if (pConfig->format == mal_format_u8) {
...@@ -4660,6 +4633,9 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type ...@@ -4660,6 +4633,9 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type
if (formatAL == MAL_AL_FORMAT_MONO16 || formatAL == MAL_AL_FORMAT_STEREO16) { if (formatAL == MAL_AL_FORMAT_MONO16 || formatAL == MAL_AL_FORMAT_STEREO16) {
pDevice->internalFormat = mal_format_s16; pDevice->internalFormat = mal_format_s16;
} }
if (formatAL == MAL_AL_FORMAT_MONO_FLOAT32 || formatAL == MAL_AL_FORMAT_STEREO_FLOAT32) {
pDevice->internalFormat = mal_format_f32;
}
pDevice->openal.pDeviceALC = pDeviceALC; pDevice->openal.pDeviceALC = pDeviceALC;
pDevice->openal.pContextALC = pContextALC; pDevice->openal.pContextALC = pContextALC;
...@@ -5123,7 +5099,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal ...@@ -5123,7 +5099,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal
#ifdef MAL_ENABLE_WASAPI #ifdef MAL_ENABLE_WASAPI
case mal_backend_wasapi: case mal_backend_wasapi:
{ {
mal_result result = mal_context_init__wasapi(pContext); result = mal_context_init__wasapi(pContext);
if (result == MAL_SUCCESS) { if (result == MAL_SUCCESS) {
pContext->backend = mal_backend_wasapi; pContext->backend = mal_backend_wasapi;
return result; return result;
...@@ -5133,7 +5109,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal ...@@ -5133,7 +5109,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal
#ifdef MAL_ENABLE_DSOUND #ifdef MAL_ENABLE_DSOUND
case mal_backend_dsound: case mal_backend_dsound:
{ {
mal_result result = mal_context_init__dsound(pContext); result = mal_context_init__dsound(pContext);
if (result == MAL_SUCCESS) { if (result == MAL_SUCCESS) {
pContext->backend = mal_backend_dsound; pContext->backend = mal_backend_dsound;
return result; return result;
...@@ -5143,7 +5119,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal ...@@ -5143,7 +5119,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal
#ifdef MAL_ENABLE_ALSA #ifdef MAL_ENABLE_ALSA
case mal_backend_alsa: case mal_backend_alsa:
{ {
mal_result result = mal_context_init__alsa(pContext); result = mal_context_init__alsa(pContext);
if (result == MAL_SUCCESS) { if (result == MAL_SUCCESS) {
pContext->backend = mal_backend_alsa; pContext->backend = mal_backend_alsa;
return result; return result;
...@@ -5153,7 +5129,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal ...@@ -5153,7 +5129,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal
#ifdef MAL_ENABLE_OPENSLES #ifdef MAL_ENABLE_OPENSLES
case mal_backend_opensl: case mal_backend_opensl:
{ {
mal_result result = mal_context_init__opensl(pContext); result = mal_context_init__opensl(pContext);
if (result == MAL_SUCCESS) { if (result == MAL_SUCCESS) {
pContext->backend = mal_backend_opensl; pContext->backend = mal_backend_opensl;
return result; return result;
...@@ -5163,7 +5139,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal ...@@ -5163,7 +5139,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal
#ifdef MAL_ENABLE_OPENAL #ifdef MAL_ENABLE_OPENAL
case mal_backend_openal: case mal_backend_openal:
{ {
mal_result result = mal_context_init__openal(pContext); result = mal_context_init__openal(pContext);
if (result == MAL_SUCCESS) { if (result == MAL_SUCCESS) {
pContext->backend = mal_backend_openal; pContext->backend = mal_backend_openal;
return result; return result;
...@@ -5173,7 +5149,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal ...@@ -5173,7 +5149,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, mal
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
case mal_backend_null: case mal_backend_null:
{ {
mal_result result = mal_context_init__null(pContext); result = mal_context_init__null(pContext);
if (result == MAL_SUCCESS) { if (result == MAL_SUCCESS) {
pContext->backend = mal_backend_null; pContext->backend = mal_backend_null;
return result; return result;
...@@ -5640,6 +5616,258 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format) ...@@ -5640,6 +5616,258 @@ mal_uint32 mal_get_sample_size_in_bytes(mal_format format)
}; };
return sizes[format]; return sizes[format];
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// FORMAT CONVERSION
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if 0
#include "tools/malgen/bin/malgen_test0.c"
#else
void mal_pcm_u8_to_s16(short* pOut, const unsigned char* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x - 128;
r = r << 8;
pOut[i] = (short)r;
}
}
void mal_pcm_u8_to_s24(void* pOut, const unsigned char* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x - 128;
r = r << 16;
((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16);
}
}
void mal_pcm_u8_to_s32(int* pOut, const unsigned char* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x - 128;
r = r << 24;
pOut[i] = (int)r;
}
}
void mal_pcm_u8_to_f32(float* pOut, const unsigned char* pIn, unsigned int count)
{
float r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x / 255.0f;
r = r * 2;
r = r - 1;
pOut[i] = (float)r;
}
}
void mal_pcm_s16_to_u8(unsigned char* pOut, const short* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x >> 8;
r = r + 128;
pOut[i] = (unsigned char)r;
}
}
void mal_pcm_s16_to_s24(void* pOut, const short* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x << 8;
((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16);
}
}
void mal_pcm_s16_to_s32(int* pOut, const short* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x << 16;
pOut[i] = (int)r;
}
}
void mal_pcm_s16_to_f32(float* pOut, const short* pIn, unsigned int count)
{
float r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x + 32768.0f;
r = r / 65536.0f;
r = r * 2;
r = r - 1;
pOut[i] = (float)r;
}
}
void mal_pcm_s24_to_u8(unsigned char* pOut, const void* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8;
r = x >> 16;
r = r + 128;
pOut[i] = (unsigned char)r;
}
}
void mal_pcm_s24_to_s16(short* pOut, const void* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8;
r = x >> 8;
pOut[i] = (short)r;
}
}
void mal_pcm_s24_to_s32(int* pOut, const void* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8;
r = x << 8;
pOut[i] = (int)r;
}
}
void mal_pcm_s24_to_f32(float* pOut, const void* pIn, unsigned int count)
{
float r;
for (unsigned int i = 0; i < count; ++i) {
int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8;
r = x + 8388608.0f;
r = r / 16777215.0f;
r = r * 2;
r = r - 1;
pOut[i] = (float)r;
}
}
void mal_pcm_s32_to_u8(unsigned char* pOut, const int* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x >> 24;
r = r + 128;
pOut[i] = (unsigned char)r;
}
}
void mal_pcm_s32_to_s16(short* pOut, const int* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x >> 16;
pOut[i] = (short)r;
}
}
void mal_pcm_s32_to_s24(void* pOut, const int* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
r = x >> 8;
((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16);
}
}
void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count)
{
float r;
for (unsigned int i = 0; i < count; ++i) {
int x = pIn[i];
int s;
s = ((*((int*)&x)) & 0x80000000) >> 31;
s = s + 2147483647;
r = x / (float)(unsigned int)s;
pOut[i] = (float)r;
}
}
void mal_pcm_f32_to_u8(unsigned char* pOut, const float* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
float x = pIn[i];
float c;
int s;
c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
s = ((*((int*)&x)) & 0x80000000) >> 31;
s = s + 127;
r = (int)(c * s);
r = r + 128;
pOut[i] = (unsigned char)r;
}
}
void mal_pcm_f32_to_s16(short* pOut, const float* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
float x = pIn[i];
float c;
int s;
c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
s = ((*((int*)&x)) & 0x80000000) >> 31;
s = s + 32767;
r = (int)(c * s);
pOut[i] = (short)r;
}
}
void mal_pcm_f32_to_s24(void* pOut, const float* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
float x = pIn[i];
float c;
int s;
c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
s = ((*((int*)&x)) & 0x80000000) >> 31;
s = s + 8388607;
r = (int)(c * s);
((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16);
}
}
void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count)
{
int r;
for (unsigned int i = 0; i < count; ++i) {
float x = pIn[i];
float c;
int s;
c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
s = ((*((int*)&x)) & 0x80000000) >> 31;
s = s + 2147483647;
r = (int)(c * s);
pOut[i] = (int)r;
}
}
#endif
#endif #endif
......
...@@ -4,14 +4,15 @@ ...@@ -4,14 +4,15 @@
# #
# Instructions # Instructions
# ============ # ============
# add [output] [a] [b] -> output = a + b # add [output] [a] [b] -> output = a + b
# sub [output] [a] [b] -> output = a - b # sub [output] [a] [b] -> output = a - b
# mul [output] [a] [b] -> output = a * b # mul [output] [a] [b] -> output = a * b
# div [output] [a] [b] -> output = a / b # div [output] [a] [b] -> output = a / b
# shl [output] [a] [b] -> output = a << b # shl [output] [a] [b] -> output = a << b
# shr [output] [a] [b] -> output = a >> b # shr [output] [a] [b] -> output = a >> b
# sig [output] [b] -> output = (sign bit in "a" is set) ? 1 : 0 # sig [output] [b] -> output = (sign bit in "a" is set) ? 1 : 0
# mov [output] [a] -> output = a; # mov [output] [a] -> output = a;
# clip [output] [a] -> output = clamp(a, -1, 1)
# #
# int [name] -> Declare an uninitialized 32-bit integer # int [name] -> Declare an uninitialized 32-bit integer
# flt [name] -> Declare an uninitialized 32-bit float # flt [name] -> Declare an uninitialized 32-bit float
...@@ -36,16 +37,128 @@ u8->s32 { ...@@ -36,16 +37,128 @@ u8->s32 {
# r = (x / 255) * 2 - 1 # r = (x / 255) * 2 - 1
u8->f32 { u8->f32 {
div r x 255.0; div r x 255.0f;
mul r r 2; mul r r 2;
sub r r 1; sub r r 1;
} }
# r = (x >> 8) + 128
s16->u8 {
shr r x 8;
add r r 128;
}
# r = x << 8
s16->s24 {
shl r x 8;
}
# r = x << 16
s16->s32 {
shl r x 16;
}
# r = ((x + 32768) / 65536) * 2 - 1
s16->f32 {
add r x 32768.0f;
div r r 65536.0f;
mul r r 2;
sub r r 1;
}
# r = (x >> 16) + 128
s24->u8 {
shr r x 16;
add r r 128;
}
# r = x >> 8
s24->s16 {
shr r x 8;
}
# r = x << 8
s24->s32 {
shl r x 8;
}
# r = ((x + 8388608) / 16777215) * 2 - 1
s24->f32 {
add r x 8388608.0f;
div r r 16777215.0f;
mul r r 2;
sub r r 1;
}
# r = (x >> 24) + 128
s32->u8 {
shr r x 24;
add r r 128;
}
# r = x >> 16
s32->s16 {
shr r x 16;
}
# r = x >> 8
s32->s24 {
shr r x 8;
}
# r = x / (2147483647 + sign(x)) # r = x / (2147483647 + sign(x))
u32->f32 { s32->f32 {
int s; int s;
sig s x; sig s x;
add s s 2147483647; add s s 2147483647;
div r x (flt)s; div r x (flt)(uint)s;
} }
\ No newline at end of file
# r = (clip(x) * (0x7F + sign(x))) + 128
f32->u8 {
flt c;
int s;
clip c x;
sig s x;
add s s 127;
mul (int)r c s;
add r r 128;
}
# r = clip(x) * (0x7FFF + sign(x))
f32->s16 {
flt c;
int s;
clip c x;
sig s x;
add s s 32767;
mul (int)r c s;
}
# r = clip(x) * (0x7FFFFF + sign(x))
f32->s24 {
flt c;
int s;
clip c x;
sig s x;
add s s 8388607;
mul (int)r c s;
}
# r = clip(x) * (0x7FFFFFFF + sign(x))
f32->s32 {
flt c;
int s;
clip c x;
sig s x;
add s s 2147483647;
mul (int)r c s;
}
...@@ -21,6 +21,7 @@ typedef struct ...@@ -21,6 +21,7 @@ typedef struct
typedef struct typedef struct
{ {
char* pFormatsFileData; char* pFormatsFileData;
const char* userNamespace;
std::vector<malgen_conversion_desc> conversions; std::vector<malgen_conversion_desc> conversions;
} malgen_context; } malgen_context;
...@@ -66,7 +67,7 @@ void u8_to_f32(const unsigned char* pIn, float* pOut, unsigned int count) ...@@ -66,7 +67,7 @@ void u8_to_f32(const unsigned char* pIn, float* pOut, unsigned int count)
int x; int x;
unsigned int i = 0; unsigned int i = 0;
switch ((uintptr_t)pIn & 0x3) switch (((unsigned long long)pIn & 0x15) / sizeof(float))
{ {
case 3: case 3:
x = pIn[i]; x = pIn[i];
...@@ -319,6 +320,242 @@ int malgen_compile(malgen_context* pContext) ...@@ -319,6 +320,242 @@ int malgen_compile(malgen_context* pContext)
return 0; return 0;
} }
std::string malgen_get_format_c_type_string(const char* formatStr)
{
if (strcmp(formatStr, "u8") == 0) {
return "unsigned char";
}
if (strcmp(formatStr, "s16") == 0) {
return "short";
}
if (strcmp(formatStr, "s24") == 0) {
return "void";
}
if (strcmp(formatStr, "s32") == 0) {
return "int";
}
if (strcmp(formatStr, "f32") == 0) {
return "float";
}
return "";
}
std::string malgen_get_format_impl_c_type_string(const char* formatStr)
{
if (strcmp(formatStr, "f32") == 0) {
return "float";
}
return "int";
}
std::string malgen_generate_code__conversion_func_params(malgen_context* pContext, malgen_conversion_desc* pFuncDesc)
{
std::string code;
code += malgen_get_format_c_type_string(pFuncDesc->formatOutStr); code += "* pOut, ";
code += "const "; code += malgen_get_format_c_type_string(pFuncDesc->formatInStr); code += "* pIn, ";
code += "unsigned int count";
return code;
}
std::string malgen_get_format_input_conversion_code(const char* formatStr)
{
if (strcmp(formatStr, "s24") == 0) {
return "((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8";
}
return "pIn[i]";
}
std::string malgen_get_format_output_conversion_code(const char* formatStr)
{
if (strcmp(formatStr, "s24") == 0) {
return "((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16)";
}
std::string code;
code = "pOut[i] = ("; code += malgen_get_format_c_type_string(formatStr); code += ")r";
return code;
}
std::string malgen_format_op_param(const char* param)
{
std::string s(param);
// (flt) -> (float)
{
const char* src = "(flt)"; const char* dst = "(float)";
size_t loc = s.find(src);
if (loc != std::string::npos) {
s = s.replace(loc, strlen(src), dst);
}
}
// (dbl) -> (double)
{
const char* src = "(dbl)"; const char* dst = "(double)";
size_t loc = s.find(src);
if (loc != std::string::npos) {
s = s.replace(loc, strlen(src), dst);
}
}
// (uint) -> (unsigned int)
{
const char* src = "(uint)"; const char* dst = "(unsigned int)";
size_t loc = s.find(src);
if (loc != std::string::npos) {
s = s.replace(loc, strlen(src), dst);
}
}
return s;
}
std::string malgen_generate_code__conversion_func_inst_binary_op(const char* result, const char* param1, const char* param2, const char* op)
{
bool requiresCast = false;
const char* resultVar = result;
if (resultVar[0] == '(') {
for (;;) {
if (resultVar[0] == '\0' || resultVar[0] == ')') {
resultVar += 1;
break;
}
resultVar += 1;
}
requiresCast = true;
}
std::string assignmentStr = malgen_format_op_param(param1) + " " + op + " " + malgen_format_op_param(param2);
std::string code;
code += resultVar; code += " = ";
if (requiresCast) {
char typeStr[64];
strncpy_s(typeStr, result, resultVar - result);
code += typeStr; code += "("; code += assignmentStr; code += ")";
return code;
} else {
code += assignmentStr;
return code;
}
}
std::string malgen_generate_code__conversion_func_inst(malgen_context* pContext, malgen_instruction* pInst)
{
std::string code;
if (strcmp(pInst->name, "int") == 0) {
code += "int "; code += pInst->params[0];
}
if (strcmp(pInst->name, "flt") == 0) {
code += "float "; code += pInst->params[0];
}
if (strcmp(pInst->name, "add") == 0) {
code += malgen_generate_code__conversion_func_inst_binary_op(pInst->params[0], pInst->params[1], pInst->params[2], "+");
}
if (strcmp(pInst->name, "sub") == 0) {
code += malgen_generate_code__conversion_func_inst_binary_op(pInst->params[0], pInst->params[1], pInst->params[2], "-");
}
if (strcmp(pInst->name, "mul") == 0) {
code += malgen_generate_code__conversion_func_inst_binary_op(pInst->params[0], pInst->params[1], pInst->params[2], "*");
}
if (strcmp(pInst->name, "div") == 0) {
code += malgen_generate_code__conversion_func_inst_binary_op(pInst->params[0], pInst->params[1], pInst->params[2], "/");
}
if (strcmp(pInst->name, "shl") == 0) {
code += malgen_generate_code__conversion_func_inst_binary_op(pInst->params[0], pInst->params[1], pInst->params[2], "<<");
}
if (strcmp(pInst->name, "shr") == 0) {
code += malgen_generate_code__conversion_func_inst_binary_op(pInst->params[0], pInst->params[1], pInst->params[2], ">>");
}
if (strcmp(pInst->name, "mov") == 0) {
code += pInst->params[0]; code += " = "; code += pInst->params[1];
}
if (strcmp(pInst->name, "sig") == 0) { // <-- This gets the sign of the first input parameter and moves it to the result.
code += pInst->params[0]; code += " = "; code += "((*((int*)&"; code += pInst->params[1]; code += ")) & 0x80000000) >> 31";
}
if (strcmp(pInst->name, "clip") == 0) { // clamp(a, -1, 1) -> r = ((a < -1) ? -1 : ((a > 1) ? 1 : a))
code += pInst->params[0]; code += " = "; code += "(("; code += pInst->params[1]; code += " < -1) ? -1 : (("; code += pInst->params[1]; code += " > 1) ? 1 : "; code += pInst->params[1]; code += "))";
}
return code;
}
std::string malgen_generate_code__conversion_func_decl(malgen_context* pContext, malgen_conversion_desc* pFuncDesc)
{
std::string code = "void ";
code += pContext->userNamespace;
code += pFuncDesc->formatInStr;
code += "_to_";
code += pFuncDesc->formatOutStr;
code += "(";
code += malgen_generate_code__conversion_func_params(pContext, pFuncDesc);
code += ")";
return code;
}
std::string malgen_generate_code__conversion_func_impl(malgen_context* pContext, malgen_conversion_desc* pFuncDesc)
{
std::string code;
code += " "; code += malgen_get_format_impl_c_type_string(pFuncDesc->formatOutStr); code += " r;\n";
code += " for (unsigned int i = 0; i < count; ++i) {\n";
code += " "; code += malgen_get_format_impl_c_type_string(pFuncDesc->formatInStr); code += " x = "; code += malgen_get_format_input_conversion_code(pFuncDesc->formatInStr); code += ";\n";
for (size_t i = 0; i < pFuncDesc->instructions.size(); ++i) {
code += " "; code += malgen_generate_code__conversion_func_inst(pContext, &pFuncDesc->instructions[i]); code += ";\n";
}
code += " "; code += malgen_get_format_output_conversion_code(pFuncDesc->formatOutStr); code += ";\n";
code += " }";
return code;
}
std::string malgen_generate_code__conversion_func(malgen_context* pContext, malgen_conversion_desc* pFuncDesc)
{
std::string code = malgen_generate_code__conversion_func_decl(pContext, pFuncDesc);
code += "\n{\n";
code += malgen_generate_code__conversion_func_impl(pContext, pFuncDesc);
code += "\n}\n";
return code;
}
int malgen_generate_code(malgen_context* pContext, std::string* pCodeOut)
{
std::string code;
// Conversion functions.
// Declarations.
for (size_t i = 0; i < pContext->conversions.size(); ++i) {
code += malgen_generate_code__conversion_func_decl(pContext, &pContext->conversions[i]);
code += ";\n";
}
code += "\n";
// Definitions.
for (size_t i = 0; i < pContext->conversions.size(); ++i) {
code += malgen_generate_code__conversion_func(pContext, &pContext->conversions[i]);
code += "\n";
}
*pCodeOut = code;
return 0;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
(void)argc; (void)argc;
...@@ -330,16 +567,27 @@ int main(int argc, char** argv) ...@@ -330,16 +567,27 @@ int main(int argc, char** argv)
return result; return result;
} }
context.userNamespace = "mal_pcm_"; // TODO: Implement the "--namespace" command line argument.
FILE* pOutputFile = dr_fopen("malgen_test0.c", "w"); FILE* pOutputFile = dr_fopen("malgen_test0.c", "w");
if (pOutputFile == NULL) { if (pOutputFile == NULL) {
printf("Failed to open output file.\n"); printf("Failed to open output file.\n");
return -2; return -2;
} }
std::string code;
result = malgen_generate_code(&context, &code);
if (result != 0) {
printf("Code generation failed.\n");
return result;
}
// We need conversion routines for each different combination of formats. fprintf(pOutputFile, "%s", code.c_str());
// We need conversion routines for each different combination of formats.
// TESTING // TESTING
for (size_t i = 0; i < context.conversions.size(); ++i) { for (size_t i = 0; i < context.conversions.size(); ++i) {
......
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