语音识别中的端点检测(VAD)

转载于:https://blog.csdn.net/c602273091/article/details/44340451

作者:Snail_Walker


在之前呢我们已经把portaudio平台搭好了,可以采集声音信号并播放了。那么接下来呢我们就来做一些实质性的东西——自适应端点检测。那么什么是自适应端点检测呢?也就是采集声音信号的时候,开始说话到说话结束,我们把这一段声音信号采集下来进行处理。不然那么多信号都去处理,没有声音也处理那就浪费了很多的空间以及浪费了CPU去做后续的操作。后面的功夫是省了,但是前面的工作就多了。天下可没有白费的午餐!接下来我就大概说一下我的做法吧。


1、基础


      采样频率的设置:我们人耳一般可以听到的频率最高就是16000HZ。根据采样定理,一般采样频率要是这个的两倍才不会发生混叠。所以我们在通话的时候采样频率一般是8Khz,带宽就需要16Khz。这样就基本可以使得通话的体验非常到位,还原度非常高!不是说采样频率越高声音的效果就越好,这是一个trade-off。这一次我们采样就用16Khz,这样其实已经可以把基本的声音采下来。因为人耳对于低频还是更加敏感!现在的高保真就是44.1Khz的采样率。在经过量化(均匀量化和非均匀量化)就可以进行保存。怎么把采集到的信号进行数字化变成非均匀量化比如Mu律。请参考:

http://www.speech.cs.cmu.edu/comp.speech/Section2/Q2.7.html

         声音采集时遇到的问题:在进行声音采集的时候有噪声,我们得小减小噪声的影响;以及还有回声。

        声音采集的方式:直接对已有的声音(已经录制好的)进行处理;以及现场录制。这样的工具有:Windows recorder,Adobe audition,Linux的arecord。

        声音保存的方式:如下图。一般是PCM之后才好做进一步的处理。

    语音识别中的端点检测(VAD)

          声音采集时序考虑的参数:采样频率,量化方式,通道,存储。    

          声音采集时的两种模式:阻塞(自己设定时间,不管有没有数据都要回来)和回调(有有效的数据的时候才会调用这个函数返回数据),这两种在Portaudio里面都有对应的代码。在这里你大概也想到了我们应该使用的就是回调才能实现我们的功能。

         语言处理的模式:Push和Pull。在这里的话,这两个东西正好和阻塞和回调差不多对应。

         端点检测:实现效果如下图:一般来说人说话是突然说的,然后我们还要判断什么时候结束。

   语音识别中的端点检测(VAD)


2、算法


具体实现的步骤如下图:

语音识别中的端点检测(VAD)


  • 判别:计算每个时刻的能量,设定一个阈值k,如果大于它,我们认为是1(1表示该点是语言),否则就是0。能量计算的公式就是:语音识别中的端点检测(VAD)
  • 平滑:小于100ms的silien我们认为是语音的部分,大于250ms的语言我们才认为是语言。在截取的语音信号前后多截出250ms。这个的前提是比较安静,如果不安静的话那么就得另当别论,看外界影响有多大。
  • 算法一:先来一个比较简单的算法

  语音识别中的端点检测(VAD)

  • 算法二:更复杂一些的算法

       语音识别中的端点检测(VAD)


3、代码

捕获声音信号并转化:

