mirror of
https://github.com/ScrelliCopter/VGM-Tools
synced 2025-02-21 04:09:25 +11:00
neotools: adpcm-a partial rewrite
This commit is contained in:
@@ -4,7 +4,7 @@ if (USE_ZLIB AND NOT ZLIB_FOUND)
|
|||||||
message(FATAL_ERROR "USE_ZLIB specified but Zlib was not found")
|
message(FATAL_ERROR "USE_ZLIB specified but Zlib was not found")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(adpcm adpcm.c)
|
add_executable(adpcm adpcm.h adpcm.c)
|
||||||
set_property(TARGET adpcm PROPERTY C_STANDARD 99)
|
set_property(TARGET adpcm PROPERTY C_STANDARD 99)
|
||||||
target_compile_options(adpcm PRIVATE ${WARNINGS})
|
target_compile_options(adpcm PRIVATE ${WARNINGS})
|
||||||
target_link_libraries(adpcm Common::wave $<$<C_COMPILER_ID:Clang,GNU>:m>)
|
target_link_libraries(adpcm Common::wave $<$<C_COMPILER_ID:Clang,GNU>:m>)
|
||||||
|
|||||||
142
neotools/adpcm.c
142
neotools/adpcm.c
@@ -2,11 +2,12 @@
|
|||||||
* original ADPCM to PCM converter v 1.01 By MARTINEZ Fabrice aka SNK of SUPREMACY
|
* original ADPCM to PCM converter v 1.01 By MARTINEZ Fabrice aka SNK of SUPREMACY
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "adpcm.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "wave.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "util.h"
|
|
||||||
#include "wave.h"
|
|
||||||
|
|
||||||
#define BUFFER_SIZE (1024 * 256)
|
#define BUFFER_SIZE (1024 * 256)
|
||||||
#define ADPCMA_VOLUME_RATE 1
|
#define ADPCMA_VOLUME_RATE 1
|
||||||
@@ -14,66 +15,56 @@
|
|||||||
#define ADPCMA_DECODE_MIN (-(ADPCMA_DECODE_RANGE * ADPCMA_VOLUME_RATE))
|
#define ADPCMA_DECODE_MIN (-(ADPCMA_DECODE_RANGE * ADPCMA_VOLUME_RATE))
|
||||||
#define ADPCMA_DECODE_MAX ((ADPCMA_DECODE_RANGE * ADPCMA_VOLUME_RATE) - 1)
|
#define ADPCMA_DECODE_MAX ((ADPCMA_DECODE_RANGE * ADPCMA_VOLUME_RATE) - 1)
|
||||||
|
|
||||||
static int decode_tableA1[16] =
|
|
||||||
|
static const int decodeTableA1[16] =
|
||||||
{
|
{
|
||||||
-1 * 16, -1 * 16, -1 * 16, -1 * 16, 2 * 16, 5 * 16, 7 * 16, 9 * 16,
|
-1 * 16, -1 * 16, -1 * 16, -1 * 16, 2 * 16, 5 * 16, 7 * 16, 9 * 16,
|
||||||
-1 * 16, -1 * 16, -1 * 16, -1 * 16, 2 * 16, 5 * 16, 7 * 16, 9 * 16
|
-1 * 16, -1 * 16, -1 * 16, -1 * 16, 2 * 16, 5 * 16, 7 * 16, 9 * 16
|
||||||
};
|
};
|
||||||
|
|
||||||
static int jedi_table[49 * 16];
|
int main(int argc, char* argv[])
|
||||||
static int cursignal;
|
|
||||||
static int delta;
|
|
||||||
|
|
||||||
void adpcm_init(void);
|
|
||||||
void adpcm_decode(void *, void *, int);
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
{
|
||||||
FILE *InputFile, *OutputFile;
|
fprintf(stderr, "**** ADPCM to PCM converter v 1.01\n\n");
|
||||||
void *InputBuffer, *OutputBuffer;
|
|
||||||
int bytesRead;
|
|
||||||
unsigned int Filelen;
|
|
||||||
|
|
||||||
puts("**** ADPCM to PCM converter v 1.01\n");
|
|
||||||
if (argc != 3)
|
if (argc != 3)
|
||||||
{
|
{
|
||||||
puts("USAGE: adpcm <InputFile.pcm> <OutputFile.wav>");
|
fprintf(stderr, "USAGE: adpcm <InputFile.pcm> <OutputFile.wav>\n");
|
||||||
exit(-1);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputFile = fopen(argv[1], "rb");
|
FILE* inFile = fopen(argv[1], "rb");
|
||||||
if (!InputFile)
|
if (!inFile)
|
||||||
{
|
{
|
||||||
printf("Could not open inputfile %s\n", argv[1]);
|
fprintf(stderr, "Could not open inputfile %s\n", argv[1]);
|
||||||
exit(-2);
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputFile = fopen(argv[2], "wb");
|
FILE* outFile = fopen(argv[2], "wb");
|
||||||
if (!OutputFile)
|
if (!outFile)
|
||||||
{
|
{
|
||||||
printf("Could not open outputfile %s\n", argv[2]);
|
fprintf(stderr, "Could not open outputfile %s\n", argv[2]);
|
||||||
exit(-3);
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputBuffer = malloc(BUFFER_SIZE);
|
char* InputBuffer = malloc(BUFFER_SIZE);
|
||||||
if (InputBuffer == NULL)
|
if (InputBuffer == NULL)
|
||||||
{
|
{
|
||||||
printf("Could not allocate input buffer. (%d bytes)\n", BUFFER_SIZE);
|
fprintf(stderr, "Could not allocate input buffer. (%d bytes)\n", BUFFER_SIZE);
|
||||||
exit(-4);
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputBuffer = malloc(BUFFER_SIZE * 10);
|
short* OutputBuffer = malloc(BUFFER_SIZE * 4);
|
||||||
if (OutputBuffer == NULL)
|
if (OutputBuffer == NULL)
|
||||||
{
|
{
|
||||||
printf("Could not allocate output buffer. (%d bytes)\n", BUFFER_SIZE * 4);
|
fprintf(stderr, "Could not allocate output buffer. (%d bytes)\n", BUFFER_SIZE * 4);
|
||||||
exit(-5);
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
adpcm_init();
|
AdpcmADecoderState decoder;
|
||||||
|
adpcmAInit(&decoder);
|
||||||
|
|
||||||
fseek(InputFile, 0, SEEK_END);
|
fseek(inFile, 0, SEEK_END);
|
||||||
Filelen = ftell(InputFile);
|
unsigned int Filelen = ftell(inFile);
|
||||||
fseek(InputFile, 0, SEEK_SET);
|
fseek(inFile, 0, SEEK_SET);
|
||||||
|
|
||||||
// Write wave header
|
// Write wave header
|
||||||
waveWrite(&(const WaveSpec)
|
waveWrite(&(const WaveSpec)
|
||||||
@@ -83,79 +74,64 @@ int main(int argc, char *argv[])
|
|||||||
.rate = 18500,
|
.rate = 18500,
|
||||||
.bytedepth = 2
|
.bytedepth = 2
|
||||||
},
|
},
|
||||||
NULL, Filelen * 4, &waveStreamDefaultCb, OutputFile);
|
NULL, Filelen * 4, &waveStreamDefaultCb, outFile);
|
||||||
|
|
||||||
// Convert ADPCM to PCM and write to wave
|
// Convert ADPCM to PCM and write to wave
|
||||||
|
int bytesRead;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
bytesRead = fread(InputBuffer, 1, BUFFER_SIZE, InputFile);
|
bytesRead = fread(InputBuffer, 1, BUFFER_SIZE, inFile);
|
||||||
if (bytesRead > 0)
|
if (bytesRead > 0)
|
||||||
{
|
{
|
||||||
adpcm_decode(InputBuffer, OutputBuffer, bytesRead);
|
adpcmADecode(&decoder, InputBuffer, OutputBuffer, bytesRead);
|
||||||
fwrite(OutputBuffer, bytesRead * 4, 1, OutputFile);
|
fwrite(OutputBuffer, bytesRead * 4, 1, outFile);
|
||||||
}
|
}
|
||||||
} while (bytesRead == BUFFER_SIZE);
|
}
|
||||||
|
while (bytesRead == BUFFER_SIZE);
|
||||||
|
|
||||||
free(InputBuffer);
|
|
||||||
free(OutputBuffer);
|
free(OutputBuffer);
|
||||||
fclose(InputFile);
|
free(InputBuffer);
|
||||||
fclose(OutputFile);
|
fclose(outFile);
|
||||||
|
fclose(inFile);
|
||||||
|
|
||||||
puts("Done...");
|
fprintf(stderr, "Done...\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void adpcm_init(void)
|
void adpcmAInit(AdpcmADecoderState* decoder)
|
||||||
{
|
{
|
||||||
int step, nib;
|
for (int step = 0; step <= 48; step++)
|
||||||
|
|
||||||
for (step = 0; step <= 48; step++)
|
|
||||||
{
|
{
|
||||||
int stepval = floor(16.0 * pow (11.0 / 10.0, (double)step) * ADPCMA_VOLUME_RATE);
|
int stepval = floor(16.0 * pow(11.0 / 10.0, step) * ADPCMA_VOLUME_RATE);
|
||||||
// Loop over all nibbles and compute the difference
|
// Loop over all nibbles and compute the difference
|
||||||
for (nib = 0; nib < 16; nib++)
|
for (int nib = 0; nib < 16; nib++)
|
||||||
{
|
{
|
||||||
int value = stepval * ((nib & 0x07) * 2 + 1) / 8;
|
int value = stepval * ((nib & 0x07) * 2 + 1) / 8;
|
||||||
jedi_table[step * 16 + nib] = (nib & 0x08) ? -value : value;
|
decoder->jediTable[step * 16 + nib] = (nib & 0x08) ? -value : value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delta = 0;
|
decoder->delta = 0;
|
||||||
cursignal = 0;
|
decoder->cursignal = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void adpcm_decode(void *InputBuffer, void *OutputBuffer, int Length)
|
void adpcmADecode(AdpcmADecoderState* restrict decoder, char* restrict in, short* restrict out, int len)
|
||||||
{
|
{
|
||||||
char *in;
|
for (int i = 0; i < len * 2; ++i)
|
||||||
short *out;
|
|
||||||
int i, data, oldsignal;
|
|
||||||
|
|
||||||
in = (char *)InputBuffer;
|
|
||||||
out = (short *)OutputBuffer;
|
|
||||||
|
|
||||||
for (i = 0; i < Length; i++)
|
|
||||||
{
|
{
|
||||||
data = ((*in) >> 4) & 0x0F;
|
int data = (!(i & 0x1) ? ((*in) >> 4) : (*in++)) & 0x0F;
|
||||||
oldsignal = cursignal;
|
int oldsignal = decoder->cursignal;
|
||||||
cursignal = CLAMP(cursignal + (jedi_table[data + delta]), ADPCMA_DECODE_MIN, ADPCMA_DECODE_MAX);
|
decoder->cursignal = CLAMP(decoder->cursignal + decoder->jediTable[data + decoder->delta],
|
||||||
delta = CLAMP(delta + decode_tableA1[data], 0 * 16, 48 * 16);
|
ADPCMA_DECODE_MIN, ADPCMA_DECODE_MAX);
|
||||||
if (abs(oldsignal - cursignal) > 2500)
|
decoder->delta = CLAMP(decoder->delta + decodeTableA1[data], 0 * 16, 48 * 16);
|
||||||
|
if (abs(oldsignal - decoder->cursignal) > 2500)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "WARNING: Suspicious signal evolution %06x,%06x pos:%06x delta:%06x\n", oldsignal, cursignal, i, delta);
|
fprintf(stderr, "WARNING: Suspicious signal evolution %06x,%06x pos:%06x delta:%06x\n",
|
||||||
fprintf(stderr, "data:%02x dx:%08x\n", data, jedi_table[data + delta]);
|
oldsignal, decoder->cursignal, i % len, decoder->delta);
|
||||||
|
fprintf(stderr, "data:%02x dx:%08x\n",
|
||||||
|
data, decoder->jediTable[data + decoder->delta]);
|
||||||
}
|
}
|
||||||
*(out++) = (cursignal & 0xffff) * 32;
|
*(out++) = (decoder->cursignal & 0xffff) * 32;
|
||||||
|
|
||||||
data = (*in++) & 0x0F;
|
|
||||||
oldsignal = cursignal;
|
|
||||||
cursignal = CLAMP(cursignal + (jedi_table[data + delta]), ADPCMA_DECODE_MIN, ADPCMA_DECODE_MAX);
|
|
||||||
delta = CLAMP(delta + decode_tableA1[data], 0 * 16, 48 * 16);
|
|
||||||
if (abs(oldsignal - cursignal) > 2500)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "WARNING: Suspicious signal evolution %06x,%06x pos:%06x delta:%06x\n", oldsignal, cursignal, i, delta);
|
|
||||||
fprintf(stderr, "data:%02x dx:%08x\n", data, jedi_table[data + delta]);
|
|
||||||
}
|
|
||||||
*(out++) = (cursignal & 0xffff) * 32;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
neotools/adpcm.h
Normal file
14
neotools/adpcm.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef ADPCM_H
|
||||||
|
#define ADPCM_H
|
||||||
|
|
||||||
|
typedef struct AdpcmADecoderState
|
||||||
|
{
|
||||||
|
int jediTable[49 * 16];
|
||||||
|
int cursignal;
|
||||||
|
int delta;
|
||||||
|
} AdpcmADecoderState;
|
||||||
|
|
||||||
|
void adpcmAInit(AdpcmADecoderState* decoder);
|
||||||
|
void adpcmADecode(AdpcmADecoderState* restrict decoder, char* restrict in, short* restrict out, int len);
|
||||||
|
|
||||||
|
#endif//ADPCM_H
|
||||||
Reference in New Issue
Block a user