1
0
mirror of https://github.com/ScrelliCopter/VGM-Tools synced 2025-02-21 04:09:25 +11:00

Initial commit.

This commit is contained in:
2018-06-14 12:29:59 +10:00
commit 48dcc09399
9 changed files with 870 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
*.exe
*.vgm
*.vgz
*.log
*.pcm
*.wav

32
README.md Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}