背景
工作需要转换WAV和PCM格式的音频。直接用audition软件另存为就可以把WAV的文件头去掉,但强烈的好奇心驱使下还是想弄清楚都有哪些信息,手动转换格式该怎么做。
RIFF格式
资源交换档案标准(Resource Interchange File Format) (RIFF) 是一种把资料储存在被标记的区块(tagged chunks)中的档案格式(meta-format):
WAVE文件
一个WAV文件通常有三个chunk以及一个可选chunk,其在文件中的排列方式依次是:RIFF chunk,Format chunk,Fact chunk(附加块,可选),Data chunk。
参考代码
/*
* @Descripttion: read wave file
* @version: 0.1.0
* @Author: PandaYoung
* @Date: 2023-01-06 16:10:58
*/
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#define LOG_DEBUG 1
#define ID_LENGTH 4
#define KILO 1000
typedef struct
{
char id[ID_LENGTH];
uint32_t size;
char type[ID_LENGTH];
} RIFF_CHUNK;
typedef struct
{
char id[ID_LENGTH];
uint32_t size;
uint16_t AudioFmt;
uint16_t NumChannel;
uint32_t SampleRate;
uint32_t ByteRate;
uint16_t BlockAlign;
uint16_t BitDepth;
} FORMAT_CHUNK;
typedef struct
{
char id[ID_LENGTH];
uint32_t size;
uint16_t info[0];
} FACT_CHUNK;
typedef struct
{
char id[ID_LENGTH];
uint32_t size;
uint16_t data[0];
} DATA_CHUNK;
typedef struct
{
RIFF_CHUNK riff_chunk;
FORMAT_CHUNK format_chunk;
FACT_CHUNK fact_chunk;
DATA_CHUNK data_chunk;
} WAV;
void print_param(int argc, char *argv[])
{
#if LOG_DEBUG
printf("argument count: %d\n", argc);
for (int i = 0; i < argc; i++)
{
printf("argument value[%d]: %s\n", i, argv[i]);
}
#endif
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("No file!\n");
return -1;
}
print_param(argc, argv);
if (access(argv[1], R_OK))
{
perror("ERROR: ");
return -2;
}
FILE *fp;
fp = fopen(argv[1], "rb");
if (fp ==NULL)
{
perror("ERROR: ");
return -3;
}
WAV wav = {0};
RIFF_CHUNK *riff_chunk = &wav.riff_chunk;
FORMAT_CHUNK *format_chunk = &wav.format_chunk;
FACT_CHUNK *fact_chunk = &wav.fact_chunk;
DATA_CHUNK *data_chunk = &wav.data_chunk;
fread(&wav, sizeof(RIFF_CHUNK) + sizeof(FORMAT_CHUNK) + ID_LENGTH, 1, fp);
printf("ID:\t\t%c%c%c%c\n", riff_chunk->id[0], riff_chunk->id[1], riff_chunk->id[2], riff_chunk->id[3]);
printf("size:\t\t%d Bytes\n", riff_chunk->size);
printf("type:\t\t%c%c%c%c\n\n", riff_chunk->type[0], riff_chunk->type[1], riff_chunk->type[2], riff_chunk->type[3]);
printf("ID:\t\t%c%c%c%c\n", format_chunk->id[0], format_chunk->id[1], format_chunk->id[2], format_chunk->id[3]);
printf("size:\t\t%d Bytes\n", format_chunk->size);
printf("AudioFormat:\t%d\n", format_chunk->AudioFmt);
printf("NumberChannel:\t%d\n", format_chunk->NumChannel);
printf("SampleRate:\t%.1f kHz\n", (float)format_chunk->SampleRate/KILO);
printf("ByteRate:\t%d\n", format_chunk->ByteRate);
printf("BlockAlign:\t%d\n", format_chunk->BlockAlign);
printf("BitDepth:\t%d\n\n", format_chunk->BitDepth);
if (strcmp(wav.fact_chunk.id, "data"))
{
fread(&wav.fact_chunk.size, sizeof(uint32_t), 1, fp);
fseek(fp, wav.fact_chunk.size, SEEK_CUR);
printf("ID:\t\t%c%c%c%c\n", fact_chunk->id[0], fact_chunk->id[1], fact_chunk->id[2], fact_chunk->id[3]);
printf("size:\t\t%d Bytes\n\n", fact_chunk->size);
}
fread(&wav.data_chunk, sizeof(DATA_CHUNK), 1, fp);
printf("ID:\t\t%c%c%c%c\n", data_chunk->id[0], data_chunk->id[1], data_chunk->id[2], data_chunk->id[3]);
printf("size:\t\t%d Bytes\n", data_chunk->size);
fclose(fp);
return 0;
}