mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Add some bad experimental work on automatic sample format conversion.
This commit is contained in:
@@ -0,0 +1,51 @@
|
|||||||
|
# The worlds worst programming language!
|
||||||
|
#
|
||||||
|
# The final result needs to be moved to the "r" variable. The input sample is "x".
|
||||||
|
#
|
||||||
|
# Instructions
|
||||||
|
# ============
|
||||||
|
# add [output] [a] [b] -> output = a + b
|
||||||
|
# sub [output] [a] [b] -> output = a - b
|
||||||
|
# mul [output] [a] [b] -> output = a * b
|
||||||
|
# div [output] [a] [b] -> output = a / b
|
||||||
|
# shl [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
|
||||||
|
# mov [output] [a] -> output = a;
|
||||||
|
#
|
||||||
|
# int [name] -> Declare an uninitialized 32-bit integer
|
||||||
|
# flt [name] -> Declare an uninitialized 32-bit float
|
||||||
|
|
||||||
|
# r = (x - 128) << 8
|
||||||
|
u8->s16 {
|
||||||
|
sub r x 128;
|
||||||
|
shl r r 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
# r = (x - 128) << 16
|
||||||
|
u8->s24 {
|
||||||
|
sub r x 128;
|
||||||
|
shl r r 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
# r = (x - 128) << 24
|
||||||
|
u8->s32 {
|
||||||
|
sub r x 128;
|
||||||
|
shl r r 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
# r = (x / 255) * 2 - 1
|
||||||
|
u8->f32 {
|
||||||
|
div r x 255.0;
|
||||||
|
mul r r 2;
|
||||||
|
sub r r 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# r = x / (2147483647 + sign(x))
|
||||||
|
u32->f32 {
|
||||||
|
int s;
|
||||||
|
sig s x;
|
||||||
|
add s s 2147483647;
|
||||||
|
div r x (flt)s;
|
||||||
|
}
|
||||||
@@ -0,0 +1,357 @@
|
|||||||
|
|
||||||
|
#define DR_IMPLEMENTATION
|
||||||
|
#include "../../../../../dr_libs/dr.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
const char* params[4];
|
||||||
|
int paramCount;
|
||||||
|
} malgen_instruction;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char* formatInStr;
|
||||||
|
const char* formatOutStr;
|
||||||
|
std::vector<malgen_instruction> instructions;
|
||||||
|
} malgen_conversion_desc;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char* pFormatsFileData;
|
||||||
|
std::vector<malgen_conversion_desc> conversions;
|
||||||
|
} malgen_context;
|
||||||
|
|
||||||
|
void u8_to_s16(const unsigned char* px, short* pr, unsigned int count)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
for (unsigned int i = 0; i < count; ++i) {
|
||||||
|
int x = px[i];
|
||||||
|
|
||||||
|
r = x - 128;
|
||||||
|
r = x << 8;
|
||||||
|
pr[i] = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void u8_to_s24(const unsigned char* px, unsigned char* pr, unsigned int count)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
for (unsigned int i = 0; i < count; ++i) {
|
||||||
|
int x = px[i];
|
||||||
|
|
||||||
|
r = x - 128;
|
||||||
|
r = x << 16;
|
||||||
|
memcpy(&pr[i*3], &r, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void u8_to_s32(const unsigned char* px, int* pr, unsigned int count)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
for (unsigned int i = 0; i < count; ++i) {
|
||||||
|
int x = px[i];
|
||||||
|
|
||||||
|
r = x - 128;
|
||||||
|
r = x << 24;
|
||||||
|
pr[i] = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void u8_to_f32(const unsigned char* pIn, float* pOut, unsigned int count)
|
||||||
|
{
|
||||||
|
float r;
|
||||||
|
int x;
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
switch ((uintptr_t)pIn & 0x3)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
x = pIn[i];
|
||||||
|
r = x / 255.0f;
|
||||||
|
r = r * 2;
|
||||||
|
r = r - 1;
|
||||||
|
pOut[i++] = r;
|
||||||
|
case 2:
|
||||||
|
x = pIn[i];
|
||||||
|
r = x / 255.0f;
|
||||||
|
r = r * 2;
|
||||||
|
r = r - 1;
|
||||||
|
pOut[i++] = r;
|
||||||
|
case 1:
|
||||||
|
x = pIn[i];
|
||||||
|
r = x / 255.0f;
|
||||||
|
r = r * 2;
|
||||||
|
r = r - 1;
|
||||||
|
pOut[i++] = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i+3 < count) {
|
||||||
|
float r[4];
|
||||||
|
int x[4];
|
||||||
|
|
||||||
|
x[0] = pIn[i+0];
|
||||||
|
x[1] = pIn[i+1];
|
||||||
|
x[2] = pIn[i+2];
|
||||||
|
x[3] = pIn[i+3];
|
||||||
|
|
||||||
|
r[0] = x[0] / 255.0f;
|
||||||
|
r[1] = x[1] / 255.0f;
|
||||||
|
r[2] = x[2] / 255.0f;
|
||||||
|
r[3] = x[3] / 255.0f;
|
||||||
|
|
||||||
|
r[0] = r[0] * 2;
|
||||||
|
r[1] = r[1] * 2;
|
||||||
|
r[2] = r[2] * 2;
|
||||||
|
r[3] = r[3] * 2;
|
||||||
|
|
||||||
|
r[0] = r[0] - 1;
|
||||||
|
r[1] = r[1] - 1;
|
||||||
|
r[2] = r[2] - 1;
|
||||||
|
r[3] = r[3] - 1;
|
||||||
|
|
||||||
|
pOut[i+0] = r[0];
|
||||||
|
pOut[i+1] = r[1];
|
||||||
|
pOut[i+2] = r[2];
|
||||||
|
pOut[i+3] = r[3];
|
||||||
|
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (count - i)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
x = pIn[i];
|
||||||
|
r = x / 255.0f;
|
||||||
|
r = r * 2;
|
||||||
|
r = r - 1;
|
||||||
|
pOut[i++] = r;
|
||||||
|
case 2:
|
||||||
|
x = pIn[i];
|
||||||
|
r = x / 255.0f;
|
||||||
|
r = r * 2;
|
||||||
|
r = r - 1;
|
||||||
|
pOut[i++] = r;
|
||||||
|
case 1:
|
||||||
|
x = pIn[i];
|
||||||
|
r = x / 255.0f;
|
||||||
|
r = r * 2;
|
||||||
|
r = r - 1;
|
||||||
|
pOut[i++] = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int malgen_compile(malgen_context* pContext)
|
||||||
|
{
|
||||||
|
size_t formatsFileData;
|
||||||
|
pContext->pFormatsFileData = dr_open_and_read_text_file("../../../resources/format_conversions.txt", &formatsFileData);
|
||||||
|
if (pContext->pFormatsFileData == NULL) {
|
||||||
|
printf("Failed to open sample format conversion definitions.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first part is going to blank out comments. It just makes the actual parsing soooo much simpler.
|
||||||
|
char* pRunningStr = pContext->pFormatsFileData;
|
||||||
|
for (;;) {
|
||||||
|
if (pRunningStr[0] == '\0') break;
|
||||||
|
if (pRunningStr[0] == '#') {
|
||||||
|
while (pRunningStr[0] != '\n') {
|
||||||
|
if (pRunningStr[0] == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRunningStr[0] = ' ';
|
||||||
|
pRunningStr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pRunningStr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
malgen_conversion_desc currentFunc;
|
||||||
|
malgen_instruction currentInst;
|
||||||
|
memset(¤tInst, 0, sizeof(currentInst));
|
||||||
|
int currentParam = 0;
|
||||||
|
|
||||||
|
// Level 0 = not inside a conversion function.
|
||||||
|
// Level 1 = inside a conversion function.
|
||||||
|
// Level 2 = inside an instruction (parsing parameters).
|
||||||
|
int level = 0;
|
||||||
|
|
||||||
|
pRunningStr = pContext->pFormatsFileData;
|
||||||
|
for (;;) {
|
||||||
|
if (pRunningStr[0] == '\0')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (level == 0) {
|
||||||
|
// Find the first non-whitespace.
|
||||||
|
for (;;) {
|
||||||
|
if (pRunningStr[0] == '\0') return 0;
|
||||||
|
if (!dr_is_whitespace(pRunningStr[0])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRunningStr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the end of the conversion name.
|
||||||
|
char* pConversionNameBeg = pRunningStr;
|
||||||
|
char* pConversionNameEnd = pConversionNameBeg;
|
||||||
|
for (;;) {
|
||||||
|
if (pConversionNameEnd[0] == '\0') return -1;
|
||||||
|
if (dr_is_whitespace(pConversionNameEnd[0])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pConversionNameEnd += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pConversionNameEnd[0] = '\0';
|
||||||
|
pRunningStr = pConversionNameEnd;
|
||||||
|
pRunningStr += 1;
|
||||||
|
|
||||||
|
// Find the opening bracket.
|
||||||
|
for (;;) {
|
||||||
|
if (pRunningStr[0] == '\0') return -1;
|
||||||
|
if (pRunningStr[0] == '{') {
|
||||||
|
currentFunc.formatInStr = pConversionNameBeg;
|
||||||
|
char* formatInStrEnd = strstr((char*const)currentFunc.formatInStr, "->");
|
||||||
|
formatInStrEnd[0] = '\0';
|
||||||
|
currentFunc.formatOutStr = formatInStrEnd += 2;
|
||||||
|
|
||||||
|
level += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRunningStr += 1;
|
||||||
|
}
|
||||||
|
} else if (level == 1) {
|
||||||
|
// Inside a function.
|
||||||
|
|
||||||
|
// Find the first non-whitespace which is where the first instruction should be located.
|
||||||
|
for (;;) {
|
||||||
|
if (pRunningStr[0] == '\0') return -1;
|
||||||
|
if (!dr_is_whitespace(pRunningStr[0])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRunningStr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should be sitting at the name of the next instruction or the closing bracket.
|
||||||
|
if (pRunningStr[0] == '}') {
|
||||||
|
pContext->conversions.push_back(currentFunc);
|
||||||
|
currentFunc.formatInStr = NULL;
|
||||||
|
currentFunc.formatOutStr = NULL;
|
||||||
|
currentFunc.instructions.clear();
|
||||||
|
pRunningStr += 1;
|
||||||
|
level -= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentInst.name = pRunningStr;
|
||||||
|
|
||||||
|
// Get to the end of the name and null terminate it.
|
||||||
|
for (;;) {
|
||||||
|
if (pRunningStr[0] == '\0') return -1;
|
||||||
|
if (dr_is_whitespace(pRunningStr[0])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pRunningStr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRunningStr[0] = '\0';
|
||||||
|
level += 1;
|
||||||
|
} else if (level == 2) {
|
||||||
|
// Inside an instruction.
|
||||||
|
|
||||||
|
// Find the first non-whitespace which is where the next parameter should be located.
|
||||||
|
for (;;) {
|
||||||
|
if (pRunningStr[0] == '\0') return -1;
|
||||||
|
if (!dr_is_whitespace(pRunningStr[0])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pRunningStr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentInst.params[currentParam++] = pRunningStr;
|
||||||
|
currentInst.paramCount += 1;
|
||||||
|
|
||||||
|
// Should be sitting at the next parameter or the semi-colon.
|
||||||
|
if (pRunningStr[0] == ';') {
|
||||||
|
currentFunc.instructions.push_back(currentInst);
|
||||||
|
memset(¤tInst, 0, sizeof(currentInst));
|
||||||
|
currentParam = 0;
|
||||||
|
pRunningStr[0] = '\0';
|
||||||
|
pRunningStr += 1;
|
||||||
|
level -= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get to the end of the name and null terminate it.
|
||||||
|
for (;;) {
|
||||||
|
if (pRunningStr[0] == '\0') return -1;
|
||||||
|
if (dr_is_whitespace(pRunningStr[0])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pRunningStr[0] == ';') {
|
||||||
|
currentFunc.instructions.push_back(currentInst);
|
||||||
|
memset(¤tInst, 0, sizeof(currentInst));
|
||||||
|
currentParam = 0;
|
||||||
|
pRunningStr[0] = '\0';
|
||||||
|
pRunningStr += 1;
|
||||||
|
level -= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRunningStr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRunningStr[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
pRunningStr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
malgen_context context;
|
||||||
|
int result = malgen_compile(&context);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* pOutputFile = dr_fopen("malgen_test0.c", "w");
|
||||||
|
if (pOutputFile == NULL) {
|
||||||
|
printf("Failed to open output file.\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// We need conversion routines for each different combination of formats.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TESTING
|
||||||
|
for (size_t i = 0; i < context.conversions.size(); ++i) {
|
||||||
|
printf("%s to %s\n", context.conversions[i].formatInStr, context.conversions[i].formatOutStr);
|
||||||
|
for (size_t j = 0; j < context.conversions[i].instructions.size(); ++j) {
|
||||||
|
printf(" %s", context.conversions[i].instructions[j].name);
|
||||||
|
for (int k = 0; k < context.conversions[i].instructions[j].paramCount; ++k) {
|
||||||
|
printf(" %s", context.conversions[i].instructions[j].params[k]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user