mirror of
https://github.com/OpenDriver2/REDRIVER2.git
synced 2024-11-25 11:52:32 +01:00
- remove dump_music as it moved to OpenDriver2Tools
This commit is contained in:
parent
c187a98658
commit
e92fb3db7f
@ -1,740 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
|
||||
// WAV file header and smpl-chunk template - Quick and dirty solution because I'm lazy
|
||||
int wavHeader[11] = {
|
||||
0x46464952, 0, 0x45564157, 0x20746D66,
|
||||
0x10, 0x10001, 0, 0,
|
||||
0x100002, 0x61746164, 0
|
||||
};
|
||||
|
||||
int smplChunk[17] = {
|
||||
0x6C706D73, 0x3C, 0, 0,
|
||||
0x1D316, 0x3C, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0
|
||||
};
|
||||
|
||||
// PSX ADPCM coefficients
|
||||
const double K0[5] = { 0, 0.9375, 1.796875, 1.53125, 1.90625 };
|
||||
const double K1[5] = { 0, 0, -0.8125, -0.859375, -0.9375 };
|
||||
|
||||
// PSX ADPCM decoding routine - decodes a single sample
|
||||
short vagToPcm(unsigned char soundParameter, int soundData, double* vagPrev1, double* vagPrev2)
|
||||
{
|
||||
int resultInt = 0;
|
||||
|
||||
double dTmp1 = 0.0;
|
||||
double dTmp2 = 0.0;
|
||||
double dTmp3 = 0.0;
|
||||
|
||||
if (soundData > 7)
|
||||
soundData -= 16;
|
||||
|
||||
dTmp1 = (double)soundData * pow(2, (double)(12 - (soundParameter & 0x0F)));
|
||||
|
||||
dTmp2 = (*vagPrev1) * K0[(soundParameter >> 4) & 0x0F];
|
||||
dTmp3 = (*vagPrev2) * K1[(soundParameter >> 4) & 0x0F];
|
||||
|
||||
(*vagPrev2) = (*vagPrev1);
|
||||
(*vagPrev1) = dTmp1 + dTmp2 + dTmp3;
|
||||
|
||||
resultInt = (int)round((*vagPrev1));
|
||||
|
||||
if (resultInt > 32767)
|
||||
resultInt = 32767;
|
||||
|
||||
if (resultInt < -32768)
|
||||
resultInt = -32768;
|
||||
|
||||
return (short)resultInt;
|
||||
}
|
||||
|
||||
// Main decoding routine - Takes PSX ADPCM formatted audio data and converts it to PCM. It also extracts the looping information if used.
|
||||
void decodeSound(unsigned char* iData, short* oData, int soundSize, int* loopStart, int* loopLength)
|
||||
{
|
||||
unsigned char sp = 0;
|
||||
int sd = 0;
|
||||
double vagPrev1 = 0.0;
|
||||
double vagPrev2 = 0.0;
|
||||
int k = 0;
|
||||
|
||||
for (int i = 0; i < soundSize; i++)
|
||||
{
|
||||
if (i % 16 == 0)
|
||||
{
|
||||
sp = iData[i];
|
||||
|
||||
if ((iData[i + 1] & 0x0E) == 6)
|
||||
(*loopStart) = k;
|
||||
|
||||
if ((iData[i + 1] & 0x0F) == 3 || (iData[i + 1] & 0x0F) == 7)
|
||||
(*loopLength) = (k + 28) - (*loopStart);
|
||||
|
||||
i += 2;
|
||||
}
|
||||
|
||||
sd = (int)iData[i] & 0x0F;
|
||||
oData[k++] = vagToPcm(sp, sd, &vagPrev1, &vagPrev2);
|
||||
sd = ((int)iData[i] >> 4) & 0x0F;
|
||||
oData[k++] = vagToPcm(sp, sd, &vagPrev1, &vagPrev2);
|
||||
}
|
||||
}
|
||||
|
||||
void XM_Sample2Delta(short *p, int len)
|
||||
{
|
||||
short news, olds;
|
||||
|
||||
news = 0;
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
olds = p[i];
|
||||
p[i] -= news;
|
||||
news = olds;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
#define XM_SONGS 8
|
||||
|
||||
#define XM_INSTR_HEADER_SIZE 263
|
||||
#define XM_MAX_CHANNELS 32
|
||||
|
||||
struct song_t
|
||||
{
|
||||
int xm_offset;
|
||||
int bank_offset;
|
||||
};
|
||||
|
||||
struct SAMPLE_DATA
|
||||
{
|
||||
unsigned long address;
|
||||
unsigned long length;
|
||||
unsigned long loop;
|
||||
unsigned long samplerate;
|
||||
};
|
||||
|
||||
struct PCMSample
|
||||
{
|
||||
short* data;
|
||||
int length;
|
||||
int loopStart;
|
||||
int loopLength;
|
||||
};
|
||||
|
||||
struct XM_Note
|
||||
{
|
||||
unsigned char note;
|
||||
unsigned char inst;
|
||||
unsigned char volc;
|
||||
unsigned char efft;
|
||||
unsigned char effp;
|
||||
};
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
struct XM_SampleHeader
|
||||
{
|
||||
int32_t len, repS, repL;
|
||||
uint8_t vol;
|
||||
int8_t fine;
|
||||
uint8_t typ, pan;
|
||||
int8_t relTon;
|
||||
uint8_t reserved;
|
||||
char name[22];
|
||||
};
|
||||
|
||||
struct XM_InstHeaeder
|
||||
{
|
||||
uint32_t instrSize;
|
||||
char name[22];
|
||||
uint8_t typ;
|
||||
int16_t antSamp;
|
||||
int32_t sampleSize;
|
||||
uint8_t ta[96];
|
||||
int16_t envVP[12][2], envPP[12][2];
|
||||
uint8_t envVPAnt, envPPAnt;
|
||||
uint8_t envVSust, envVRepS, envVRepE;
|
||||
uint8_t envPSust, envPRepS, envPRepE;
|
||||
uint8_t envVTyp, envPTyp;
|
||||
uint8_t vibTyp, vibSweep, vibDepth, vibRate;
|
||||
uint16_t fadeOut;
|
||||
uint8_t midiOn, midiChannel;
|
||||
int16_t midiProgram, midiBend;
|
||||
int8_t mute;
|
||||
uint8_t reserved[15];
|
||||
XM_SampleHeader samp[16];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
int DecompressAndRestoreXM(char* destXM, char* xmData, int srcSize, PCMSample* samples)
|
||||
{
|
||||
char* destOrig = destXM;
|
||||
char* srcOrig = xmData;
|
||||
|
||||
memcpy(destXM, xmData, 336);
|
||||
|
||||
unsigned short* version = (unsigned short*)(&destXM[58]);
|
||||
|
||||
// check if it's an XMPlay version (superpacked)
|
||||
if (*version != 0xDDBA)
|
||||
{
|
||||
memcpy(destXM, xmData, srcSize);
|
||||
return srcSize;
|
||||
}
|
||||
|
||||
printf("Decompressing XM...\n");
|
||||
|
||||
// convert XM to standard version
|
||||
*version = 0x104;
|
||||
|
||||
destXM += 336; // go to patterns
|
||||
xmData += 68;
|
||||
|
||||
short numChannels = *(short*)xmData; xmData += 2;
|
||||
short numPatterns = *(short*)xmData; xmData += 2;
|
||||
short numInstruments = *(short*)xmData; xmData += 264; // skip other header data since it's not changed
|
||||
|
||||
printf("channel count: %d\n", numChannels);
|
||||
|
||||
printf("Unpacking %d patterns\n", numPatterns);
|
||||
|
||||
XM_Note rowNotes[XM_MAX_CHANNELS]; // more for safety
|
||||
|
||||
for (int i = 0; i < numPatterns; i++)
|
||||
{
|
||||
xmData += 5;
|
||||
int pattLen = *(short*)xmData;
|
||||
xmData -= 5;
|
||||
|
||||
memcpy(destXM, xmData, 7); // copy pattern header properties
|
||||
destXM += 7;
|
||||
xmData += 7;
|
||||
|
||||
short patternSize = *(short*)xmData;
|
||||
xmData += sizeof(short); // now pattern data itself
|
||||
|
||||
short* unpackedPatternSize = (short*)destXM;
|
||||
destXM += sizeof(short);
|
||||
|
||||
// no empty reads
|
||||
if (patternSize == 0)
|
||||
continue;
|
||||
|
||||
char* pattStartSrc = xmData;
|
||||
char* pattStart = destXM;
|
||||
|
||||
for (int r = 0; r < pattLen; r++)
|
||||
{
|
||||
// zero full channel size double from current position
|
||||
memset(rowNotes, 0, sizeof(rowNotes));
|
||||
|
||||
while (1)
|
||||
{
|
||||
// don't overflow reading
|
||||
if ((xmData - pattStartSrc) >= patternSize)
|
||||
break;
|
||||
|
||||
unsigned char patdat = *xmData++;
|
||||
|
||||
if (patdat == 0xFF) // channel end
|
||||
break;
|
||||
|
||||
unsigned char data = 0;
|
||||
|
||||
XM_Note& xmnote = rowNotes[patdat];
|
||||
|
||||
// unpack it fully
|
||||
unsigned char note = *xmData++;
|
||||
if (note & 0x80)
|
||||
{
|
||||
data = 0; if (note & 0x01) data = *xmData++; xmnote.note = data;
|
||||
data = 0; if (note & 0x02) data = *xmData++; xmnote.inst = data;
|
||||
data = 0; if (note & 0x04) data = *xmData++; xmnote.volc = data;
|
||||
data = 0; if (note & 0x08) data = *xmData++; xmnote.efft = data;
|
||||
data = 0; if (note & 0x10) data = *xmData++; xmnote.effp = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
xmnote.note = note;
|
||||
xmnote.inst = *xmData++;
|
||||
xmnote.volc = *xmData++;
|
||||
xmnote.efft = *xmData++;
|
||||
xmnote.effp = *xmData++;
|
||||
}
|
||||
}
|
||||
|
||||
// pack notes again
|
||||
for (int c = 0; c < numChannels; c++)
|
||||
{
|
||||
XM_Note& xmnote = rowNotes[c];
|
||||
|
||||
if (xmnote.note > 0 &&
|
||||
xmnote.inst > 0 &&
|
||||
xmnote.volc > 0 &&
|
||||
xmnote.efft > 0 &&
|
||||
xmnote.effp > 0)
|
||||
{
|
||||
// write full note
|
||||
memcpy(destXM, &xmnote, sizeof(XM_Note));
|
||||
destXM += sizeof(XM_Note);
|
||||
}
|
||||
else
|
||||
{
|
||||
char* packedFlag = destXM++;
|
||||
|
||||
*packedFlag = 0x80;
|
||||
|
||||
if (xmnote.note > 0) { *destXM++ = xmnote.note; *packedFlag |= 0x01; }
|
||||
if (xmnote.inst > 0) { *destXM++ = xmnote.inst; *packedFlag |= 0x02; }
|
||||
if (xmnote.volc > 0) { *destXM++ = xmnote.volc; *packedFlag |= 0x04; }
|
||||
if (xmnote.efft > 0) { *destXM++ = xmnote.efft; *packedFlag |= 0x08; }
|
||||
if (xmnote.effp > 0) { *destXM++ = xmnote.effp; *packedFlag |= 0x10; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*unpackedPatternSize = destXM - pattStart;
|
||||
}
|
||||
|
||||
printf("instrument count: %d\n", numInstruments);
|
||||
|
||||
for (int i = 0; i < numInstruments; i++)
|
||||
{
|
||||
char* instStart = xmData;
|
||||
|
||||
XM_InstHeaeder* instr = (XM_InstHeaeder*)xmData;
|
||||
|
||||
{
|
||||
int readSize = instr->instrSize;
|
||||
if ((readSize < 4) || (readSize > XM_INSTR_HEADER_SIZE))
|
||||
readSize = XM_INSTR_HEADER_SIZE;
|
||||
|
||||
if (instr->instrSize > XM_INSTR_HEADER_SIZE)
|
||||
readSize += instr->instrSize - XM_INSTR_HEADER_SIZE;
|
||||
|
||||
printf("instr %d size: %d readSize: %d\n", i, instr->instrSize, readSize);
|
||||
|
||||
memcpy(destXM, xmData, readSize);
|
||||
|
||||
xmData += readSize;
|
||||
destXM += readSize;
|
||||
}
|
||||
|
||||
printf("instr name: %s\n", instr->name);
|
||||
printf("sample count: %d\n", instr->antSamp);
|
||||
|
||||
// since the XMPlay for PSX does not
|
||||
// support more than one samples, we don't bother...
|
||||
if (instr->antSamp > 0)
|
||||
{
|
||||
//if (i == 17)
|
||||
// printf("flash!\n");
|
||||
|
||||
printf("sample: %s typ %d\n", instr->samp[0].name, instr->samp[0].typ);
|
||||
|
||||
// samples are direct to the instrument number,
|
||||
// so we don't bother here too...
|
||||
PCMSample& sample = samples[i];
|
||||
|
||||
if ((instr->samp[0].typ & 0x16))
|
||||
{
|
||||
instr->samp[0].len = sample.length * sizeof(short);
|
||||
instr->samp[0].repS = sample.loopStart * sizeof(short);
|
||||
instr->samp[0].repL = sample.loopLength * sizeof(short);
|
||||
}
|
||||
|
||||
// write headers
|
||||
int readSize = instr->antSamp * sizeof(XM_SampleHeader);
|
||||
|
||||
memcpy(destXM, xmData, readSize);
|
||||
xmData += readSize;
|
||||
destXM += readSize;
|
||||
|
||||
if ((instr->samp[0].typ & 0x16))
|
||||
{
|
||||
// right after the instrument data comes the sample data
|
||||
// there is nothing to read, but there is something to write...
|
||||
XM_Sample2Delta(sample.data, sample.length);
|
||||
|
||||
memcpy(destXM, sample.data, sample.length * sizeof(short));
|
||||
destXM += sample.length * sizeof(short);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int remainingStart = (xmData - srcOrig);
|
||||
int remaining = srcSize - remainingStart;
|
||||
|
||||
// copy remaining data
|
||||
memcpy(destXM, xmData, remaining);
|
||||
destXM += remaining;
|
||||
|
||||
return destXM-destOrig;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int LoadSoundBank(SAMPLE_DATA* out_sample_info, PCMSample* out_samples, FILE* fp)
|
||||
{
|
||||
int numBankSamples = 0;
|
||||
fread(&numBankSamples, sizeof(int), 1, fp);
|
||||
|
||||
printf("bank sounds: %d\n", numBankSamples);
|
||||
|
||||
fread(out_sample_info, sizeof(SAMPLE_DATA), numBankSamples, fp);
|
||||
|
||||
int bankSamplesOffset = ftell(fp);
|
||||
|
||||
printf("bank sounds: %d\n", numBankSamples);
|
||||
|
||||
for (int j = 0; j < numBankSamples; j++)
|
||||
{
|
||||
SAMPLE_DATA& sample = out_sample_info[j];
|
||||
PCMSample& pcmSample = out_samples[j];
|
||||
|
||||
if (sample.loop == 0)
|
||||
sample.length -= 16;
|
||||
|
||||
if (sample.length == 0)
|
||||
continue;
|
||||
|
||||
// read VAG and convert to ADPCM
|
||||
{
|
||||
unsigned char* iData = (unsigned char*)malloc(sample.length);
|
||||
|
||||
pcmSample.length = (sample.length >> 4) * 28;
|
||||
pcmSample.data = new short[pcmSample.length];
|
||||
|
||||
fseek(fp, bankSamplesOffset + sample.address, SEEK_SET);
|
||||
fread(iData, sizeof(char), sample.length, fp); // Read the audio data
|
||||
|
||||
decodeSound(iData, pcmSample.data, sample.length, &pcmSample.loopStart, &pcmSample.loopLength);
|
||||
|
||||
free(iData);
|
||||
|
||||
printf("sample %d rate=%d loop=%d size=%d\n", j, sample.samplerate, sample.loop, pcmSample.length);
|
||||
}
|
||||
}
|
||||
|
||||
return numBankSamples;
|
||||
}
|
||||
|
||||
int DoConvertSBK(const char* sbkFileName)
|
||||
{
|
||||
char tmpString[_MAX_PATH];
|
||||
snprintf(tmpString, _MAX_PATH, "%s_dec", sbkFileName);
|
||||
|
||||
printf("Loading '%s'...\n", sbkFileName);
|
||||
|
||||
FILE* sbkFp = fopen(sbkFileName, "rb");
|
||||
|
||||
if (!sbkFp)
|
||||
{
|
||||
printf("No such file '%s'!", sbkFileName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
CreateDirectoryA(tmpString, NULL);
|
||||
|
||||
PCMSample pcmSamples[80];
|
||||
SAMPLE_DATA sampleDescs[80];
|
||||
memset(pcmSamples, 0, sizeof(PCMSample) * 80);
|
||||
memset(sampleDescs, 0, sizeof(SAMPLE_DATA) * 80);
|
||||
|
||||
int numBankSamples = LoadSoundBank(sampleDescs, pcmSamples, sbkFp);
|
||||
|
||||
for (int i = 0; i < numBankSamples; i++)
|
||||
{
|
||||
PCMSample& sample = pcmSamples[i];
|
||||
SAMPLE_DATA& sampleDesc = sampleDescs[i];
|
||||
|
||||
snprintf(tmpString, _MAX_PATH, "%s_dec\\%d.wav", sbkFileName, i);
|
||||
|
||||
FILE* wavfp = fopen(tmpString, "wb");
|
||||
|
||||
if (wavfp)
|
||||
{
|
||||
// Prepare the WAV file header
|
||||
wavHeader[1] = sample.length * sizeof(short) + 36; // Size of the "RIFF" chunk
|
||||
|
||||
if (sample.loopLength > 0)
|
||||
wavHeader[1] += 68;
|
||||
|
||||
wavHeader[6] = sampleDesc.samplerate; // Sampling rate
|
||||
wavHeader[7] = wavHeader[6] * sizeof(short); // Average bytes per second
|
||||
wavHeader[10] = sample.length * sizeof(short); // Size of the "data" chunk
|
||||
|
||||
// Write WAV file header, the converted audio data, and the loop positions if used
|
||||
fwrite(&wavHeader, sizeof(int), 11, wavfp);
|
||||
fwrite(sample.data, sizeof(short), sample.length, wavfp);
|
||||
if (sample.loopLength > 0)
|
||||
{
|
||||
smplChunk[13] = sample.loopStart * sizeof(short);
|
||||
smplChunk[14] = sample.loopStart * sizeof(short) + sample.loopLength * sizeof(short);
|
||||
fwrite(&smplChunk, sizeof(int), 17, wavfp);
|
||||
}
|
||||
|
||||
fclose(wavfp);
|
||||
}
|
||||
else
|
||||
printf("Unable to create file %s\n", tmpString);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DoConvertXMAndSBK(const char* xmFilename)
|
||||
{
|
||||
char tmpString[_MAX_PATH];
|
||||
char sbkFileName[_MAX_PATH];
|
||||
strcpy_s(sbkFileName, xmFilename);
|
||||
|
||||
char* extStr = strchr(sbkFileName, '.');
|
||||
if (extStr)
|
||||
strcpy(extStr, ".sbk");
|
||||
|
||||
FILE* psxXmFp = fopen(xmFilename, "rb");
|
||||
|
||||
if (!psxXmFp)
|
||||
{
|
||||
printf("No such file '%s'!", xmFilename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE* sbkFp = fopen(sbkFileName, "rb");
|
||||
|
||||
if (!sbkFp)
|
||||
{
|
||||
printf("No such file '%s'!", sbkFileName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Loading '%s' & '%s'...\n", xmFilename, sbkFileName);
|
||||
|
||||
PCMSample pcmSamples[80];
|
||||
SAMPLE_DATA sampleDescs[80];
|
||||
memset(pcmSamples, 0, sizeof(PCMSample) * 80);
|
||||
memset(sampleDescs, 0, sizeof(SAMPLE_DATA) * 80);
|
||||
|
||||
int numBankSamples = LoadSoundBank(sampleDescs, pcmSamples, sbkFp);
|
||||
|
||||
// restore XM and save to disk
|
||||
{
|
||||
*extStr = 0;
|
||||
|
||||
printf("--- XM song '%s' ---\n", sbkFileName);
|
||||
sprintf_s(tmpString, "%s_orig.xm", sbkFileName);
|
||||
|
||||
FILE* xmFp = fopen(tmpString, "wb");
|
||||
|
||||
if (xmFp)
|
||||
{
|
||||
fseek(psxXmFp, 0, SEEK_END);
|
||||
int songSize = ftell(psxXmFp);
|
||||
fseek(psxXmFp, 0, SEEK_SET);
|
||||
|
||||
// read the PSX XM
|
||||
char* xmData = (char*)malloc(songSize);
|
||||
fread(xmData, songSize, 1, psxXmFp);
|
||||
|
||||
fclose(psxXmFp);
|
||||
|
||||
// calculate new XM size according to samples
|
||||
int addSize = 0;
|
||||
|
||||
for (int j = 0; j < numBankSamples; j++)
|
||||
{
|
||||
//printf("sample %d rate=%d loop=%d size=%d\n", j, sample.samplerate, sample.loop, sample.length);
|
||||
addSize += pcmSamples[j].length * sizeof(short);
|
||||
}
|
||||
|
||||
int calculatedXMSize = songSize * 4 + addSize;
|
||||
|
||||
// decompress
|
||||
char* newXMData = (char*)malloc(calculatedXMSize); // the new size is pretty hardcoded setting
|
||||
|
||||
songSize = DecompressAndRestoreXM(newXMData, xmData, songSize, pcmSamples);
|
||||
|
||||
free(xmData);
|
||||
xmData = newXMData;
|
||||
|
||||
fwrite(xmData, 1, songSize, xmFp);
|
||||
fclose(xmFp);
|
||||
|
||||
free(xmData);
|
||||
}
|
||||
else
|
||||
printf("ERROR: can't open '%s' for write!", tmpString);
|
||||
}
|
||||
|
||||
// free samples
|
||||
for (int j = 0; j < numBankSamples; j++)
|
||||
{
|
||||
delete[] pcmSamples[j].data;
|
||||
pcmSamples[j].data = nullptr;
|
||||
}
|
||||
|
||||
// close handles
|
||||
fclose(sbkFp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DoExtractMusicFile(const char* fileName)
|
||||
{
|
||||
FILE* fp = fopen(fileName, "rb");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
printf("No such file '%s'!", fileName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Loading '%s'...\n", fileName);
|
||||
|
||||
//char songPath[_MAX_PATH];
|
||||
char tmpString[_MAX_PATH];
|
||||
|
||||
// max 80 samples per bank
|
||||
PCMSample pcmSamples[80];
|
||||
SAMPLE_DATA sampleDescs[80];
|
||||
song_t songs[XM_SONGS];
|
||||
int numBankSamples = 0;
|
||||
|
||||
// read song offsets
|
||||
fread(songs, sizeof(song_t), XM_SONGS, fp);
|
||||
|
||||
for (int i = 0; i < XM_SONGS; i++)
|
||||
{
|
||||
const song_t& offsets = songs[i];
|
||||
|
||||
int songSize = offsets.bank_offset - offsets.xm_offset;
|
||||
|
||||
printf("--- XM song %d at %d (size %d) ---\n", i, offsets.xm_offset, songSize);
|
||||
|
||||
// create folder for song
|
||||
//sprintf_s(songPath, "%s_song_%d", fileName, i);
|
||||
//CreateDirectoryA(songPath, NULL); // Create the sound bank directory
|
||||
|
||||
// Read XM and store to separate file
|
||||
fseek(fp, offsets.xm_offset, SEEK_SET);
|
||||
|
||||
char* xmData = (char*)malloc(songSize);
|
||||
fread(xmData, songSize, 1, fp);
|
||||
|
||||
// Read sound bank and then convert it using vabdecode
|
||||
fseek(fp, offsets.bank_offset, SEEK_SET);
|
||||
|
||||
memset(pcmSamples, 0, sizeof(PCMSample) * 80);
|
||||
memset(sampleDescs, 0, sizeof(SAMPLE_DATA) * 80);
|
||||
|
||||
numBankSamples = LoadSoundBank(sampleDescs, pcmSamples, fp);
|
||||
|
||||
// restore XM and save to disk
|
||||
{
|
||||
printf("--- XM song %d ---\n", i);
|
||||
sprintf_s(tmpString, "%s_song%d.xm", fileName, i);
|
||||
|
||||
FILE* xmFp = fopen(tmpString, "wb");
|
||||
|
||||
if (xmFp)
|
||||
{
|
||||
|
||||
// calculate new XM size according to samples
|
||||
int addSize = 0;
|
||||
|
||||
for (int j = 0; j < numBankSamples; j++)
|
||||
{
|
||||
//printf("sample %d rate=%d loop=%d size=%d\n", j, sample.samplerate, sample.loop, sample.length);
|
||||
addSize += pcmSamples[j].length * sizeof(short);
|
||||
}
|
||||
|
||||
int calculatedXMSize = songSize * 4 + addSize;
|
||||
|
||||
// decompress
|
||||
char* newXMData = (char*)malloc(calculatedXMSize); // the new size is pretty hardcoded setting
|
||||
|
||||
songSize = DecompressAndRestoreXM(newXMData, xmData, songSize, pcmSamples);
|
||||
|
||||
free(xmData);
|
||||
xmData = newXMData;
|
||||
|
||||
fwrite(xmData, 1, songSize, xmFp);
|
||||
fclose(xmFp);
|
||||
}
|
||||
else
|
||||
printf("ERROR: can't open '%s' for write!", tmpString);
|
||||
|
||||
free(xmData);
|
||||
}
|
||||
|
||||
// free samples
|
||||
for (int j = 0; j < numBankSamples; j++)
|
||||
{
|
||||
delete[] pcmSamples[j].data;
|
||||
pcmSamples[j].data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DoAssembleMusicFile(const char* folder)
|
||||
{
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc <= 1)
|
||||
{
|
||||
printf("usage:\n");
|
||||
printf("\tdump_music -bin2xm MUSIC.BIN\n");
|
||||
printf("\tdump_music -psx2xm FETUNE.XM\n");
|
||||
printf("\tdump_music -sbk2wav SOUNDS.SBK\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
if (!_stricmp(argv[i], "-bin2xm"))
|
||||
{
|
||||
if (i + 1 <= argc)
|
||||
DoExtractMusicFile(argv[i + 1]);
|
||||
else
|
||||
printf("-extract must have an argument!");
|
||||
}
|
||||
else if (!_stricmp(argv[i], "-psx2xm"))
|
||||
{
|
||||
if (i + 1 <= argc)
|
||||
DoConvertXMAndSBK(argv[i + 1]);
|
||||
else
|
||||
printf("-psx2xm must have an argument!");
|
||||
}
|
||||
else if (!_stricmp(argv[i], "-sbk2wav"))
|
||||
{
|
||||
if (i + 1 <= argc)
|
||||
DoConvertSBK(argv[i + 1]);
|
||||
else
|
||||
printf("-sbk2wav must have an argument!");
|
||||
}
|
||||
else if (!_stricmp(argv[i], "-a") || !_stricmp(argv[i], "-assemble"))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{E82851E6-2037-4D5A-9C8B-910DBCD09783}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>dumpmusic</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dump_music.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Исходные файлы">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Файлы заголовков">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Файлы ресурсов">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dump_music.cpp">
|
||||
<Filter>Исходные файлы</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user