1
0
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:
2023-12-10 11:28:52 +11:00
parent ff41b5415e
commit 46c78c24e1
3 changed files with 74 additions and 84 deletions

View File

@@ -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>)

View File

@@ -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
View 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