mirror of
https://github.com/ScrelliCopter/VGM-Tools
synced 2025-02-21 04:09:25 +11:00
Initial commit.
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
*.exe
|
||||||
|
*.vgm
|
||||||
|
*.vgz
|
||||||
|
*.log
|
||||||
|
*.pcm
|
||||||
|
*.wav
|
||||||
32
README.md
Normal file
32
README.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
Neo-Geo VGM tools
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
A hodge-podge of tools for working on NG VGM files,
|
||||||
|
these files are provided in the hope that they may be useful to someone.
|
||||||
|
|
||||||
|
Makefiles have currently not been tested but shouldn't be hard to get working.
|
||||||
|
Windows binaries are available under the Releases tab.
|
||||||
|
|
||||||
|
Included tools (sources included).
|
||||||
|
- **adpcm.exe**:
|
||||||
|
ADPCM Type-A to WAV converter.
|
||||||
|
- **adpcmb.exe**:
|
||||||
|
ADPCM Type-B encoding tool that also does decoding to WAV.
|
||||||
|
- **neoadpcmextract.exe**:
|
||||||
|
Scans a .vgm and dumps all ADPCM type A&B data to raw .pcm files.
|
||||||
|
- **autoextract.bat**:
|
||||||
|
Convenience batch script that uses the above tools to dump all samples to WAVs.
|
||||||
|
|
||||||
|
How to use
|
||||||
|
----------
|
||||||
|
Copy your .vgz into this directory, drag it onto autoextract.bat,
|
||||||
|
the script will create a directory of the same name and dump all the converted samples there.
|
||||||
|
|
||||||
|
That's all there is to it.
|
||||||
|
|
||||||
|
TODO
|
||||||
|
----
|
||||||
|
|
||||||
|
- Replace the batch script with something less shite (and actually cross-platform).
|
||||||
|
- Write a makefile for neoadpcmextract.
|
||||||
|
- Make this stuff build on Linux.
|
||||||
70
adpcm.Makefile
Normal file
70
adpcm.Makefile
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# Standard makefile to use as a base for DJGPP projects
|
||||||
|
# By MARTINEZ Fabrice aka SNK of SUPREMACY
|
||||||
|
|
||||||
|
# Programs to use during make
|
||||||
|
AR = ar
|
||||||
|
CC = gcc
|
||||||
|
LD = gcc
|
||||||
|
ASM = nasm
|
||||||
|
PACKER = upx
|
||||||
|
|
||||||
|
# Flags for debugging
|
||||||
|
#DEBUG=1
|
||||||
|
#SYMBOLS=1
|
||||||
|
|
||||||
|
# Flags for compilation
|
||||||
|
ASMFLAGS = -f coff
|
||||||
|
ifdef SYMBOLS
|
||||||
|
CFLAGS = -o -mpentium -Wall -Werror -g
|
||||||
|
LDFLAGS = -s
|
||||||
|
else
|
||||||
|
CFLAGS = -fomit-frame-pointer -O3 -mpentium -Werror -Wall \
|
||||||
|
-W -Wno-sign-compare -Wno-unused \
|
||||||
|
-Wpointer-arith -Wbad-function-cast -Wcast-align -Waggregate-return \
|
||||||
|
-pedantic \
|
||||||
|
-Wshadow \
|
||||||
|
-Wstrict-prototypes
|
||||||
|
LDFLAGS =
|
||||||
|
endif
|
||||||
|
CDEFS =
|
||||||
|
ASMDEFS =
|
||||||
|
|
||||||
|
# Object files
|
||||||
|
MAINOBJS =
|
||||||
|
|
||||||
|
# Library files
|
||||||
|
MAINLIBS = obj/adpcm.a
|
||||||
|
|
||||||
|
# Make rules
|
||||||
|
all: adpcm.exe
|
||||||
|
|
||||||
|
adpcm.exe: $(MAINOBJS) $(MAINLIBS)
|
||||||
|
$(LD) $(LDFLAGS) $(MAINOBJS) $(MAINLIBS) -o $@
|
||||||
|
|
||||||
|
src/%.asm:
|
||||||
|
|
||||||
|
obj/%.o: src/%.c
|
||||||
|
$(CC) $(CDEFS) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
obj/%.oa: src/%.asm
|
||||||
|
$(ASM) -o $@ $(ASMFLAGS) $(ASMDEFS) $<
|
||||||
|
|
||||||
|
obj/%.a:
|
||||||
|
$(AR) cr $@ $^
|
||||||
|
|
||||||
|
# Rules to manage files
|
||||||
|
pack: adpcm.exe
|
||||||
|
$(PACKER) adpcm.exe
|
||||||
|
|
||||||
|
mkdir:
|
||||||
|
md obj
|
||||||
|
|
||||||
|
clean:
|
||||||
|
del obj\*.o
|
||||||
|
del obj\*.a
|
||||||
|
del obj\*.oa
|
||||||
|
del *.exe
|
||||||
|
|
||||||
|
# Rules to make libraries
|
||||||
|
obj/adpcm.a: obj/adpcm.o
|
||||||
|
# obj/decode.oa \
|
||||||
158
adpcm.c
Normal file
158
adpcm.c
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
#include <process.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <mem.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 1024*256
|
||||||
|
#define ADPCMA_VOLUME_RATE 1
|
||||||
|
#define ADPCMA_DECODE_RANGE 1024
|
||||||
|
#define ADPCMA_DECODE_MIN (-(ADPCMA_DECODE_RANGE*ADPCMA_VOLUME_RATE))
|
||||||
|
#define ADPCMA_DECODE_MAX ((ADPCMA_DECODE_RANGE*ADPCMA_VOLUME_RATE)-1)
|
||||||
|
#define ADPCMA_VOLUME_DIV 1
|
||||||
|
|
||||||
|
unsigned char RiffWave[44] = {
|
||||||
|
0x52, 0x49, 0x46, 0x46, 0x24, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74,
|
||||||
|
0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x44, 0x48, 0x00, 0x00, 0x88, 0x90,
|
||||||
|
0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static int decode_tableA1[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];
|
||||||
|
static int signal;
|
||||||
|
static int delta;
|
||||||
|
|
||||||
|
void adpcm_init(void);
|
||||||
|
void adpcm_decode(void *, void *, int);
|
||||||
|
int Limit(int, int, int);
|
||||||
|
FILE* errorlog;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *Fp1, *Fp2;
|
||||||
|
void *InputBuffer, *OutputBuffer;
|
||||||
|
int Readed;
|
||||||
|
unsigned int Filelen;
|
||||||
|
|
||||||
|
puts("**** ADPCM to PCM converter v 1.01\n");
|
||||||
|
if (argc!=3) {
|
||||||
|
puts("USAGE: adpcm <InputFile.pcm> <OutputFile.wav>");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fp1 = fopen(argv[1], "rb");
|
||||||
|
if (Fp1==NULL) {
|
||||||
|
printf("Could not open inputfile %s\n", argv[1]);
|
||||||
|
exit(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fp2 = fopen(argv[2], "wb");
|
||||||
|
if (Fp2==NULL) {
|
||||||
|
printf("Could not open outputfile %s\n", argv[2]);
|
||||||
|
exit(-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
errorlog = fopen("error.log", "wb");
|
||||||
|
|
||||||
|
InputBuffer = malloc(BUFFER_SIZE);
|
||||||
|
if (InputBuffer == NULL) {
|
||||||
|
printf("Could not allocate input buffer. (%d bytes)\n", BUFFER_SIZE);
|
||||||
|
exit(-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputBuffer = malloc(BUFFER_SIZE*10);
|
||||||
|
if (OutputBuffer == NULL) {
|
||||||
|
printf("Could not allocate output buffer. (%d bytes)\n", BUFFER_SIZE*4);
|
||||||
|
exit(-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
adpcm_init();
|
||||||
|
|
||||||
|
Filelen = filelength(fileno(Fp1));
|
||||||
|
*((unsigned int*)(&RiffWave[4])) = Filelen*4 + 0x2C;
|
||||||
|
*((unsigned int*)(&RiffWave[0x28])) = Filelen*4;
|
||||||
|
|
||||||
|
fwrite(RiffWave, 0x2c, 1, Fp2);
|
||||||
|
|
||||||
|
do {
|
||||||
|
Readed = fread(InputBuffer, 1, BUFFER_SIZE, Fp1);
|
||||||
|
if (Readed>0) {
|
||||||
|
adpcm_decode(InputBuffer, OutputBuffer, Readed);
|
||||||
|
fwrite(OutputBuffer, Readed*4, 1, Fp2);
|
||||||
|
}
|
||||||
|
} while (Readed==BUFFER_SIZE);
|
||||||
|
|
||||||
|
free(InputBuffer);
|
||||||
|
free(OutputBuffer);
|
||||||
|
fclose(Fp1);
|
||||||
|
fclose(Fp2);
|
||||||
|
|
||||||
|
puts("Done...");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adpcm_init(void)
|
||||||
|
{
|
||||||
|
int step, nib;
|
||||||
|
|
||||||
|
for (step = 0; step <= 48; step++)
|
||||||
|
{
|
||||||
|
int stepval = floor (16.0 * pow (11.0 / 10.0, (double)step) * ADPCMA_VOLUME_RATE);
|
||||||
|
/* loop over all nibbles and compute the difference */
|
||||||
|
for (nib = 0; nib < 16; nib++)
|
||||||
|
{
|
||||||
|
int value = stepval*((nib&0x07)*2+1)/8;
|
||||||
|
jedi_table[step*16+nib] = (nib&0x08) ? -value : value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delta = 0;
|
||||||
|
signal = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adpcm_decode(void *InputBuffer, void *OutputBuffer, int Length)
|
||||||
|
{
|
||||||
|
char *in;
|
||||||
|
short *out;
|
||||||
|
int i, data, oldsignal;
|
||||||
|
|
||||||
|
in = (char *)InputBuffer;
|
||||||
|
out = (short *)OutputBuffer;
|
||||||
|
|
||||||
|
for(i=0;i<Length;i++) {
|
||||||
|
data = ((*in)>>4)&0x0F;
|
||||||
|
oldsignal = signal;
|
||||||
|
signal = Limit(signal + (jedi_table[data+delta]), ADPCMA_DECODE_MAX, ADPCMA_DECODE_MIN);
|
||||||
|
delta = Limit(delta + decode_tableA1[data], 48*16, 0*16);
|
||||||
|
if (abs(oldsignal-signal)>2500) {
|
||||||
|
fprintf(errorlog, "WARNING: Suspicious signal evolution %06x,%06x pos:%06x delta:%06x\n", oldsignal, signal, i, delta);
|
||||||
|
fprintf(errorlog, "data:%02x dx:%08x\n", data, jedi_table[data+delta]);
|
||||||
|
}
|
||||||
|
*(out++) = (signal&0xffff)*32;
|
||||||
|
|
||||||
|
data = (*in++)&0x0F;
|
||||||
|
oldsignal = signal;
|
||||||
|
signal = Limit(signal + (jedi_table[data+delta]), ADPCMA_DECODE_MAX, ADPCMA_DECODE_MIN);
|
||||||
|
delta = Limit(delta + decode_tableA1[data], 48*16, 0*16);
|
||||||
|
if (abs(oldsignal-signal)>2500) {
|
||||||
|
fprintf(errorlog, "WARNING: Suspicious signal evolution %06x,%06x pos:%06x delta:%06x\n", oldsignal, signal, i, delta);
|
||||||
|
fprintf(errorlog, "data:%02x dx:%08x\n", data, jedi_table[data+delta]);
|
||||||
|
}
|
||||||
|
*(out++) = (signal&0xffff)*32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Limit( int val, int max, int min ) {
|
||||||
|
|
||||||
|
if ( val > max )
|
||||||
|
val = max;
|
||||||
|
else if ( val < min )
|
||||||
|
val = min;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
16
adpcm.txt
Normal file
16
adpcm.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
**** ADPCM to PCM converter v 1.01
|
||||||
|
|
||||||
|
USAGE: adpcm <InputFile.pcm> <OutputFile.wav>
|
||||||
|
|
||||||
|
By MARTINEZ Fabrice aka SNK of SUPREMACY
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--(ADPCM.diz.txt)--
|
||||||
|
|
||||||
|
ADPCM To WAV Converter
|
||||||
|
This simple utility converts ADPCM files from NeoGeo cartridge systems
|
||||||
|
(*_v?.rom) or NeoGeo CD systems (*.PCM). This tool converts ADPCM A type
|
||||||
|
samples (99% of the samples), ADPCM B type samples will sound distorted...
|
||||||
|
Get it here
|
||||||
|
|
||||||
15
adpcmb.Makefile
Normal file
15
adpcmb.Makefile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
CC = gcc
|
||||||
|
CFLAGS = -O3
|
||||||
|
|
||||||
|
SRC = .
|
||||||
|
OBJ = .
|
||||||
|
|
||||||
|
OUT_OBJ = $(OBJ)/adpcmb.exe
|
||||||
|
|
||||||
|
all: $(OUT_OBJ)
|
||||||
|
|
||||||
|
$(OBJ)/%.exe: $(SRC)/%.c
|
||||||
|
$(CC) $(CCFLAGS) $(MAINFLAGS) $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm $(OUT_OBJ)
|
||||||
445
adpcmb.c
Normal file
445
adpcmb.c
Normal file
@@ -0,0 +1,445 @@
|
|||||||
|
/*; 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
|
||||||
|
;
|
||||||
|
; Fred/FRONT
|
||||||
|
;
|
||||||
|
;Usage 1: ADPCM_Encode.exe -d [-r:reg,clock] Input.bin Output.wav
|
||||||
|
;Usage 2: ADPCM_Encode.exe -e Input.wav Output.bin
|
||||||
|
;
|
||||||
|
; Valley Bell
|
||||||
|
;----------------------------------------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define INLINE static __inline
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define INLINE static __inline__
|
||||||
|
#else
|
||||||
|
#define INLINE static inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_STDINT
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef uint8_t UINT8;
|
||||||
|
typedef int8_t INT8;
|
||||||
|
typedef uint16_t UINT16;
|
||||||
|
typedef int16_t INT16;
|
||||||
|
typedef uint32_t UINT32;
|
||||||
|
typedef int32_t INT32;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef unsigned char UINT8;
|
||||||
|
typedef signed char INT8;
|
||||||
|
typedef unsigned short UINT16;
|
||||||
|
typedef signed short INT16;
|
||||||
|
typedef unsigned int UINT32;
|
||||||
|
typedef signed int INT32;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef UINT8 BYTE;
|
||||||
|
typedef UINT16 WORD;
|
||||||
|
typedef UINT32 DWORD;
|
||||||
|
|
||||||
|
// -- from mmsystem.h --
|
||||||
|
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
|
||||||
|
((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
|
||||||
|
((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
|
||||||
|
|
||||||
|
// -- from mmreg.h, slightly modified --
|
||||||
|
|
||||||
|
/* general waveform format structure (information common to all formats) */
|
||||||
|
typedef struct waveformat_tag {
|
||||||
|
WORD wFormatTag; /* format type */
|
||||||
|
WORD nChannels; /* number of channels (i.e. mono, stereo...) */
|
||||||
|
DWORD nSamplesPerSec; /* sample rate */
|
||||||
|
DWORD nAvgBytesPerSec; /* for buffer estimation */
|
||||||
|
WORD nBlockAlign; /* block size of data */
|
||||||
|
WORD wBitsPerSample;
|
||||||
|
} WAVEFORMAT;
|
||||||
|
|
||||||
|
/* flags for wFormatTag field of WAVEFORMAT */
|
||||||
|
#define WAVE_FORMAT_PCM 1
|
||||||
|
|
||||||
|
// -- from mm*.h end --
|
||||||
|
|
||||||
|
#define FOURCC_RIFF MAKEFOURCC('R', 'I', 'F', 'F')
|
||||||
|
#define FOURCC_WAVE MAKEFOURCC('W', 'A', 'V', 'E')
|
||||||
|
#define FOURCC_fmt_ MAKEFOURCC('f', 'm', 't', ' ')
|
||||||
|
#define FOURCC_data MAKEFOURCC('d', 'a', 't', 'a')
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UINT32 RIFFfcc; // 'RIFF'
|
||||||
|
UINT32 RIFFLen;
|
||||||
|
UINT32 WAVEfcc; // 'WAVE'
|
||||||
|
UINT32 fmt_fcc; // 'fmt '
|
||||||
|
UINT32 fmt_Len;
|
||||||
|
WAVEFORMAT fmt_Data;
|
||||||
|
UINT32 datafcc; // 'data'
|
||||||
|
UINT32 dataLen;
|
||||||
|
} WAVE_FILE;
|
||||||
|
|
||||||
|
|
||||||
|
static const long stepsizeTable[16] =
|
||||||
|
{
|
||||||
|
57, 57, 57, 57, 77, 102, 128, 153,
|
||||||
|
57, 57, 57, 57, 77, 102, 128, 153
|
||||||
|
};
|
||||||
|
|
||||||
|
static int YM2610_ADPCM_Encode(INT16 *src, UINT8 *dest, int len)
|
||||||
|
{
|
||||||
|
int lpc, flag;
|
||||||
|
long i, dn, xn, stepSize;
|
||||||
|
UINT8 adpcm;
|
||||||
|
UINT8 adpcmPack;
|
||||||
|
|
||||||
|
xn = 0;
|
||||||
|
stepSize = 127;
|
||||||
|
flag = 0;
|
||||||
|
|
||||||
|
for (lpc = 0; lpc < len; lpc ++)
|
||||||
|
{
|
||||||
|
dn = *src - xn;
|
||||||
|
src ++;
|
||||||
|
|
||||||
|
i = (abs(dn) << 16) / (stepSize << 14);
|
||||||
|
if (i > 7)
|
||||||
|
i = 7;
|
||||||
|
adpcm = (UINT8)i;
|
||||||
|
|
||||||
|
i = (adpcm * 2 + 1) * stepSize / 8;
|
||||||
|
|
||||||
|
if (dn < 0)
|
||||||
|
{
|
||||||
|
adpcm |= 0x8;
|
||||||
|
xn -= i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xn += i;
|
||||||
|
}
|
||||||
|
|
||||||
|
stepSize = (stepsizeTable[adpcm] * stepSize) / 64;
|
||||||
|
|
||||||
|
if (stepSize < 127)
|
||||||
|
stepSize = 127;
|
||||||
|
else if (stepSize > 24576)
|
||||||
|
stepSize = 24576;
|
||||||
|
|
||||||
|
if (flag == 0)
|
||||||
|
{
|
||||||
|
adpcmPack = (adpcm << 4);
|
||||||
|
flag = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
adpcmPack |= adpcm;
|
||||||
|
*dest = adpcmPack;
|
||||||
|
dest ++;
|
||||||
|
flag = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int YM2610_ADPCM_Decode(UINT8 *src, INT16 *dest, int len)
|
||||||
|
{
|
||||||
|
int lpc, flag, shift, step;
|
||||||
|
long i, xn, stepSize;
|
||||||
|
UINT8 adpcm;
|
||||||
|
|
||||||
|
xn = 0;
|
||||||
|
stepSize = 127;
|
||||||
|
flag = 0;
|
||||||
|
shift = 4;
|
||||||
|
step = 0;
|
||||||
|
|
||||||
|
for (lpc = 0; lpc < len; lpc ++)
|
||||||
|
{
|
||||||
|
adpcm = (*src >> shift) & 0xf;
|
||||||
|
|
||||||
|
i = ((adpcm & 7) * 2 + 1) * stepSize / 8;
|
||||||
|
if (adpcm & 8)
|
||||||
|
xn -= i;
|
||||||
|
else
|
||||||
|
xn += i;
|
||||||
|
|
||||||
|
if (xn > 32767)
|
||||||
|
xn = 32767;
|
||||||
|
else if (xn < -32768)
|
||||||
|
xn = -32768;
|
||||||
|
|
||||||
|
stepSize = stepSize * stepsizeTable[adpcm] / 64;
|
||||||
|
|
||||||
|
if (stepSize < 127)
|
||||||
|
stepSize = 127;
|
||||||
|
else if (stepSize > 24576)
|
||||||
|
stepSize = 24576;
|
||||||
|
|
||||||
|
*dest = (INT16)xn;
|
||||||
|
dest ++;
|
||||||
|
|
||||||
|
src += step;
|
||||||
|
step = step ^ 1;
|
||||||
|
shift = shift ^ 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE UINT32 DeltaTReg2SampleRate(UINT16 DeltaN, UINT32 Clock)
|
||||||
|
{
|
||||||
|
return (UINT32)(DeltaN * (Clock / 72.0) / 65536.0 + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int ErrVal;
|
||||||
|
int ArgBase;
|
||||||
|
DWORD OutSmplRate;
|
||||||
|
FILE* hFile;
|
||||||
|
unsigned int AdpcmSize;
|
||||||
|
UINT8* AdpcmData;
|
||||||
|
unsigned int WaveSize;
|
||||||
|
UINT16* WaveData;
|
||||||
|
WAVE_FILE WaveFile;
|
||||||
|
WAVEFORMAT* TempFmt;
|
||||||
|
unsigned int TempLng;
|
||||||
|
UINT16 DTRegs;
|
||||||
|
char* TempPnt;
|
||||||
|
|
||||||
|
printf("NeoGeo ADPCM-B En-/Decoder\n--------------------------\n");
|
||||||
|
if (argc < 4)
|
||||||
|
{
|
||||||
|
printf("Usage: ADPCM_Encode.exe -method [-option] InputFile OutputFile\n");
|
||||||
|
printf("-method - En-/Decoding Method:\n");
|
||||||
|
printf(" -d for decode (bin -> wav)\n");
|
||||||
|
printf(" -e for encode (wav -> bin)\n");
|
||||||
|
printf("-option - Options for Sample Rate of decoded Wave:\n");
|
||||||
|
printf(" -s:rate - Sample Rate in Hz (default: 22050)\n");
|
||||||
|
printf(" -r:regs[,clock] - DeltaT Register value (use 0x for hex) and chip clock\n");
|
||||||
|
printf(" (default chip clock: 4 MHz)\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Wave In-/Output is 16-bit, Mono\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "-d") && strcmp(argv[1], "-e"))
|
||||||
|
{
|
||||||
|
printf("Wrong option! Use -d or -e!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrVal = 0;
|
||||||
|
AdpcmData = NULL;
|
||||||
|
WaveData = NULL;
|
||||||
|
OutSmplRate = 0;
|
||||||
|
|
||||||
|
ArgBase = 2;
|
||||||
|
if (argv[2][0] == '-' && argv[2][2] == ':')
|
||||||
|
{
|
||||||
|
switch(argv[2][1])
|
||||||
|
{
|
||||||
|
case 's':
|
||||||
|
OutSmplRate = strtol(argv[2] + 3, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
DTRegs = (UINT16)strtoul(argv[2] + 3, &TempPnt, 0);
|
||||||
|
TempLng = 0;
|
||||||
|
if (*TempPnt == ',')
|
||||||
|
{
|
||||||
|
TempLng = strtoul(TempPnt + 1, NULL, 0);
|
||||||
|
}
|
||||||
|
if (! TempLng)
|
||||||
|
TempLng = 4000000;
|
||||||
|
OutSmplRate = DeltaTReg2SampleRate(DTRegs, TempLng);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ArgBase ++;
|
||||||
|
if (argc < ArgBase + 2)
|
||||||
|
{
|
||||||
|
printf("Not enought arguments!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(argv[1][1])
|
||||||
|
{
|
||||||
|
case 'd':
|
||||||
|
hFile = fopen(argv[ArgBase + 0], "rb");
|
||||||
|
if (hFile == NULL)
|
||||||
|
{
|
||||||
|
printf("Error opening input file!\n");
|
||||||
|
ErrVal = 2;
|
||||||
|
goto Finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(hFile, 0x00, SEEK_END);
|
||||||
|
AdpcmSize = ftell(hFile);
|
||||||
|
|
||||||
|
fseek(hFile, 0x00, SEEK_SET);
|
||||||
|
AdpcmData = (UINT8*)malloc(AdpcmSize);
|
||||||
|
fread(AdpcmData, 0x01, AdpcmSize, hFile);
|
||||||
|
fclose(hFile);
|
||||||
|
|
||||||
|
WaveSize = AdpcmSize * 2; // 4-bit ADPCM -> 2 values per byte
|
||||||
|
WaveData = (UINT16*)malloc(WaveSize * 2);
|
||||||
|
printf("Decoding ...");
|
||||||
|
YM2610_ADPCM_Decode(AdpcmData, WaveData, WaveSize);
|
||||||
|
printf(" OK\n");
|
||||||
|
|
||||||
|
WaveFile.RIFFfcc = FOURCC_RIFF;
|
||||||
|
WaveFile.WAVEfcc = FOURCC_WAVE;
|
||||||
|
WaveFile.fmt_fcc = FOURCC_fmt_;
|
||||||
|
WaveFile.fmt_Len = sizeof(WAVEFORMAT);
|
||||||
|
|
||||||
|
TempFmt = &WaveFile.fmt_Data;
|
||||||
|
TempFmt->wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
TempFmt->nChannels = 1;
|
||||||
|
TempFmt->wBitsPerSample = 16;
|
||||||
|
TempFmt->nSamplesPerSec = OutSmplRate ? OutSmplRate : 22050;
|
||||||
|
TempFmt->nBlockAlign = TempFmt->nChannels * TempFmt->wBitsPerSample / 8;
|
||||||
|
TempFmt->nAvgBytesPerSec = TempFmt->nBlockAlign * TempFmt->nSamplesPerSec;
|
||||||
|
|
||||||
|
WaveFile.datafcc = FOURCC_data;
|
||||||
|
WaveFile.dataLen = WaveSize * 2;
|
||||||
|
WaveFile.RIFFLen = 0x04 + 0x08 + WaveFile.fmt_Len + 0x08 + WaveFile.dataLen;
|
||||||
|
|
||||||
|
hFile = fopen(argv[ArgBase + 1], "wb");
|
||||||
|
if (hFile == NULL)
|
||||||
|
{
|
||||||
|
printf("Error opening output file!\n");
|
||||||
|
ErrVal = 3;
|
||||||
|
goto Finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(&WaveFile, sizeof(WAVE_FILE), 0x01, hFile);
|
||||||
|
fwrite(WaveData, 0x02, WaveSize, hFile);
|
||||||
|
fclose(hFile);
|
||||||
|
printf("File written.\n");
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
hFile = fopen(argv[ArgBase + 0], "rb");
|
||||||
|
if (hFile == NULL)
|
||||||
|
{
|
||||||
|
printf("Error opening input file!\n");
|
||||||
|
ErrVal = 2;
|
||||||
|
goto Finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(&WaveFile.RIFFfcc, 0x0C, 0x01, hFile);
|
||||||
|
if (WaveFile.RIFFfcc != FOURCC_RIFF || WaveFile.WAVEfcc != FOURCC_WAVE)
|
||||||
|
{
|
||||||
|
fclose(hFile);
|
||||||
|
printf("This is no wave file!\n");
|
||||||
|
ErrVal = 4;
|
||||||
|
goto Finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
TempLng = fread(&WaveFile.fmt_fcc, 0x04, 0x01, hFile);
|
||||||
|
fread(&WaveFile.fmt_Len, 0x04, 0x01, hFile);
|
||||||
|
while(WaveFile.fmt_fcc != FOURCC_fmt_)
|
||||||
|
{
|
||||||
|
if (! TempLng) // TempLng == 0 -> EOF reached
|
||||||
|
{
|
||||||
|
fclose(hFile);
|
||||||
|
printf("Error in wave file: Can't find format-tag!\n");
|
||||||
|
ErrVal = 4;
|
||||||
|
goto Finish;
|
||||||
|
}
|
||||||
|
fseek(hFile, WaveFile.fmt_Len, SEEK_CUR);
|
||||||
|
|
||||||
|
TempLng = fread(&WaveFile.fmt_fcc, 0x04, 0x01, hFile);
|
||||||
|
fread(&WaveFile.fmt_Len, 0x04, 0x01, hFile);
|
||||||
|
};
|
||||||
|
TempLng = ftell(hFile) + WaveFile.fmt_Len;
|
||||||
|
fread(&WaveFile.fmt_Data, sizeof(WAVEFORMAT), 0x01, hFile);
|
||||||
|
fseek(hFile, TempLng, SEEK_SET);
|
||||||
|
|
||||||
|
TempFmt = &WaveFile.fmt_Data;
|
||||||
|
if (TempFmt->wFormatTag != WAVE_FORMAT_PCM)
|
||||||
|
{
|
||||||
|
fclose(hFile);
|
||||||
|
printf("Error in wave file: Compressed wave file are not supported!\n");
|
||||||
|
ErrVal = 4;
|
||||||
|
goto Finish;
|
||||||
|
}
|
||||||
|
if (TempFmt->nChannels != 1)
|
||||||
|
{
|
||||||
|
fclose(hFile);
|
||||||
|
printf("Error in wave file: Unsupported number of channels (%hu)!\n", TempFmt->nChannels);
|
||||||
|
ErrVal = 4;
|
||||||
|
goto Finish;
|
||||||
|
}
|
||||||
|
if (TempFmt->wBitsPerSample != 16)
|
||||||
|
{
|
||||||
|
fclose(hFile);
|
||||||
|
printf("Error in wave file: Only 16-bit waves are supported! (File uses %hu bit)\n", TempFmt->wBitsPerSample);
|
||||||
|
ErrVal = 4;
|
||||||
|
goto Finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
TempLng = fread(&WaveFile.datafcc, 0x04, 0x01, hFile);
|
||||||
|
fread(&WaveFile.dataLen, 0x04, 0x01, hFile);
|
||||||
|
while(WaveFile.datafcc != FOURCC_data)
|
||||||
|
{
|
||||||
|
if (! TempLng) // TempLng == 0 -> EOF reached
|
||||||
|
{
|
||||||
|
fclose(hFile);
|
||||||
|
printf("Error in wave file: Can't find data-tag!\n");
|
||||||
|
ErrVal = 4;
|
||||||
|
goto Finish;
|
||||||
|
}
|
||||||
|
fseek(hFile, WaveFile.dataLen, SEEK_CUR);
|
||||||
|
|
||||||
|
TempLng = fread(&WaveFile.datafcc, 0x04, 0x01, hFile);
|
||||||
|
fread(&WaveFile.dataLen, 0x04, 0x01, hFile);
|
||||||
|
};
|
||||||
|
WaveSize = WaveFile.dataLen / 2;
|
||||||
|
WaveData = (UINT16*)malloc(WaveSize * 2);
|
||||||
|
fread(WaveData, 0x02, WaveSize, hFile);
|
||||||
|
|
||||||
|
fclose(hFile);
|
||||||
|
|
||||||
|
AdpcmSize = WaveSize / 2;
|
||||||
|
AdpcmData = (UINT8*)malloc(AdpcmSize);
|
||||||
|
printf("Encoding ...");
|
||||||
|
YM2610_ADPCM_Encode(WaveData, AdpcmData, WaveSize);
|
||||||
|
printf(" OK\n");
|
||||||
|
|
||||||
|
hFile = fopen(argv[ArgBase + 1], "wb");
|
||||||
|
if (hFile == NULL)
|
||||||
|
{
|
||||||
|
printf("Error opening output file!\n");
|
||||||
|
ErrVal = 3;
|
||||||
|
goto Finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(AdpcmData, 0x01, AdpcmSize, hFile);
|
||||||
|
fclose(hFile);
|
||||||
|
printf("File written.\n");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Finish:
|
||||||
|
free(AdpcmData);
|
||||||
|
free(WaveData);
|
||||||
|
|
||||||
|
return ErrVal;
|
||||||
|
}
|
||||||
19
autoextract.bat
Normal file
19
autoextract.bat
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
if ["%~x1"]==[".vgz"] goto vgztopcm else goto vgmtopcm
|
||||||
|
|
||||||
|
:vgmtopcm
|
||||||
|
neoadpcmextract.exe %1
|
||||||
|
goto pcmtowav
|
||||||
|
|
||||||
|
:vgztopcm
|
||||||
|
copy /y %1 temp.vgm.gz
|
||||||
|
gzip.exe -d temp.vgm.gz
|
||||||
|
neoadpcmextract.exe temp.vgm
|
||||||
|
del temp.vgm
|
||||||
|
goto pcmtowav
|
||||||
|
|
||||||
|
:pcmtowav
|
||||||
|
for /r %%v in (smpa_*.pcm) do adpcm.exe "%%v" "%%v.wav"
|
||||||
|
for /r %%v in (smpb_*.pcm) do adpcmb.exe -d "%%v" "%%v.wav"
|
||||||
|
del "*.pcm"
|
||||||
|
mkdir "%~n1"
|
||||||
|
move "*.wav" "%~n1"
|
||||||
109
neoadpcmextract.cpp
Normal file
109
neoadpcmextract.cpp
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/* neoadpcmextract.cpp
|
||||||
|
Copyright (C) 2017 Nicholas Curtis
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
void DecodeSample ( std::ifstream& a_file, std::vector<uint8_t>& a_out )
|
||||||
|
{
|
||||||
|
// Set up output vector.
|
||||||
|
uint32_t sampLen = 0;
|
||||||
|
a_file.read ( (char*)&sampLen, sizeof(uint32_t) );
|
||||||
|
if ( sampLen < sizeof(uint64_t) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sampLen -= sizeof(uint64_t);
|
||||||
|
a_out.clear ();
|
||||||
|
a_out.resize ( sampLen );
|
||||||
|
|
||||||
|
// Ignore 8 bytes.
|
||||||
|
uint64_t dummy;
|
||||||
|
a_file.read ( (char*)&dummy, sizeof(uint64_t) );
|
||||||
|
|
||||||
|
// Read adpcm data.
|
||||||
|
a_file.read ( (char*)a_out.data (), sampLen );
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumpBytes ( std::string a_path, const std::vector<uint8_t>& a_bytes )
|
||||||
|
{
|
||||||
|
std::ofstream fileOut ( a_path, std::ios::binary );
|
||||||
|
fileOut.write ( (const char*)a_bytes.data (), a_bytes.size () );
|
||||||
|
fileOut.close ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main ( int argc, char** argv )
|
||||||
|
{
|
||||||
|
if ( argc != 2 )
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open file.
|
||||||
|
std::ifstream file ( argv[1], std::ios::binary );
|
||||||
|
if ( !file.is_open () )
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for pcm headers.
|
||||||
|
std::vector<uint8_t> smpBytes;
|
||||||
|
int smpA = 0, smpB = 0;
|
||||||
|
while ( !file.eof () && !file.fail () )
|
||||||
|
{
|
||||||
|
uint8_t byte;
|
||||||
|
|
||||||
|
file >> byte;
|
||||||
|
if ( byte == 0x67 )
|
||||||
|
{
|
||||||
|
file >> byte;
|
||||||
|
if ( byte == 0x66 )
|
||||||
|
{
|
||||||
|
file >> byte;
|
||||||
|
if ( byte == 0x82 )
|
||||||
|
{
|
||||||
|
std::cout << "ADPCM-A data found at 0x" << std::hex << file.tellg () << std::endl;
|
||||||
|
DecodeSample ( file, smpBytes );
|
||||||
|
std::stringstream path;
|
||||||
|
path << std::hex << "smpa_" << (smpA++) << ".pcm";
|
||||||
|
DumpBytes ( path.str (), smpBytes );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if ( byte == 0x83 )
|
||||||
|
{
|
||||||
|
std::cout << "ADPCM-B data found at 0x" << std::hex << file.tellg () << std::endl;
|
||||||
|
DecodeSample ( file, smpBytes );
|
||||||
|
std::stringstream path;
|
||||||
|
path << std::hex << "smpb_" << (smpB++) << ".pcm";
|
||||||
|
DumpBytes ( path.str (), smpBytes );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user