语音知识回顾和总结-----读取语音之c语言版本

来源:互联网 发布:rs485网络接口引脚图 编辑:程序博客网 时间:2024/06/01 18:41

         一开始,先煽情下。(呵呵……)明天就是教师节了,在这里祝愿所有的老师们身体健康,工作顺利。或许若干年后,我也可以过这个节日。

ok,回归正题,接着昨晚的继续说。

        昨晚说到matlab读取语音,感觉一个很简单的读取语音是不是给我说复杂了。希望大家给予批评和指正。接下来,就真正的进入主题了,希望大家可以学到想学的。

c语言读取语音就没matlab那么简单了。读取wav文件,主要是读取里面存储的数据。一些具体的就不说了。 WAVE文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF WAVE Chunk, Format Chunk, Fact Chunk(可选), Data Chunk。具体见下图:

------------------------------------------------
|            
RIFF WAVE Chunk                  |
|             ID  = 'RIFF'                     |
|             RiffType = 'WAVE'                |
------------------------------------------------
|             Format Chunk                     |
|             ID = 'fmt '                      |
------------------------------------------------
|             Fact Chunk(optional)             |
|             ID = 'fact'                      |
------------------------------------------------
|             Data Chunk                       |
|             ID = 'data'                      |
------------------------------------------------
            1   Wav格式包含Chunk示例

    其中除了Fact Chunk外,其他三个Chunk是必须的。每个Chunk有各自的ID,位于Chunk最开始位置,作为标示,而且均为4个字节。并且紧跟在ID后面的是Chunk大小(去除IDSize所占的字节数后剩下的其他字节数目),4个字节表示,低字节表示数值低位,高字节表示数值高位。下面具体介绍各个Chunk内容。
PS
:所有数值表示均为低字节表示低位,高字节表示高位。

其中每个部分也有具体的组成:

RIFF WAVE Chunk
   
==================================
    |       |所占字节数具体内容   |
    ==================================
    | ID    |  4 Bytes |   'RIFF'    |
    ----------------------------------
    | Size  |  4 Bytes |             |
    ----------------------------------
    | Type  |  4 Bytes |   'WAVE'    |
    ----------------------------------
            RIFF WAVE Chunk

Format Chunk
   
====================================================================
    |               |   字节数 |              具体内容               |
    ====================================================================
    | ID            |  4 Bytes  |   'fmt '                             |
    --------------------------------------------------------------------
    | Size          |  4 Bytes  | 数值为161818则最后又附加信息    |
    --------------------------------------------------------------------  ----
    | FormatTag     |  2 Bytes  | 编码方式,一般为0x0001              |     |
    --------------------------------------------------------------------     |
    | Channels      |  2 Bytes  | 声道数目,1--单声道;2--双声道      |     |
    --------------------------------------------------------------------     |
    | SamplesPerSec |  4 Bytes  | 采样频率                            |     |
    --------------------------------------------------------------------     |
    | AvgBytesPerSec|  4 Bytes  | 每秒所需字节数                      |     |===> WAVE_FORMAT
    --------------------------------------------------------------------     |
    | BlockAlign    |  2 Bytes  | 数据块对齐单位(每个采样需要的字节数) |    |
    --------------------------------------------------------------------     |
    | BitsPerSample |  2 Bytes  | 每个采样需要的bit                 |     |
    --------------------------------------------------------------------     |
    |               |  2 Bytes  | 附加信息(可选,通过Size来判断有无)|     |
    --------------------------------------------------------------------  ----
                            Format Chunk

Fact Chunk
   
==================================
    |       |所占字节数具体内容   |
    ==================================
    | ID    |  4 Bytes |   'fact'    |
    ----------------------------------
    | Size  |  4 Bytes |   数值为4  |
    ----------------------------------
    | data  |  4 Bytes |             |
    ----------------------------------
            Fact Chunk

Data Chunk
    ==================================
    |       |所占字节数具体内容   |
    ==================================
    | ID    |  4 Bytes |   'data'    |
    ----------------------------------
    | Size  |  4 Bytes |             |
    ----------------------------------
    | data  |          |             |
    ----------------------------------
             5 Data Chunk

不知道你看懂这些图没?也许你只要知道个大概就可以。最重要的到来了,下面的大家记住的哦!!!

文件头长度加起来是44个字节(用UltraEdit打开一个WAVE文件,数一下就知道了)。如果用以个结构体来定义WAVE文件头应该为:
struct WAVEFILEHEADER
{
 
char chRIFF[4];
 DWORD dwRIFFLen;
 char chWAVE[4];
 char chFMT[4];
 DWORD dwFMTLen;
 PCMWAVEFORMAT pwf;
 char chDATA[4];
 DWORD dwDATALen;
};

