vag是dvd音频格式,lumines中使用的略有不同,不分512块的左右声道,而是左右各一个文件。单个声道内连续存放数据块。
修改后可以解为wav.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
![](/Images/OutliningIndicators/None.gif)
struct VAGState
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
VAGState()
{ Reset(); }
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
void Reset()
{ s[0] = s[1] = 0; }
double s[2];
};
![](/Images/OutliningIndicators/None.gif)
void DecodeVAGBlock(const unsigned char in[16], short out[28], VAGState* state);
![](/Images/OutliningIndicators/None.gif)
const double filter[5][2] =
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 0.0, 0.0 },
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 60.0 / 64.0, 0.0 },
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 115.0 / 64.0, -52.0 / 64.0 },
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 98.0 / 64.0, -55.0 / 64.0 },
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ 122.0 / 64.0, -60.0 / 64.0 }
};
![](/Images/OutliningIndicators/None.gif)
const unsigned char wavhdr[44] =
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
'R','I','F','F',
0,0,0,0, // length of file - 8
'W','A','V','E',
'f','m','t',' ',
0x10,0,0,0,
1,0,2,0,
0,0,0,0, // sample rate
0,0xF4,1,0,
4,0,0x10,0,
'd','a','t','a',
0,0,0,0, // length of file - 0x2C
};
![](/Images/OutliningIndicators/None.gif)
int main(int argc, char *argv[])
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
int rate = 32000;
argc--;
argv++;
while (argc && (argv[0][0] == '-'))
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
char parm = argv[0][1];
if (parm == 'r')
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (argv[0][2])
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
rate = atoi(argv[0] + 2);
}
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
argc--;
argv++;
rate = atoi(argv[0]);
}
printf("Sample rate : %d\n", rate);
}
argc--;
argv++;
}
char src[256];
char dst[256];
if (argc == 1)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
sprintf(src, "%s", argv[0]);
sprintf(dst, "%s.WAV", argv[0]);
}
else if (argc == 2)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
strcpy(src, argv[0]);
strcpy(dst, argv[1]);
}
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
printf("Usage: Decode [-r ] | []\n");
return -1;
}
FILE* vag = fopen(src, "rb");
if (!vag)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
printf("Can't open source file %s\n", src);
return -1;
}
// find number of blocks
fseek(vag, 0, SEEK_END);
int length = (ftell(vag) - 0x40) / 16;
fseek(vag, 0x0c, SEEK_SET);
unsigned char buf[8];
fread(buf, 2, sizeof(unsigned long), vag);
length = ((unsigned int)buf[0]<<24) + ((unsigned int)buf[1]<<16) + ((unsigned int)buf[2]<<8) + (unsigned int)buf[3];
length -= 0x20;
rate = ((unsigned int)buf[4]<<24) + ((unsigned int)buf[5]<<16) + ((unsigned int)buf[6]<<8) + (unsigned int)buf[7];
rate/=2;
fseek(vag, 0x20, SEEK_SET);
fread(dst, 0x20, 1, vag);
fseek(vag, 0x40, SEEK_SET);
const int size = 1;
![](/Images/OutliningIndicators/InBlock.gif)
//length /= size*2;
FILE* wav = fopen(dst, "wb");
if (!wav)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
printf("Can't open destination file %s\n", dst);
return -1;
}
printf("Length : %d blocks\n", length);
unsigned char hdr[44];
int* ihdr = (int*)hdr;
memcpy(hdr, wavhdr, 44);
ihdr[1] = length * 28 * size * 2 + 0x24;
ihdr[10] = length * 28 * size * 2;
ihdr[6] = rate;
fwrite(hdr, 1, 44, wav);
VAGState st[2];
unsigned char bl[size * 16];
short out[size * 28 * 2];
extern int vag_depack(unsigned char *entree, unsigned char *sortie );
for (int blk = 0; blk < length; blk+=16)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
short obuf[28];
fread(bl, 16, 1, vag);
int flags = (bl[1] >> 4 ) & 0x0f;
if (flags == 7)
break;
if (flags ==3)
break;
if (flags ==4)
break;
if (flags ==6)
break;
DecodeVAGBlock(bl, obuf, &st[0]);
fwrite(obuf, 2, 28, wav);
}
fclose(wav);
fclose(vag);
return 0;
}
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
int highnibble(int a)
{ return (a >> 4) & 15; }
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
int lownibble(int a)
{ return a & 15; }
![](/Images/OutliningIndicators/None.gif)
short quantize(double sample)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
int a = int(sample + 0.5);
if (a < -32768) return -32768;
if (a > 32767) return 32767;
return short(a);
}
![](/Images/OutliningIndicators/None.gif)
void DecodeVAGBlock(const unsigned char in[16], short out[28], VAGState* state)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
double s[2];
s[0] = state->s[0];
s[1] = state->s[1];
int predictor = highnibble(in[0]);
int shift = lownibble(in[0]);
int flags = in[1];
if (predictor > 4)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// this should never happen in a valid VAG block
printf("Predictor %d!\n", predictor);
predictor = 0;
}
int ii;
for (ii = 0; ii < 14; ii++)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
int byte = in[ii + 2];
out[ii * 2] = short(lownibble(byte) << 12) >> shift;
out[ii * 2 + 1] = short(highnibble(byte) << 12) >> shift;
}
for (ii = 0; ii < 28; ii++)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
double filt = out[ii] + s[0] * filter[predictor][0] + s[1] * filter[predictor][1];
s[1] = s[0];
s[0] = filt;
out[ii] = quantize(filt);
}
state->s[0] = s[0];
state->s[1] = s[1];
}
![](/Images/OutliningIndicators/None.gif)