读取Wave格式语音头信息的实现

/*
 *=================================================================
 * FNAME: test.cc
 * DESCP: <+Brief Descripation+>
 * CREAT: 2015-08-18 15:39:21
 * LC_AT: 2015-08-18 15:45:57
 * VERNO: 1.0.4
 * CNOTE: <+Latest Change+>
 *=================================================================
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define FOURCC_RIFF "RIFF"
#define FOURCC_WAVE "WAVE"
#define FOURCC_FMT  "fmt "
#define FOURCC_DATA "data"

#define SUPPORTED_SAMPLE_RATE_8K 8000

#ifndef WAVE_FORMAT_PCM
#define WAVE_FORMAT_PCM     0x0001
#define WAVE_FORMAT_ALAW    0x0006
#define WAVE_FORMAT_MULAW   0x0007
#endif

//#ifdef  DEBUG
//#define   tDebug printf
//#else      /* -----  not DEBUG  ----- */
//#define   tDebug //printf
//#endif     /* -----  not DEBUG  ----- */
#define tDebug printf

/**
 * @brief
 *      获取语音文件的头信息(包含 采样点数,语音文件的编码格式,声轨数目)
 * @param fpWav
 * @param nSampleNum
 * @param nChanns
 * @param nWavType
 * @return
 *    0, WAVE文件头正常,且此时文件指针(fpWav)指向实际声音数据的起始位置
 *   -1, 不是RIFF格式的文件
 *   -2, 文件是RIFF格式的非WAVE文件
 *   -3, 此WAVE文件的编码格式不是 PCM,ALAW,ULAW
 *   -4, 此WAVE文件的音轨数不是 1 也不是 2
 *   -5, 此WAVE文件的采样率不是 8K
 *   -6, 此WAVE文件的采样点的大小不是 8bit 也不是16bit
 *   -7, 此WAVE文件的具体格式 不是 8K_16BIT_PCM 也不是 8K_8BIT_ALAW
 */
int GetWaveHeader(FILE *fpWav, int &nSampleNum, short &nChanns, short &nWavType)

{
  nSampleNum = -1;
  nWavType = -1;

  char magic[4] = {0};
  fseek(fpWav, 0L, SEEK_SET); //确保输入的文件指针 fpWav 的位置是文件的初始位置
  fread((void*) magic, 4, 1, fpWav);
  if (0 != strncmp(FOURCC_RIFF, magic, 4)) {
    tDebug("[Tip] Input file is not in RIFF format\n");
    return -1;
  }
  int lng = 0;
  fread((void*) &lng, 4, 1, fpWav);
  fread((void*) magic, 4, 1, fpWav);
  if (0 != strncmp(FOURCC_WAVE, magic, 4)) {
    tDebug("[Tip] Input file is not in WAVE format\n");
    return -2;
  }

  //look for FOURCC_FMT/FOURCC_DATA before end of file
  int len = 0;
  short blockAlign = 0, sampleSize = 0;

  while (0 == feof(fpWav)) //not reach the end of this file
  {
    fread((void*) magic, 4, 1, fpWav); //read ChunkID
    fread((void*) &len, 4, 1, fpWav); //read ChunkSize
    if (0 == strncmp(FOURCC_DATA, magic, 4))
    {//reach DATA Chunk,exit the while loop
      nSampleNum = len / (sampleSize / 8); // 声音数据的采样点数目
      break;
    }
    if (0 == strncmp(FOURCC_FMT, magic, 4))
    { //reach Fmt Chunk,and parse format informations

      fread(&nWavType, 2, 1, fpWav); // 读取数据类型,例如: PCM, ALaw,Mulaw等
      if (nWavType != WAVE_FORMAT_PCM && nWavType != WAVE_FORMAT_MULAW
        && nWavType != WAVE_FORMAT_ALAW)
      {
        tDebug("[Tip] Only standard PCM and ALAW supported.\n");
        return -3;
      }

      fread(&nChanns, 2, 1, fpWav); //Number of Channels, 单通道或双通道
      if (nChanns != 1 && nChanns != 2)
      {
        tDebug("[Tip] Wave file's channels is %d,NOT SUPPORTED\n", nChanns);
        nChanns = -1;
        return -4;
      }

      fread(&lng, 4, 1, fpWav); // Sample Rate , 采样率
      if (lng != SUPPORTED_SAMPLE_RATE_8K)
      {
        tDebug("[Tip] Wave file's SampleRate(SR) is %d, NOT SUPPORTED! \n", lng);
        return -5;
      }
      fread(&lng, 4, 1, fpWav); //  每秒的字节数。例如:8k16bit时为 8000×2=16000
      fread(&blockAlign, 2, 1, fpWav); // Block align , Chunk 的对齐单位
      fread(&sampleSize, 2, 1, fpWav); // Data size ,一个采样点的大小(比特数)
      if (sampleSize != 16 && sampleSize != 8)
      {
        tDebug("[Tip] Only 8/16 bit audio supported!\n");
        return -6;
      }

      // 类型检查
      if ((nWavType == WAVE_FORMAT_PCM && sampleSize != 16)
       || ((nWavType == WAVE_FORMAT_MULAW || nWavType == WAVE_FORMAT_ALAW)
        && sampleSize != 8))
      {
        tDebug("[Tip] Only 8K_16BIT_PCM and 8K_8BIT_ALAW supported!\n");
        return -7;
      }
      // 如果是扩展的RIFF格式,则"fmt "块的大小可能大于16字节
      len -= 16;
    }//end of if (0 == strncmp(FOURCC_FMT, magic, 4))

    //fmt子块多余的信息,我们不感兴趣. 直接跳过剩余的fmt字节
    for (char c; len > 0; len--)
    {
      fread(&c, 1, 1, fpWav);
    }
  }

  return 0;
}

猜你喜欢

转载自blog.csdn.net/liudglink/article/details/47753345