最后贴出c语言实现的代码。代码只是实现了这个功能,不是很规范。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
// Microsoft wav pcm sound file format. Normal 44 bytes header
typedef struct _tagMsWavPcmHeader44{
unsigned char ChunkID[4]; // "RIFF"; The "RIFF" the mainchunk;
unsigned long ChunkSize; // FileSize - 8; The size following this data
unsigned char Format[4]; // "WAVE"; The "WAVE" format consists of two subchunks: "fmt " and "data"
unsigned char SubChunk1ID[4]; // "fmt "
unsigned long SubChunk1Size; // 16 for PCM. This is the size of the rest of the subchunk which follows this data.
unsigned short AudioFormat; // 1 for PCM. Linear quantization
unsigned short NumChannels; // 1->Mono, 2->stereo, etc..
unsigned long SampleRate; // 8000, 11025, 16000, 44100, 48000, etc..
unsigned long ByteRate; // = SampleRate * NumChannels * BitsPerSample/8
unsigned short BlockAlign; // = NumChannels * BitsPerSample / 8
unsigned short BitsPerSample; // 8->8bits, 16->16bits, etc..
unsigned char SubChunk2ID[4]; // "data"
unsigned long SubChun2Size; // = NumSamples * NumChannels * BitsPerSample / 8. The size of data
} wav_pcm_header44;


void wave_generator(FILE *fpwav, wav_pcm_header44 *phwav);

void main(int argc, char **argv)
{
  FILE *fpWav=NULL;
  FILE *fp;
  unsigned long size;
  short *wav_data;
  unsigned int i;
  wav_pcm_header44 hwav;
/*
* 1. Get wave header information demo
*/
  fpWav = fopen("back.wav", "rb");
  if (fpWav)
  {
    fread(&hwav, sizeof(wav_pcm_header44), 1, fpWav);
    /* Check wave header */
   if ( (0==memcmp(hwav.ChunkID, "RIFF", 4)) &&
      (0==memcmp(hwav.Format, "WAVE", 4)) &&
      (0==memcmp(hwav.SubChunk1ID, "fmt ", 4)) &&
      (0==memcmp(hwav.SubChunk2ID, "data", 4)) &&
      (1==hwav.AudioFormat))
   {
    printf("Wave audio data format:\n");
    printf("Channel number: %d\n", hwav.NumChannels);
    printf("SampleRate: %dHz\n", hwav.SampleRate);
    printf("BitsPerSample: %dbits\n", hwav.BitsPerSample);
    printf("Audio data size:%d\n", hwav.SubChun2Size*8/hwav.BitsPerSample);
   }

 fseek(fpWav,0,SEEK_END);
 wav_data=(short*)malloc(sizeof(short)*hwav.SubChun2Size*8/hwav.BitsPerSample);
 fseek(fpWav,44,SEEK_SET);
 fread(wav_data,2,hwav.SubChun2Size*8/hwav.BitsPerSample,fpWav);
 fp=fopen("shujupiano2.txt","w");
 for (i=0;i<hwav.SubChun2Size*8/hwav.BitsPerSample;i++)
 {
  fprintf(fp,"%d\n",wav_data[i]);
 }
   fclose(fpWav);
    fpWav = NULL;
  }
  else
  {
   printf("Open wave file %s failed!\n", argv[1]);
  }
}

 

最后,需要指出的是,对于语音的处理,读取wav文件只是很小的一步。也是比较简单的一步。当我们遇到MP3,wma怎么去读取数据了?或许你需要去思考。当然解码是很重要的,但是MP3已经压缩了,还是返回完整的数据吗?我也不是很清楚。

此外,附上现在存在的音频格式:pcm,wav,mp2,mp3.aac,wb+,729等。

matlab读取音频除了wavread还有Dan Ellis写的audioread,详细见http://www.ee.columbia.edu/~dpwe/resources/matlab/audioread/。

再者,在http://www.ee.columbia.edu/~dpwe/resources/matlab/这个网址里,Dan Ellis教授开源了许多matlab处理语音的代码。大家可以去关注下,学习下。

同样,上次说的台湾的张智星教授也提供了matlab处理语音的一些代码。

 

     至此,语音知识回顾和总结的第一篇---读取语音部分就基本说完了。感觉自己的思路不是很清楚,说的也不清楚,大家凑合看。不了解的随时找我,欢迎大家指正。

原创粉丝点击