[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <math.h>         //function log  
  4. #include <conio.h>        //kbhit()  
  5. #include "portaudio.h"  
  6. #include "readwave.h"     //WriteWave()  
  7.   
  8. /* #define SAMPLE_RATE  (17932) // Test failure to open with this value. */  
  9. //SAMPLE_RATE,  FRAMES_PER_BUFFER, NUM_SECONDS, NUM_CHANNELS are modified by Yao Canwu  
  10. #define SAMPLE_RATE (16000)    
  11. #define FRAMES_PER_BUFFER (400)  
  12. #define NUM_SECONDS     (60)  
  13. #define NUM_CHANNELS    (1)  
  14. /* #define DITHER_FLAG     (paDitherOff) */  
  15. #define DITHER_FLAG     (0) /**/  
  16. /** Set to 1 if you want to capture the recording to a file. */  
  17. #define WRITE_TO_FILE   (0)  
  18.   
  19. /* Select sample format. */  
  20. #if 0  
  21. #define PA_SAMPLE_TYPE  paFloat32  
  22. typedef float SAMPLE;  
  23. #define SAMPLE_SILENCE  (0.0f)  
  24. #define PRINTF_S_FORMAT "%.8f"  
  25. #elif 1  
  26. #define PA_SAMPLE_TYPE  paInt16  
  27. typedef short SAMPLE;  
  28. #define SAMPLE_SILENCE  (0)  
  29. #define PRINTF_S_FORMAT "%d"  
  30. #elif 0  
  31. #define PA_SAMPLE_TYPE  paInt8  
  32. typedef char SAMPLE;  
  33. #define SAMPLE_SILENCE  (0)  
  34. #define PRINTF_S_FORMAT "%d"  
  35. #else  
  36. #define PA_SAMPLE_TYPE  paUInt8  
  37. typedef unsigned char SAMPLE;  
  38. #define SAMPLE_SILENCE  (128)  
  39. #define PRINTF_S_FORMAT "%d"  
  40. #endif  
  41.   
  42. typedef struct  
  43. {  
  44.     int          frameIndex;  /* Index into sample array. */  
  45.     int          maxFrameIndex;  
  46.     SAMPLE      *recordedSamples;  
  47. }  
  48. paTestData;  
  49.   
  50. //calculate the energy in decibe of a frame segment  
  51. //added by Yao Canwu  
  52. float energyPerSampleInDecibe(const SAMPLE *ptr)  
  53. {  
  54.     float energy = 0.0f;  
  55.     SAMPLE temp;  
  56.     for (unsigned long i = 0; i<FRAMES_PER_BUFFER; i++)  
  57.     {  
  58.         temp = *(ptr + i);  
  59.         energy += temp * temp;  
  60.     }  
  61.     energy = 10 * log(energy);  
  62.     return energy;  
  63. }  
  64. //An Adaptive Endpointing Algorithm  
  65. //added by Yao Canwu  
  66. const float forgetfactor = 1;  
  67. const float adjustment = 0.05;  
  68. //key value for classifyFrame(), need to adjust to different environment.  
  69. const float threshold = 10; //  
  70. float background = 0;  
  71. float level = 0;  
  72. int count = 0;  
  73.   
  74. bool classifyFrame(const SAMPLE *ptr)  
  75. {  
  76.     float current = energyPerSampleInDecibe(ptr);  
  77.     bool isSpeech = false;  
  78.     level = ((level * forgetfactor) + current) / (forgetfactor + 1);  
  79.     if (current < background)  background = current;  
  80.     else background += (current - background) * adjustment;  
  81.     if (level < background)  level = background;  
  82.     if (level - background > threshold)  isSpeech = true;  
  83.     return isSpeech;  
  84. }  
  85. /* This routine will be called by the PortAudio engine when audio is needed. 
  86. ** It may be called at interrupt level on some machines so don't do anything 
  87. ** that could mess up the system like calling malloc() or free(). 
  88. */  
  89. static int recordCallback(const void *inputBuffer, void *outputBuffer,  
  90.     unsigned long framesPerBuffer,  
  91.     const PaStreamCallbackTimeInfo* timeInfo,  
  92.     PaStreamCallbackFlags statusFlags,  
  93.     void *userData)  
  94. {  
  95.     paTestData *data = (paTestData*)userData;  
  96.     const SAMPLE *rptr = (const SAMPLE*)inputBuffer;  
  97.     SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];  
  98.     long framesToCalc;  
  99.     long i;  
  100.     int finished;  
  101.     unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;  
  102.   
  103.     (void)outputBuffer; /* Prevent unused variable warnings. */  
  104.     (void)timeInfo;  
  105.     (void)statusFlags;  
  106.     (void)userData;  
  107.   
  108.     if (framesLeft < framesPerBuffer)  
  109.     {  
  110.         framesToCalc = framesLeft;  
  111.         finished = paComplete;  
  112.     }  
  113.     else  
  114.     {  
  115.         framesToCalc = framesPerBuffer;  
  116.         finished = paContinue;  
  117.     }  
  118.   
  119.     if (inputBuffer == NULL)  
  120.     {  
  121.         for (i = 0; i<framesToCalc; i++)  
  122.         {  
  123.             *wptr++ = SAMPLE_SILENCE;  /* left */  
  124.             if (NUM_CHANNELS == 2) *wptr++ = SAMPLE_SILENCE;  /* right */  
  125.         }  
  126.     }  
  127.     else  
  128.     {  
  129.         for (i = 0; i<framesToCalc; i++)  
  130.         {  
  131.             *wptr++ = *rptr++;  /* left */  
  132.             if (NUM_CHANNELS == 2) *wptr++ = *rptr++;  /* right */  
  133.         }  
  134.     }  
  135.     data->frameIndex += framesToCalc;  
  136.     /* calculate the initial background and initial level, 
  137.     ** which will be used for classify frame 
  138.     ** Added by Yao Canwu 
  139.     */  
  140.     if (data->frameIndex == 0)  
  141.     {  
  142.         level = energyPerSampleInDecibe(&data->recordedSamples[0]);  
  143.         background = 0.0f;  
  144.         SAMPLE temp;  
  145.         for (i = 0; i < 10 * framesPerBuffer; i++)  
  146.         {  
  147.             temp = data->recordedSamples[i];  
  148.             background += temp * temp;  
  149.         }  
  150.         background = log(background);  
  151.     }  
  152.     //Silence in 4 seconds means the end of audio capture  
  153.     if (classifyFrame(rptr)) count = 0;  
  154.     else count++;  
  155.     //printf("count = %d\n", count);  
  156.   
  157.     if (count >= 80) data->maxFrameIndex = data->frameIndex;  
  158.   
  159.     return finished;  
  160. }  
  161.   
  162. /* This routine will be called by the PortAudio engine when audio is needed. 
  163. ** It may be called at interrupt level on some machines so don't do anything 
  164. ** that could mess up the system like calling malloc() or free(). 
  165. */  
  166. static int playCallback(const void *inputBuffer, void *outputBuffer,  
  167.     unsigned long framesPerBuffer,  
  168.     const PaStreamCallbackTimeInfo* timeInfo,  
  169.     PaStreamCallbackFlags statusFlags,  
  170.     void *userData)  
  171. {  
  172.     paTestData *data = (paTestData*)userData;  
  173.     SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];  
  174.     SAMPLE *wptr = (SAMPLE*)outputBuffer;  
  175.     unsigned int i;  
  176.     int finished;  
  177.     unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;  
  178.   
  179.     (void)inputBuffer; /* Prevent unused variable warnings. */  
  180.     (void)timeInfo;  
  181.     (void)statusFlags;  
  182.     (void)userData;  
  183.   
  184.     if (framesLeft < framesPerBuffer)  
  185.     {  
  186.         /* final buffer... */  
  187.         for (i = 0; i<framesLeft; i++)  
  188.         {  
  189.             *wptr++ = *rptr++;  /* left */  
  190.             if (NUM_CHANNELS == 2) *wptr++ = *rptr++;  /* right */  
  191.         }  
  192.         for (; i<framesPerBuffer; i++)  
  193.         {  
  194.             *wptr++ = 0;  /* left */  
  195.             if (NUM_CHANNELS == 2) *wptr++ = 0;  /* right */  
  196.         }  
  197.         data->frameIndex += framesLeft;  
  198.         finished = paComplete;  
  199.     }  
  200.     else  
  201.     {  
  202.         for (i = 0; i<framesPerBuffer; i++)  
  203.         {  
  204.             *wptr++ = *rptr++;  /* left */  
  205.             if (NUM_CHANNELS == 2) *wptr++ = *rptr++;  /* right */  
  206.         }  
  207.         data->frameIndex += framesPerBuffer;  
  208.         finished = paContinue;  
  209.     }  
  210.     return finished;  
  211. }  
  212.   
  213. /*******************************************************************/  
  214. int main(void)  
  215. {  
  216.     PaStreamParameters  inputParameters,  
  217.         outputParameters;  
  218.     PaStream*           stream;  
  219.     PaError             err = paNoError;  
  220.     paTestData          data;  
  221.     int                 i;  
  222.     int                 totalFrames;  
  223.     int                 numSamples;  
  224.     int                 numBytes;  
  225.     SAMPLE              max, val;  
  226.     double              average;  
  227.   
  228.     printf("patest_record.c\n"); fflush(stdout);  
  229.   
  230.     data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */  
  231.     data.frameIndex = 0;  
  232.     numSamples = totalFrames * NUM_CHANNELS;  
  233.     numBytes = numSamples * sizeof(SAMPLE);  
  234.     data.recordedSamples = (SAMPLE *)malloc(numBytes); /* From now on, recordedSamples is initialised. */  
  235.     if (data.recordedSamples == NULL)  
  236.     {  
  237.         printf("Could not allocate record array.\n");  
  238.         goto done;  
  239.     }  
  240.     for (i = 0; i<numSamples; i++) data.recordedSamples[i] = 0;  
  241.   
  242.     err = Pa_Initialize();  
  243.     if (err != paNoError) goto done;  
  244.   
  245.     inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */  
  246.     if (inputParameters.device == paNoDevice) {  
  247.         fprintf(stderr, "Error: No default input device.\n");  
  248.         goto done;  
  249.     }  
  250.     inputParameters.channelCount = 1;                    /* stereo input */  
  251.     inputParameters.sampleFormat = PA_SAMPLE_TYPE;  
  252.     inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;  
  253.     inputParameters.hostApiSpecificStreamInfo = NULL;  
  254.   
  255.     //set a keyboard hit to start recording. Added by Yao Canwu  
  256.     printf("Press any key to start recording\n");  
  257.     while (!kbhit()){}  
  258.   
  259.     /* Record some audio. -------------------------------------------- */  
  260.     err = Pa_OpenStream(  
  261.         &stream,  
  262.         &inputParameters,  
  263.         NULL,                  /* &outputParameters, */  
  264.         SAMPLE_RATE,  
  265.         FRAMES_PER_BUFFER,  
  266.         paClipOff,      /* we won't output out of range samples so don't bother clipping them */  
  267.         recordCallback,  
  268.         &data);  
  269.     if (err != paNoError) goto done;  
  270.   
  271.     err = Pa_StartStream(stream);  
  272.     if (err != paNoError) goto done;  
  273.     printf("\n=== Now start recording!!\n"); fflush(stdout);  
  274.     /* Pa_IsStreamActive: Determine whether the stream is active. A stream 
  275.     is active after a successful call to Pa_StartStream(), until it becomes 
  276.     inactive either as a result of a call to Pa_StopStream() or Pa_AbortStream(), 
  277.     or as a result of a return value other than paContinue from the stream callback. 
  278.     In the latter case, the stream is considered inactive after the last buffer has finished playing. */  
  279.     while ((err = Pa_IsStreamActive(stream)) == 1)  
  280.     {  
  281.         Pa_Sleep(1000);  
  282.         printf("index = %d\n", data.frameIndex); fflush(stdout);  
  283.     }  
  284.     if (err < 0) goto done;  
  285.   
  286.     err = Pa_CloseStream(stream);  
  287.     if (err != paNoError) goto done;  
  288.   
  289.     //Write wave to file in wav formate. Added by Yao Canwu  
  290.     printf("Waiting to save into file...\n");  
  291.     char *path = "audio.wav";  
  292.     WriteWave(path, data.recordedSamples, data.maxFrameIndex, SAMPLE_RATE);  
  293.     printf("Save successfully!\n");  
  294.   
  295.     /* Write recorded data to a file. */  
  296. #if WRITE_TO_FILE  
  297.     {  
  298.         FILE  *fid;  
  299.         fid = fopen("recorded.raw""wb");  
  300.         if (fid == NULL)  
  301.         {  
  302.             printf("Could not open file.");  
  303.         }  
  304.         else  
  305.         {  
  306.             fwrite(data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid);  
  307.             fclose(fid);  
  308.             printf("Wrote data to 'recorded.raw'\n");  
  309.         }  
  310.     }  
  311. #endif  
  312.     /* Playback recorded data.  -------------------------------------------- */  
  313.     data.frameIndex = 0;  
  314.   
  315.     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */  
  316.     if (outputParameters.device == paNoDevice) {  
  317.         fprintf(stderr, "Error: No default output device.\n");  
  318.         goto done;  
  319.     }  
  320.     outputParameters.channelCount = 1;                     /* stereo output */  
  321.     outputParameters.sampleFormat = PA_SAMPLE_TYPE;  
  322.     outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;  
  323.     outputParameters.hostApiSpecificStreamInfo = NULL;  
  324.   
  325.     printf("\n=== Now playing back. ===\n"); fflush(stdout);  
  326.     err = Pa_OpenStream(  
  327.         &stream,  
  328.         NULL, /* no input */  
  329.         &outputParameters,  
  330.         SAMPLE_RATE,  
  331.         FRAMES_PER_BUFFER,  
  332.         paClipOff,      /* we won't output out of range samples so don't bother clipping them */  
  333.         playCallback,  
  334.         &data);  
  335.     if (err != paNoError) goto done;  
  336.   
  337.     if (stream)  
  338.     {  
  339.         err = Pa_StartStream(stream);  
  340.         if (err != paNoError) goto done;  
  341.   
  342.         printf("Waiting for playback to finish.\n"); fflush(stdout);  
  343.   
  344.         while ((err = Pa_IsStreamActive(stream)) == 1) Pa_Sleep(100);  
  345.         if (err < 0) goto done;  
  346.   
  347.         err = Pa_CloseStream(stream);  
  348.         if (err != paNoError) goto done;  
  349.   
  350.         printf("Done.\n"); fflush(stdout);  
  351.     }  
  352. done:  
  353.     Pa_Terminate();  
  354.     if (data.recordedSamples)       /* Sure it is NULL or valid. */  
  355.         free(data.recordedSamples);  
  356.     if (err != paNoError)  
  357.     {  
  358.         fprintf(stderr, "An error occured while using the portaudio stream\n");  
  359.         fprintf(stderr, "Error number: %d\n", err);  
  360.         fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err));  
  361.         err = 1;          /* Always return 0 or 1, but no other return codes. */  
  362.     }  
  363.     system("pause");  
  364.     return err;  
  365. }  
