utils.h
#ifndef _EXTRACTDATA_H_
#define _EXTRACTDATA_H_
#include <stdint.h>
typedef struct tagWAVHEADER {
uint8_t ChunkID[4]; // 文档标识。 大写字符串"RIFF",标明该文件为有效的 RIFF 格式文档。
uint32_t ChunkSize; // 文件数据长度。 从下一个字段首地址开始到文件末尾的总字节数。该字段的数值加 8 为当前文件的实际长度。
uint8_t Format[4]; // 文件格式类型。 所有 WAV 格式的文件此处为字符串"WAVE",标明该文件是 WAV 格式文件。
uint8_t FmtChunkID[4]; // 格式块标识。 小写字符串,"fmt "。
uint32_t FmtChunkSize; // 格式块长度。 其数值不确定,取决于编码格式。可以是 16、 18 、20、40 等。
uint16_t AudioFormat; // 编码格式代码。 常见的 WAV 文件使用 PCM 脉冲编码调制格式,该数值通常为 1。
uint16_t NumChannels; // 声道个数。 单声道为 1,立体声或双声道为 2。
uint32_t SampleRate; // 采样频率。 每个声道单位时间采样次数。常用的采样频率有 11025, 22050 和 44100 kHz。
uint32_t ByteRate; // 数据传输速率。 该数值为:声道数×采样频率×每样本的数据位数/8。播放软件利用此值可以估计缓冲区的大小。
uint16_t BlockAlign; // 数据块对齐单位。 采样帧大小。该数值为:声道数×位数/8。播放软件需要一次处理多个该值大小的字节数据,用该数值调整缓冲区。
uint16_t BitsPerSample; // 采样位数。 存储每个采样值所用的二进制数位数。常见的位数有 4、8、12、16、24、32。
uint8_t DataChunkID[4];
uint32_t DataChunkSize;
} WAVHEADER;
void showWavHead(WAVHEADER Header);
#endif // #ifndef _EXTRACTDATA_H_
utils.cpp
#include <stdio.h>
#include "utils.h"
void showWavHead(WAVHEADER Header) {
printf("ChunkID: %c%c%c%c\t", Header.ChunkID[0], Header.ChunkID[1], Header.ChunkID[2], Header.ChunkID[3]);
printf("ChunkSize: %u\t", Header.ChunkSize);
printf("Format: %c%c%c%c\n", Header.Format[0], Header.Format[1], Header.Format[2], Header.Format[3]);
printf("FmtChunkID: %c%c%c%c\t", Header.FmtChunkID[0], Header.FmtChunkID[1], Header.FmtChunkID[2], Header.FmtChunkID[3]);
printf("FmtChunkSize: %u\t", Header.FmtChunkSize);
printf("AudioFormat: %d\t", Header.AudioFormat);
printf("NumChannels: %d\t", Header.NumChannels);
printf("SampleRate: %u\t", Header.SampleRate);
printf("ByteRate: %u\t", Header.ByteRate);
printf("BlockAlign: %d\t", Header.BlockAlign);
printf("BitsPerSample: %d\n", Header.BitsPerSample);
printf("DataChunkID: %c%c%c%c\t", Header.DataChunkID[0], Header.DataChunkID[1], Header.DataChunkID[2], Header.DataChunkID[3]);
printf("DataChunkSize: %u\n", Header.DataChunkSize);
}
main.cpp
#include <iostream>
#include <math.h>
#include "main.h"
#include "utils.h"
using namespace std;
#define W 128 //每次读写文件的数据量
int FileSet = 0; //定义一个整型变量, 用于保存fseek函数的返回值
int FileEnd = 0; //整个文件的字节数
int FileLength = 0; //文件的数据长度。(注:每2个字节作为一个数据 )
short InputData[W]; //文件读写数据缓冲区
WAVHEADER FileHeader; //存文件头的结构体
int main() {
// 保存raw数据
FILE *outfile;
int wave_index = 1;
char dst_wave_path[256] = { 0 };
sprintf(dst_wave_path, "test_%d.raw", wave_index);
if ((outfile = fopen(dst_wave_path, "wb+")) == NULL) {
return -1;
}
// 待解析wav文件和保存为txt文件
FILE *Ifp, *txt; //定义文件读写指针
Ifp = fopen("p1.wav", "rb"); /*以只读方式打开wav文件*/
txt = fopen("p1.txt", "w");
/* 获得文件字节数,fseek函数将文件内部指针指向文件末尾,
ftell函数获取文件内部指针相对于文件头的偏移量,rewind函数将文件内部指针指向文件头 */
fseek(Ifp, 0L, SEEK_END);
FileEnd = ftell(Ifp);
printf("total file size: %d bytes \n", FileEnd);
rewind(Ifp);
// 读取文件头,并打印部分信息,wav格式的文件头一般是44个字节,后面是音频数据
fread(&FileHeader, 1, sizeof(WAVHEADER), Ifp);
showWavHead(FileHeader);
// 读取数据。这里的数据大小是2字节,按照实际格式改。while循环每次读写 W 个数据量,for循环写最后剩余的
FileLength = FileHeader.DataChunkSize / 2;
while (FileLength >= W) {
fread(InputData, sizeof(short), W, Ifp);
for (int i = 0; i < W; i++) {
fprintf(txt, "%d\n", InputData[i]);
}
fwrite(&InputData, sizeof(char), W * 2, outfile);
FileLength -= W;
}
fread(InputData, sizeof(short), FileLength, Ifp);
for (int i = 0; i < FileLength; i++) {
fprintf(txt, "%d\n", InputData[i]);
}
fwrite(&InputData, sizeof(char), FileLength * 2, outfile);
fclose(outfile);
return 0;
}