mirror of
https://github.com/ScrelliCopter/VGM-Tools
synced 2025-02-21 04:09:25 +11:00
neotools: neoadpcmextract now converts ADPCM-B to Wave
This commit is contained in:
@@ -9,11 +9,15 @@ 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>)
|
||||||
|
|
||||||
add_executable(adpcmb adpcmb.h adpcmb.c)
|
add_executable(adpcmb adpcmb.h libadpcmb.c adpcmb.c)
|
||||||
|
set_property(TARGET adpcmb PROPERTY C_STANDARD 99)
|
||||||
target_compile_options(adpcmb PRIVATE ${WARNINGS})
|
target_compile_options(adpcmb PRIVATE ${WARNINGS})
|
||||||
target_link_libraries(adpcmb Common::wave)
|
target_link_libraries(adpcmb Common::wave)
|
||||||
|
|
||||||
add_executable(neoadpcmextract adpcm.h libadpcma.c neoadpcmextract.c)
|
add_executable(neoadpcmextract
|
||||||
|
libadpcma.c adpcm.h
|
||||||
|
libadpcmb.c adpcmb.h
|
||||||
|
neoadpcmextract.c)
|
||||||
set_property(TARGET neoadpcmextract PROPERTY C_STANDARD 99)
|
set_property(TARGET neoadpcmextract PROPERTY C_STANDARD 99)
|
||||||
target_compile_definitions(neoadpcmextract PRIVATE $<$<BOOL:${USE_ZLIB}>:USE_ZLIB=1>)
|
target_compile_definitions(neoadpcmextract PRIVATE $<$<BOOL:${USE_ZLIB}>:USE_ZLIB=1>)
|
||||||
target_compile_options(neoadpcmextract PRIVATE ${WARNINGS})
|
target_compile_options(neoadpcmextract PRIVATE ${WARNINGS})
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*; YM2610 ADPCM-B Codec
|
/* adpcmb.c - CLI for encoding & decoding YM2610 ADPCM-B files
|
||||||
;
|
|
||||||
;
|
|
||||||
; Fred/FRONT
|
; Fred/FRONT
|
||||||
;
|
;
|
||||||
;Usage 1: ADPCM_Encode.exe -d [-r:reg,clock] Input.bin Output.wav
|
;Usage 1: ADPCM_Encode -d [-r:reg,clock] Input.bin Output.wav
|
||||||
;Usage 2: ADPCM_Encode.exe -e Input.wav Output.bin
|
;Usage 2: ADPCM_Encode -e Input.wav Output.bin
|
||||||
;
|
;
|
||||||
; Valley Bell
|
; Valley Bell
|
||||||
;----------------------------------------------------------------------------------------------------------------------------*/
|
;----------------------------------------------------------------------------------------------------------------------------*/
|
||||||
@@ -17,90 +15,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
/* PCM to ADPCM-B & ADPCM-B to PCM converters for NEO-GEO System ****
|
|
||||||
ADPCM-B - 1 channel 1.8-55.5 KHz, 16 MB Sample ROM size, 256 B min size of sample, 16 MB max, compatable with YM2608
|
|
||||||
|
|
||||||
http://www.raregame.ru/file/15/YM2610.pdf YM2610 DATASHEET
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const long stepSizeTable[16] =
|
|
||||||
{
|
|
||||||
57, 57, 57, 57, 77, 102, 128, 153,
|
|
||||||
57, 57, 57, 57, 77, 102, 128, 153
|
|
||||||
};
|
|
||||||
|
|
||||||
void adpcmBEncoderInit(AdpcmBEncoderState* encoder)
|
|
||||||
{
|
|
||||||
encoder->xn = 0;
|
|
||||||
encoder->stepSize = 127;
|
|
||||||
encoder->flag = false;
|
|
||||||
encoder->adpcmPack = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void adpcmBEncode(AdpcmBEncoderState* encoder, const int16_t* restrict in, uint8_t* restrict out, int len)
|
|
||||||
{
|
|
||||||
for (int lpc = 0; lpc < len; ++lpc)
|
|
||||||
{
|
|
||||||
long dn = (*in++) - encoder->xn;
|
|
||||||
|
|
||||||
long i = (labs(dn) << 16) / (encoder->stepSize << 14);
|
|
||||||
i = MIN(i, 7);
|
|
||||||
uint8_t adpcm = i;
|
|
||||||
|
|
||||||
i = (adpcm * 2 + 1) * encoder->stepSize / 8;
|
|
||||||
|
|
||||||
if (dn < 0)
|
|
||||||
{
|
|
||||||
adpcm |= 0x8;
|
|
||||||
encoder->xn -= i;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
encoder->xn += i;
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder->stepSize = (stepSizeTable[adpcm] * encoder->stepSize) / 64;
|
|
||||||
encoder->stepSize = CLAMP(encoder->stepSize, 127, 24576);
|
|
||||||
|
|
||||||
if (!encoder->flag)
|
|
||||||
{
|
|
||||||
encoder->adpcmPack = adpcm << 4;
|
|
||||||
encoder->flag = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
(*out++) = encoder->adpcmPack |= adpcm;
|
|
||||||
encoder->flag = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void adpcmBDecoderInit(AdpcmBDecoderState* decoder)
|
|
||||||
{
|
|
||||||
decoder->xn = 0;
|
|
||||||
decoder->stepSize = 127;
|
|
||||||
}
|
|
||||||
|
|
||||||
void adpcmBDecode(AdpcmBDecoderState* decoder, const uint8_t* restrict in, int16_t* restrict out, int len)
|
|
||||||
{
|
|
||||||
for (long lpc = 0; lpc < len * 2; ++lpc)
|
|
||||||
{
|
|
||||||
uint8_t adpcm = (!(lpc & 0x1) ? (*in) >> 4 : (*in++)) & 0xF;
|
|
||||||
|
|
||||||
long i = ((adpcm & 7) * 2 + 1) * decoder->stepSize / 8;
|
|
||||||
if (adpcm & 8)
|
|
||||||
decoder->xn -= i;
|
|
||||||
else
|
|
||||||
decoder->xn += i;
|
|
||||||
decoder->xn = CLAMP(decoder->xn, -32768, 32767);
|
|
||||||
|
|
||||||
decoder->stepSize = decoder->stepSize * stepSizeTable[adpcm] / 64;
|
|
||||||
decoder->stepSize = CLAMP(decoder->stepSize, 127, 24576);
|
|
||||||
|
|
||||||
(*out++) = (int16_t)decoder->xn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static FORCE_INLINE uint32_t DeltaTReg2SampleRate(uint16_t DeltaN, uint32_t Clock)
|
static FORCE_INLINE uint32_t DeltaTReg2SampleRate(uint16_t DeltaN, uint32_t Clock)
|
||||||
{
|
{
|
||||||
return (uint32_t)(DeltaN * (Clock / 72.0) / 65536.0 + 0.5);
|
return (uint32_t)(DeltaN * (Clock / 72.0) / 65536.0 + 0.5);
|
||||||
@@ -302,7 +216,7 @@ int main(int argc, char* argv[])
|
|||||||
printf("NeoGeo ADPCM-B En-/Decoder\n--------------------------\n");
|
printf("NeoGeo ADPCM-B En-/Decoder\n--------------------------\n");
|
||||||
if (argc < 4)
|
if (argc < 4)
|
||||||
{
|
{
|
||||||
printf("Usage: ADPCM_Encode.exe -method [-option] InputFile OutputFile\n");
|
printf("Usage: ADPCM_Encode -method [-option] InputFile OutputFile\n");
|
||||||
printf("-method - En-/Decoding Method:\n");
|
printf("-method - En-/Decoding Method:\n");
|
||||||
printf(" -d for decode (bin -> wav)\n");
|
printf(" -d for decode (bin -> wav)\n");
|
||||||
printf(" -e for encode (wav -> bin)\n");
|
printf(" -e for encode (wav -> bin)\n");
|
||||||
|
|||||||
92
neotools/libadpcmb.c
Normal file
92
neotools/libadpcmb.c
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/* libadpcmb.c (C) 2023 a dinosaur (zlib)
|
||||||
|
|
||||||
|
** YM2610 ADPCM-B Codec **
|
||||||
|
PCM to ADPCM-B & ADPCM-B to PCM converters for NEO-GEO System
|
||||||
|
ADPCM-B - 1 channel 1.8-55.5 KHz, 16 MB Sample ROM size,
|
||||||
|
256 B min size of sample, 16 MB max, compatable with YM2608
|
||||||
|
|
||||||
|
http://www.raregame.ru/file/15/YM2610.pdf YM2610 DATASHEET
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "adpcmb.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const long stepSizeTable[16] =
|
||||||
|
{
|
||||||
|
57, 57, 57, 57, 77, 102, 128, 153,
|
||||||
|
57, 57, 57, 57, 77, 102, 128, 153
|
||||||
|
};
|
||||||
|
|
||||||
|
void adpcmBEncoderInit(AdpcmBEncoderState* encoder)
|
||||||
|
{
|
||||||
|
encoder->xn = 0;
|
||||||
|
encoder->stepSize = 127;
|
||||||
|
encoder->flag = false;
|
||||||
|
encoder->adpcmPack = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adpcmBEncode(AdpcmBEncoderState* encoder, const int16_t* restrict in, uint8_t* restrict out, int len)
|
||||||
|
{
|
||||||
|
for (int lpc = 0; lpc < len; ++lpc)
|
||||||
|
{
|
||||||
|
long dn = (*in++) - encoder->xn;
|
||||||
|
|
||||||
|
long i = (labs(dn) << 16) / (encoder->stepSize << 14);
|
||||||
|
i = MIN(i, 7);
|
||||||
|
uint8_t adpcm = i;
|
||||||
|
|
||||||
|
i = (adpcm * 2 + 1) * encoder->stepSize / 8;
|
||||||
|
|
||||||
|
if (dn < 0)
|
||||||
|
{
|
||||||
|
adpcm |= 0x8;
|
||||||
|
encoder->xn -= i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
encoder->xn += i;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder->stepSize = (stepSizeTable[adpcm] * encoder->stepSize) / 64;
|
||||||
|
encoder->stepSize = CLAMP(encoder->stepSize, 127, 24576);
|
||||||
|
|
||||||
|
if (!encoder->flag)
|
||||||
|
{
|
||||||
|
encoder->adpcmPack = adpcm << 4;
|
||||||
|
encoder->flag = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*out++) = encoder->adpcmPack |= adpcm;
|
||||||
|
encoder->flag = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void adpcmBDecoderInit(AdpcmBDecoderState* decoder)
|
||||||
|
{
|
||||||
|
decoder->xn = 0;
|
||||||
|
decoder->stepSize = 127;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adpcmBDecode(AdpcmBDecoderState* decoder, const uint8_t* restrict in, int16_t* restrict out, int len)
|
||||||
|
{
|
||||||
|
for (long lpc = 0; lpc < len * 2; ++lpc)
|
||||||
|
{
|
||||||
|
uint8_t adpcm = (!(lpc & 0x1) ? (*in) >> 4 : (*in++)) & 0xF;
|
||||||
|
|
||||||
|
long i = ((adpcm & 7) * 2 + 1) * decoder->stepSize / 8;
|
||||||
|
if (adpcm & 8)
|
||||||
|
decoder->xn -= i;
|
||||||
|
else
|
||||||
|
decoder->xn += i;
|
||||||
|
decoder->xn = CLAMP(decoder->xn, -32768, 32767);
|
||||||
|
|
||||||
|
decoder->stepSize = decoder->stepSize * stepSizeTable[adpcm] / 64;
|
||||||
|
decoder->stepSize = CLAMP(decoder->stepSize, 127, 24576);
|
||||||
|
|
||||||
|
(*out++) = (int16_t)decoder->xn;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "neoadpcmextract.h"
|
#include "neoadpcmextract.h"
|
||||||
#include "adpcm.h"
|
#include "adpcm.h"
|
||||||
|
#include "adpcmb.h"
|
||||||
#include "wave.h"
|
#include "wave.h"
|
||||||
#include "endian.h"
|
#include "endian.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -71,7 +72,6 @@ int writeAdpcmA(int id, const Buffer* enc, Buffer* pcm)
|
|||||||
{
|
{
|
||||||
char name[32];
|
char name[32];
|
||||||
snprintf(name, sizeof(name), "smpa_%02x.wav", id);
|
snprintf(name, sizeof(name), "smpa_%02x.wav", id);
|
||||||
fprintf(stderr, "write \"%s\"\n", name);
|
|
||||||
FILE* fout = fopen(name, "wb");
|
FILE* fout = fopen(name, "wb");
|
||||||
if (!fout)
|
if (!fout)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -93,7 +93,7 @@ int writeAdpcmA(int id, const Buffer* enc, Buffer* pcm)
|
|||||||
size_t decoded = 0;
|
size_t decoded = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
size_t blockSize = MIN(enc->size - decoded, DECODE_BUFFER_SIZE);
|
const size_t blockSize = MIN(enc->size - decoded, DECODE_BUFFER_SIZE);
|
||||||
adpcmADecode(&decoder, &((const char*)enc->data)[decoded], (short*)pcm->data, blockSize);
|
adpcmADecode(&decoder, &((const char*)enc->data)[decoded], (short*)pcm->data, blockSize);
|
||||||
fwrite(pcm->data, sizeof(short), blockSize * 2, fout);
|
fwrite(pcm->data, sizeof(short), blockSize * 2, fout);
|
||||||
decoded += DECODE_BUFFER_SIZE;
|
decoded += DECODE_BUFFER_SIZE;
|
||||||
@@ -101,22 +101,44 @@ int writeAdpcmA(int id, const Buffer* enc, Buffer* pcm)
|
|||||||
while (decoded < enc->size);
|
while (decoded < enc->size);
|
||||||
|
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
|
fprintf(stderr, "Wrote \"%s\"\n", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int writeAdpcmB(int id, const Buffer* enc)
|
int writeAdpcmB(int id, const Buffer* enc, Buffer* pcm)
|
||||||
{
|
{
|
||||||
char name[32];
|
char name[32];
|
||||||
snprintf(name, sizeof(name), "smpb_%02x.pcm", id);
|
snprintf(name, sizeof(name), "smpb_%02x.wav", id);
|
||||||
printf("./adpcmb -d \"%s\" \"$WAVDIR/%s.wav\"\n", name, name);
|
|
||||||
|
|
||||||
// Write ADPCM sample
|
|
||||||
FILE* fout = fopen(name, "wb");
|
FILE* fout = fopen(name, "wb");
|
||||||
if (!fout)
|
if (!fout)
|
||||||
return 1;
|
return 1;
|
||||||
fwrite(enc->data, sizeof(uint8_t), enc->size, fout);
|
|
||||||
|
// Write wave header
|
||||||
|
const uint32_t decodedSize = enc->size * 2 * sizeof(short);
|
||||||
|
waveWrite(&(const WaveSpec)
|
||||||
|
{
|
||||||
|
.format = WAVE_FMT_PCM,
|
||||||
|
.channels = 1,
|
||||||
|
.rate = 22050,
|
||||||
|
.bytedepth = 2
|
||||||
|
},
|
||||||
|
NULL, decodedSize, &waveStreamDefaultCb, fout);
|
||||||
|
|
||||||
|
bufferResize(pcm, DECODE_BUFFER_SIZE * 2 * sizeof(short));
|
||||||
|
AdpcmBDecoderState decoder;
|
||||||
|
adpcmBDecoderInit(&decoder);
|
||||||
|
size_t decoded = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const size_t blockSize = MIN(enc->size - decoded, DECODE_BUFFER_SIZE);
|
||||||
|
adpcmBDecode(&decoder, &((const uint8_t*)enc->data)[decoded], (int16_t*)pcm->data, blockSize);
|
||||||
|
fwrite(pcm->data, sizeof(int16_t), blockSize * 2, fout);
|
||||||
|
decoded += DECODE_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
while (decoded < enc->size);
|
||||||
|
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
|
fprintf(stderr, "Wrote \"%s\"\n", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +175,7 @@ int main(int argc, char** argv)
|
|||||||
if (scanType == 'A')
|
if (scanType == 'A')
|
||||||
writeAdpcmA(smpaCount++, &rawbuf, &decbuf);
|
writeAdpcmA(smpaCount++, &rawbuf, &decbuf);
|
||||||
else if (scanType == 'B')
|
else if (scanType == 'B')
|
||||||
writeAdpcmB(smpbCount++, &rawbuf);
|
writeAdpcmB(smpbCount++, &rawbuf, &decbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(rawbuf.data);
|
free(rawbuf.data);
|
||||||
|
|||||||
Reference in New Issue
Block a user