> 文档中心 > VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例

VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例

VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例

  • 前言
  • 一. 工程实现
  • 二. 生成编译
  • 三. 小结

前言

语音识别相关算法一般在MATLAB上进行仿真验证与实验,在工程上一般还是在VS中进行实现落地,本系列将介绍语音信号处理在C语言中的一系列应用,后期将以此为基础,再落地移植到嵌入式平台。

今天介绍WAV格式语音存为PCM格式语音的工程应用。两种格式语音的唯一区别在于WAV语音包含文件头信息,而PCM格式语音仅包含语音数据流。语音格式转换也算是一种比较常见的应用,可以让我们更好的理解语音文件的格式信息。

一. 工程实现

打开VS2015
VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例
点击新建一个项目(工程),输入项目名:Wav2pcm
VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例
点击“确定”,创建项目
VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例
左侧解决方案资源管理器视图中,源文件栏右键添加新建项,
VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例
点击C++文件,新建一个源文件Wav2pcm.cpp,点击“添加”
VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例
输入代码如下:

// Wav2pcm.cpp// wav格式语音文件转存为pcm格式语音// date:2022-5-9 22:32:21// author : C.S#include   #include   #include #pragma warning (disable :4996)#define  uint32_tunsigned int  #define  uint16_tunsigned short   typedef struct _riff_t {char riff[4];/* "RIFF" (ASCII characters) */uint32_t len;/* Length of package (binary, little endian) */char wave[4];/* "WAVE" (ASCII characters) */} riff_t;/* The FORMAT chunk */typedef struct _format_t {char  fmt[4];/* "fmt_" (ASCII characters) */uint32_t   len;/* length of FORMAT chunk (always 0x10) */uint16_t  type;/* codec type*/uint16_t channel;/* Channel numbers (0x01 = mono, 0x02 = stereo) */uint32_t   rate;/* Sample rate (binary, in Hz) */uint32_t   bps;/* Average Bytes Per Second */uint16_t blockalign;/*number of bytes per sample */uint16_t bitpspl;/* bits per sample */} format_t;typedef struct _data_t {char data[4];   /* "data" (ASCII characters) */uint32_t len;  /* length of data */}data_t;typedef struct _wav_head{riff_t riff;format_t format;data_t   data;}wav_head;int main(int argc, char **argv){char *src_file = "test.wav";uint32_t pcm_data_size = 0;int pcm_channel = 0;int pcm_samplerate = 0;//以下是为了建立.wav头而准备的变量    wav_head header;FILE   *fp = NULL, *fpCpy = NULL;int flen;if ((fp = fopen(src_file, "rb")) == NULL) //读取文件    {printf("open wav file %s error\n", argv[1]);return -1;}if ((flen = fread(&header.riff.riff, 1, 4, fp)) != 4)goto error;if (memcmp(&header.riff.riff, "RIFF", 4))goto error;if ((flen = fread(&header.riff.len, 1, 4, fp)) != 4)goto error;if ((flen = fread(&header.riff.wave, 1, 4, fp)) != 4)goto error;if (memcmp(&header.riff.wave, "WAVE", 4))goto error;if ((flen = fread(&header.format.fmt, 1, 4, fp)) != 4)goto error;if (memcmp(&header.format.fmt, "fmt ", 4))goto error;if ((flen = fread(&header.format.len, 1, 4, fp)) != 4){goto error;}if (header.format.len != 0x10){printf("header.format.len!=0x10 :value:%d\n", header.format.len);}if ((flen = fread(&header.format.type, 1, 2, fp)) != 2){goto error;}if (header.format.type != 0x1){printf("header.format.type != 0x1 :value:%d\n", header.format.type);}if ((flen = fread(&header.format.channel, 1, 2, fp)) != 2){goto error;}pcm_channel = header.format.channel;if ((flen = fread(&header.format.rate, 1, 4, fp)) != 4){goto error;}pcm_samplerate = header.format.rate;if ((flen = fread(&header.format.bps, 1, 4, fp)) != 4){goto error;}if ((flen = fread(&header.format.blockalign, 1, 2, fp)) != 2){goto error;}if ((flen = fread(&header.format.bitpspl, 1, 2, fp)) != 2){goto error;}int p = 0;//后面的结构可能不是直接为“data”do {if ((flen = fread(&header.data.data, 1, 4, fp)) != 4){goto error;}if (memcmp(&header.data.data, "data", 4) == 0){printf("find data chunk.");if ((flen = fread(&header.data.len, 1, 4, fp)) != 4){goto error;}pcm_data_size = header.data.len;break;}elsep += 4;} while (!feof(fp));printf("解析成功,二段PCM数据长度分别为:%d, %d\n", pcm_data_size, header.riff.len - 36);int otherdataSize = header.riff.len - 36 - pcm_data_size;if (otherdataSize>0){printf("多余的数据部分大小:%d , %d", p, otherdataSize);char *otherdata = (char *)malloc(otherdataSize + 1);memset(otherdata, 0, otherdataSize + 1);fseek(fp, -otherdataSize - 8, SEEK_CUR);fread(otherdata, 1, otherdataSize, fp);*(otherdata + otherdataSize) = '\0';fseek(fp, 8, SEEK_CUR);printf("   other data:%s", otherdata);}fseek(fp, otherdataSize + 44, SEEK_SET);//fseek(fp, 0, SEEK_CUR);unsigned char *buffer = (unsigned char*)malloc((pcm_data_size) * sizeof(char));memset(buffer, 0, pcm_data_size);int count1 = fread(buffer, 1, pcm_data_size, fp);char output[1024] = { 0 };sprintf(output, "%d_%d_.pcm", pcm_samplerate, pcm_channel);if ((fpCpy = fopen(output, "wb+"))){//fwrite(buffer, 1, sizeof(buffer), fpCpy);  写了段常犯错的代码fwrite(buffer, 1, pcm_data_size, fpCpy);}elsegoto error;free(buffer);fclose(fp); //关闭文件    fclose(fpCpy);   //关闭文件    return 0;error:if (fp){fclose(fp);}if (fpCpy){fclose(fpCpy);}return -1;}

二. 生成编译

点击目录栏“生成”中“生成解决方案”
VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例
生成成功!找一个WAV格式语音,命名为test.wav,放在Wav2pcm.cpp同目录下,点击调试运行,生成一个48000_2_.pcm文件,调用成功。
VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例
VS语音信号处理(4) C语言WAV格式语音存为PCM格式语音工程实例

三. 小结

最近项目上需要对语音信号进行处理,这个是对语音格式进行转换的工程,可以正常跑通,相对也比较简单,值得注意的是,如果没有将test.wav导入的话,工程不会报警提示,所以有需要的同学在应用的时候需要注意一下,没有源语音是得不到pcm语音的。