readwav:

[cpp] view plain copy
  1. #include <stdlib.h>  
  2. #include <math.h>  
  3. #include <memory.h>  
  4. #include <assert.h>  
  5. #include <string.h>  
  6. #include "readwave.h"  
  7.   
  8.   
  9. bool WaveRewind(FILE *wav_file, WavFileHead *wavFileHead)  
  10. {  
  11.     char riff[8],wavefmt[8];  
  12.     short i;  
  13.     rewind(wav_file);  
  14.     fread(wavFileHead,sizeof(struct WavFileHead),1,wav_file);  
  15.   
  16.     for ( i=0;i<8;i++ )  
  17.     {  
  18.         riff[i]=wavFileHead->RIFF[i];  
  19.         wavefmt[i]=wavFileHead->WAVEfmt_[i];  
  20.     }  
  21.     riff[4]='\0';  
  22.     wavefmt[7]='\0';  
  23.     if ( strcmp(riff,"RIFF")==0 && strcmp(wavefmt,"WAVEfmt")==0 )  
  24.         return  true;  // It is WAV file.  
  25.     else  
  26.     {  
  27.         rewind(wav_file);  
  28.         return(false);  
  29.     }  
  30. }  
  31.   
  32.   
  33. short *ReadWave(const char *wavFile, int *numSamples, int *sampleRate )   
  34. {                                                                 
  35.     FILE    *wavFp;  
  36.     WavFileHead     wavHead;  
  37.     short   *waveData;  
  38.     long    numRead;  
  39.   
  40.     wavFp = fopen(wavFile, "rb");  
  41.     if (!wavFp)   
  42.     {  
  43.         printf("\nERROR:can't open %s!\n", wavFile);  
  44.         exit(0);  
  45.     }  
  46.   
  47.     if (WaveRewind(wavFp, &wavHead) == false)  
  48.     {  
  49.         printf("\nERROR:%s is not a Windows wave file!\n", wavFile);  
  50.         exit(0);  
  51.     }  
  52.   
  53.     waveData = new short [wavHead.RawDataFileLength/sizeof(short)];  
  54.     numRead = fread(waveData, sizeof(short), wavHead.RawDataFileLength / 2, wavFp);  
  55.     assert(numRead * sizeof(short) == (unsigned long)wavHead.RawDataFileLength);  
  56.     fclose(wavFp);  
  57.   
  58.     *numSamples = wavHead.RawDataFileLength/sizeof(short);  
  59.     *sampleRate = wavHead.SampleRate;  
  60.     return  waveData;  
  61. }  
  62.   
  63. void FillWaveHeader(void *buffer, int raw_wave_len, int sampleRate)  
  64. {  
  65.     WavFileHead  wavHead;  
  66.   
  67.     strcpy(wavHead.RIFF, "RIFF");  
  68.     strcpy(wavHead.WAVEfmt_, "WAVEfmt ");  
  69.     wavHead.FileLength = raw_wave_len + 36;  
  70.     wavHead.noUse = 16;  
  71.     wavHead.FormatCategory = 1;  
  72.     wavHead.NChannels = 1;  
  73.     wavHead.SampleRate = sampleRate;  
  74.     wavHead.SampleBytes = sampleRate*2;  
  75.     wavHead.BytesPerSample = 2;  
  76.     wavHead.NBitsPersample = 16;  
  77.     strcpy(wavHead.data, "data");  
  78.     wavHead.RawDataFileLength = raw_wave_len;  
  79.   
  80.     memcpy(buffer, &wavHead, sizeof(WavFileHead));  
  81. }  
  82.   
  83. void WriteWave(const char *wavFile, short *waveData, int numSamples, int sampleRate)  
  84. {  
  85.     FILE    *wavFp;  
  86.     WavFileHead     wavHead;  
  87.     long    numWrite;  
  88.   
  89.     wavFp = fopen(wavFile, "wb");  
  90.     if (!wavFp)   
  91.     {  
  92.         printf("\nERROR:can't open %s!\n", wavFile);  
  93.         exit(0);  
  94.     }  
  95.   
  96.     FillWaveHeader(&wavHead, numSamples*sizeof(short), sampleRate);  
  97.     fwrite(&wavHead, sizeof(WavFileHead), 1, wavFp);  
  98.     numWrite = fwrite(waveData, sizeof(short), numSamples, wavFp);  
  99.     assert(numWrite == numSamples);  
  100.     fclose(wavFp);  
  101. }  
  102.   
  103. void GetWavHeader(const char *wavFile, short *Bits, int *Rate,  
  104.                   short *Format, int *Length, short *Channels)   
  105. {                                                                 
  106.     FILE    *wavFp;  
  107.     WavFileHead     wavHead;  
  108.     char    *waveData;  
  109.     long    numRead,File_length;  
  110.   
  111.     wavFp = fopen(wavFile, "rb");  
  112.     if (!wavFp)   
  113.     {  
  114.         printf("\nERROR:can't open %s!\n", wavFile);  
  115.         exit(0);  
  116.     }  
  117.     fseek(wavFp,0,SEEK_END);  
  118.     File_length=ftell(wavFp);  
  119.   
  120.     if (WaveRewind(wavFp, &wavHead) == false)  
  121.     {  
  122.         printf("\nERROR:%s is not a Windows wave file!\n", wavFile);  
  123.         exit(0);  
  124.     }  
  125.   
  126.     waveData = new char[(File_length-sizeof(struct WavFileHead))/sizeof(char)];  
  127.     numRead = fread(waveData, sizeof(char), File_length-sizeof(struct WavFileHead), wavFp);  
  128.     fclose(wavFp);  
  129.   
  130.     *Bits = wavHead.NBitsPersample;  
  131.     *Format = wavHead.FormatCategory;  
  132.     *Rate = wavHead.SampleRate;  
  133.     *Length = (int)numRead;  
  134.     *Channels = wavHead.NChannels;  
  135.   
  136.     delete []   waveData;  
  137. }  
  138.   
  139.   
  140. short *ReadWavFile(const char *wavFile, int *numSamples, int *sampleRate )  
  141. {                                                                 
  142.     FILE    *wavFp;  
  143.     WavFileHead     wavHead;  
  144.     short   *waveData;  
  145.     long    numRead,File_length;  
  146.   
  147.     wavFp = fopen(wavFile, "rb");  
  148.     if (!wavFp)   
  149.     {  
  150.         printf("\nERROR:can't open %s!\n", wavFile);  
  151.         exit(0);  
  152.     }  
  153.     fseek(wavFp,0,SEEK_END);  
  154.     File_length=ftell(wavFp);  
  155.   
  156.   
  157.     if (WaveRewind(wavFp, &wavHead) == false)  
  158.     {  
  159.         printf("\nERROR:%s is not a Windows wave file!\n", wavFile);  
  160.         exit(0);  
  161.     }  
  162.   
  163.     waveData = new short [(File_length-sizeof(struct WavFileHead))/sizeof(short)];  
  164.     numRead = fread(waveData, sizeof(short), (File_length-sizeof(struct WavFileHead))/sizeof(short), wavFp);  
  165.     fclose(wavFp);  
  166.   
  167.     *numSamples = (int)numRead;  
  168.     *sampleRate = wavHead.SampleRate;  
  169.     return  waveData;  
  170. }  
  171.   
  172. void ReadWav(const char *wavFile, short *waveData, int *numSamples, int *sampleRate)  
  173. {                                                                 
  174.     FILE    *wavFp;  
  175.     WavFileHead     wavHead;  
  176.     long    numRead;  
  177.   
  178.     wavFp = fopen(wavFile, "rb");  
  179.     if (!wavFp)   
  180.     {  
  181.         printf("\nERROR:can't open %s!\n", wavFile);  
  182.         exit(0);  
  183.     }  
  184.   
  185.     if (WaveRewind(wavFp, &wavHead) == false)  
  186.     {  
  187.         printf("\nERROR:%s is not a Windows PCM file!\n", wavFile);  
  188.         exit(0);  
  189.     }  
  190.   
  191.     numRead = fread(waveData, sizeof(short), wavHead.RawDataFileLength/2, wavFp);  
  192.     assert(numRead*sizeof(short) == (unsigned long)wavHead.RawDataFileLength);  
  193.     fclose(wavFp);  
  194.   
  195.     *numSamples = wavHead.RawDataFileLength/sizeof(short);  
  196.     *sampleRate = wavHead.SampleRate;  
  197. }  



特别说明:以上截图来自于CMU的李明老师的上课PPT。