64,676
社区成员
发帖
与我相关
我的任务
分享
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#pragma warning(disable:4996) /* _CRT_SECURE_NO_WARNINGS */
/*
* Each .wav file has got 4 types of block:
* . RIFF block
* . fmt block
* . fact block(optional)
* . data block
* and each start with the block IDs defined as follows:
*/
#define CHUNK_ID_RIFF "RIFF"
#define CHUNK_ID_FMT "fmt "
#define CHUNK_ID_FACT "fact"
#define CHUNK_ID_DATA "data"
#define RIFF_FMT_WAV "WAVE"
/*
* RIFF block.
*/
struct RIFF_HEADER
{
char szRiffID[4]; // 'R','I','F','F'
DWORD dwRiffSize;
char szRiffFormat[4]; // 'W','A','V','E'
};
struct WAVE_FORMAT
{
WORD wFormatTag;
WORD wChannels;
DWORD dwSamplesPerSec;
DWORD dwAvgBytesPerSec;
WORD wBlockAlign;
WORD wBitsPerSample;
};
/*
* Format block.
*/
struct FMT_BLOCK
{
char szFmtID[4]; // 'f','m','t',' '
DWORD dwFmtSize;
struct WAVE_FORMAT wavFormat;
};
/*
* fact block
*/
struct FACT_BLOCK
{
char szFactID[4]; // 'f','a','c','t'
DWORD dwFactSize;
char data[4];
};
/*
* data block
*/
struct DATA_BLOCK
{
char szDataID[4]; // 'd','a','t','a'
DWORD dwDataSize;
};
enum { OFMT_BIN, OFMT_CFILE };
static void usage(const char *progname);
static int wave_dump(const char *wavefile, const char *outfile, int outfmt, int dump_chs);
int main(int argc, char *argv[])
{
int outfmt = OFMT_CFILE; // output file format: default to 'OFMT_CFILE'
int dump_chs = 0; // defalut to disable dump data for each channel
int i;
#ifdef _DEBUG
argc = 3;
argv[1] = "sample.wav";
//argv[1] = "AlienStorm.wav";
//argv[2] = "-dc";
//argv[3] = "AlienStorm.c";
argv[2] = "sample.c";
//argv[3] = "sample.c";
//argv[3] = "-fb";
//argv[4] = "sample.bin";
//argv[4] = "AlienStorm.bin";
//argv[2] = "AlienStorm.bin";
#endif
if (argc < 3 || argc > 5) {
usage(argv[0]);
exit(EXIT_FAILURE);
}
/* parse parameters */
for (i = 2; i < argc - 1; i++)
{
if (_strnicmp(argv[i], "-f", 2) == 0) /* output file format */
{
switch (argv[i][2]) {
case 'b': case 'B': outfmt = OFMT_BIN; break;
case 'c': case 'C': outfmt = OFMT_CFILE; break;
default: usage(argv[0]); exit(EXIT_FAILURE); break;
}
}
else if (stricmp("-dc", argv[i]) == 0) /* check if user wants to dump data for each channel at the same time */
{
dump_chs = 1;
}
else
{
fprintf(stderr, "unknown option %s\n\n", argv[i]);
usage(argv[0]);
exit(EXIT_FAILURE);
}
}
/* dump wave data */
if (!wave_dump(argv[1], argv[argc - 1], outfmt, dump_chs))
return 1;
#ifdef _DEBUG
getch();
#endif
return 0;
}
static void usage(const char *progname)
{
fprintf(stderr,
"USAGE: %s wave-file [options] output-file\n"
"options:\n"
"-f<c,b>: output file format, \n"
" -fc means output a c file, it's default\n"
" -fb means output a binary file\n"
"-dc : dump data for each channel at the same time, default to disabled\n",
progname);
}
static int wave_dump(const char *wavefile, const char *outfile, int outfmt, int dump_chs)
{
#define BUF_UNIT_SZ 32 // must make sure: (BUF_UNIT_SZ % 16 == 0)
#ifdef _DEBUG
#define BUF_UNITS 1
#else
#define BUF_UNITS (8192 / BUF_UNIT_SZ)
#endif
#define BUF_SZ (BUF_UNIT_SZ * BUF_UNITS)
#define DUMP_UNITS_AT_LINE 16 // 16 bytes at each line when dumped with 'OFMT_CFILE'
FILE *istream, *ostream;
FILE *ostream_lc, *ostream_rc;
unsigned char buf[BUF_SZ];
unsigned char buf_lc[BUF_SZ / 2], buf_rc[BUF_SZ / 2];
size_t n;
char dn[_MAX_PATH];
char lcf[_MAX_PATH], rcf[_MAX_PATH];
unsigned int i, j;
struct RIFF_HEADER riffheader;
struct FMT_BLOCK fmtblk;
int hasfactblk = 0;
struct FACT_BLOCK factblk;
struct DATA_BLOCK datablk;
int ret = 1;
if (wavefile == NULL || outfile == NULL)
{
fprintf(stderr, "input or output file can't be NULL\n");
return 0;
}
if (outfmt != OFMT_CFILE && outfmt != OFMT_BIN)
{
fprintf(stderr, "output format must be 'OFMT_CFILE' or 'OFMT_BIN'\n");
return 0;
}
/* open wave file */
if ((istream = fopen(wavefile, "rb")) == NULL)
{
fprintf(stderr, "open file %s failed\n", wavefile);
return 0;
}
/* read the wave file header and parse them */
while (n = fread(buf, sizeof(char), sizeof(buf), istream))
{
if (strncmp(buf, CHUNK_ID_RIFF, strlen(CHUNK_ID_RIFF)) == 0) /* RIFF chunk */
{
fseek(istream, -(long)n, SEEK_CUR);
fread(&riffheader, sizeof(struct RIFF_HEADER), 1, istream);
if (strncmp(riffheader.szRiffFormat, RIFF_FMT_WAV, strlen(RIFF_FMT_WAV)) != 0)
{
fprintf(stderr, "file %s is not a RIFF format .wav file\n", wavefile);
ret = 0;
goto QUIT;
}
}
else if (strncmp(buf, CHUNK_ID_FMT, strlen(CHUNK_ID_FMT)) == 0) /* fmt chunk */
{
fseek(istream, -(long)n, SEEK_CUR);
fread(&fmtblk, sizeof(struct FMT_BLOCK), 1, istream);
if (fmtblk.wavFormat.wChannels == 1) dump_chs = 0;
//#ifdef _DEBUG
printf("%s: \n"
"FmtID : %c%c%c%c\n"
"FmtSize : %d bytes\n"
"FormatTag : %s\n"
"Channels : %s\n"
"SamplesPerSec : %f KHZ\n"
"AvgBytesPerSec: %ld\n"
"BlockAlign : %d\n"
"BitsPerSample : %d\n",
wavefile,
fmtblk.szFmtID[0], fmtblk.szFmtID[1], fmtblk.szFmtID[2], fmtblk.szFmtID[3],
fmtblk.dwFmtSize,
fmtblk.wavFormat.wFormatTag ? "PCM" : "ADPCM",
fmtblk.wavFormat.wChannels == 1 ? "MONO" : "STEREO",
(float)fmtblk.wavFormat.dwSamplesPerSec / 1000,
fmtblk.wavFormat.dwAvgBytesPerSec,
fmtblk.wavFormat.wBlockAlign,
fmtblk.wavFormat.wBitsPerSample);
/* check if we got a extra FMT_BLOCK information */
if (fmtblk.dwFmtSize > sizeof(struct FMT_BLOCK))
{
WORD wExtraInfo;
fread(&wExtraInfo, sizeof(WORD), 1, istream);
printf("ExtraInfo : %#06X\n\n", wExtraInfo);
}
else
{
printf("ExtraInfo : None\n\n");
}
//#endif
}
else if (strncmp(buf, CHUNK_ID_FACT, strlen(CHUNK_ID_FACT)) == 0) /* fact chunk */
{
hasfactblk = 1;
fseek(istream, -(long)n, SEEK_CUR);
fread(&factblk, sizeof(struct FACT_BLOCK), 1, istream);
}
else if (strncmp(buf, CHUNK_ID_DATA, strlen(CHUNK_ID_DATA)) == 0) /* data chunk */
{
fseek(istream, -(long)n, SEEK_CUR);
fread(&datablk, sizeof(struct DATA_BLOCK), 1, istream);
//#ifdef _DEBUG
printf("wave data size is %ld bytes\n\n", datablk.dwDataSize);
//#endif
break;
}
}
/* dump wave data stream to output file */
memset(dn, 0, sizeof(dn));
strncpy(dn, outfile, strchr(outfile, '.') - outfile);
/* make L,R channel output file name */
if (dump_chs)
{
strcpy(lcf, dn);
strcat(lcf, "_lc");
strcat(lcf, strchr(outfile, '.'));
strcpy(rcf, dn);
strcat(rcf, "_rc");
strcat(rcf, strchr(outfile, '.'));
}
if (outfmt == OFMT_CFILE)
{
ostream = fopen(outfile, "w");
fprintf(ostream, "const unsigned char %s[] = {\n", dn); /* write data header */
if (dump_chs)
{
/* L channel */
ostream_lc = fopen(lcf, "w");
fprintf(ostream_lc, "const unsigned char %s_lc[] = {\n", dn); /* write data header */
/* R channel */
ostream_rc = fopen(rcf, "w");
fprintf(ostream_rc, "const unsigned char %s_rc[] = {\n", dn); /* write data header */
}
}
else if (outfmt == OFMT_BIN)
{
ostream = fopen(outfile, "wb");
if (dump_chs)
{
ostream_lc = fopen(lcf, "wb");
ostream_rc = fopen(rcf, "wb");
}
}
while (n = fread(buf, sizeof(char), sizeof(buf), istream))
{
if (dump_chs) assert(n % 2 == 0);
if (outfmt == OFMT_CFILE)
{
for (i = 0; i < n/DUMP_UNITS_AT_LINE; i++)
{
fprintf(ostream, "\t");
if (dump_chs && i % 2 == 0)
{
fprintf(ostream_lc, "\t");
fprintf(ostream_rc, "\t");
}
for (j = 0; j < DUMP_UNITS_AT_LINE; j++)
{
fprintf(ostream, "0X%02X, ", (unsigned char)(buf[i * DUMP_UNITS_AT_LINE + j]));
if (dump_chs)
{
if (j % 2 == 0)
fprintf(ostream_lc, "0X%02X, ", (unsigned char)(buf[i * DUMP_UNITS_AT_LINE + j]));
else
fprintf(ostream_rc, "0X%02X, ", (unsigned char)(buf[i * DUMP_UNITS_AT_LINE + j]));
}
}
fprintf(ostream, "\n");
if (dump_chs && (i + 1) % 2 == 0)
{
fprintf(ostream_lc, "\n");
fprintf(ostream_rc, "\n");
}
}
if (n % DUMP_UNITS_AT_LINE)
{
fprintf(ostream, "\t");
for (j = 0; j < n % DUMP_UNITS_AT_LINE; j++)
{
fprintf(ostream, "0X%02X, ", (unsigned char)(buf[i * DUMP_UNITS_AT_LINE + j]));
if (dump_chs)
{
if (j % 2 == 0)
fprintf(ostream_lc, "0X%02X, ", (unsigned char)(buf[i * DUMP_UNITS_AT_LINE + j]));
else
fprintf(ostream_rc, "0X%02X, ", (unsigned char)(buf[i * DUMP_UNITS_AT_LINE + j]));
}
}
fprintf(ostream, "\n");
if (dump_chs)
{
fprintf(ostream_lc, "\n");
fprintf(ostream_rc, "\n");
}
}
}
else if (outfmt == OFMT_BIN)
{
if (fwrite(buf, sizeof(char), n, ostream) != n)
{
fprintf(stderr, "write file %s failed\n", outfile);
ret = 0;
goto QUIT;
}
if (dump_chs)
{
for (i = 0; i < n / 2; i++)
{
buf_lc[i] = buf[i * 2];
buf_rc[i] = buf[i * 2 + 1];
}
if (fwrite(buf_lc, sizeof(char), i, ostream_lc) != i)
{
fprintf(stderr, "write file %s failed\n", lcf);
ret = 0;
goto QUIT;
}
if (fwrite(buf_rc, sizeof(char), i, ostream_rc) != i)
{
fprintf(stderr, "write file %s failed\n", rcf);
ret = 0;
goto QUIT;
}
}
}
}
if (outfmt == OFMT_CFILE) fprintf(ostream, "};");
if (dump_chs) { fprintf(ostream_lc, "};"); fprintf(ostream_rc, "};"); }
QUIT:
fclose(istream);
fclose(ostream);
if (dump_chs)
{
fclose(ostream_lc);
fclose(ostream_rc);
}
return ret;
}