pcm 轉 wav 工具

迷霧綠洲發表於2017-07-01

在做音訊測試時經常需要採集原始資料進行分析,結果需要給其他人去聽效果,播放pcm 需要知道取樣率 ,資料位寬,聲道等資訊,每次播放設定這些引數比較麻煩,最好就是直接給pcm 資料直接加上wav 的頭資訊轉換成wav 檔案,這樣就可以在常見的播放器上播放了,wav格式的一個優勢就是沒有經過任何壓縮處理,不會出現資訊的丟失,保證能過的一樣的效果。
源程式如下:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <getopt.h>
#include <sys/signal.h>
 struct WAVFLIEHEAD
{
char RIFFNAME[4];
unsigned int nRIFFLength;
char WAVNAME[4];
char FMTNAME[4];
unsigned int nFMTLength;
unsigned short nAudioFormat;
unsigned short  nChannleNumber;
unsigned int nSampleRate;
unsigned int nBytesPerSecond;
unsigned short nBytesPerSample;
unsigned short   nBitsPerSample;
char   DATANAME[4];
unsigned int  nDataLength;
};


int main(int argc, char const *argv[])
{
    unsigned short rate;
    int option_index, c;
        static const char short_options[] = "hC:P:r:v:s:b:p:";
        static const struct option long_options[] = {
            {"help",no_argument,0,'h'},
            {"wav file name",required_argument,0,'C'},
            {"pcm file name",required_argument,0,'P'},
            {"rate",required_argument,0,'r'},
            {0, 0, 0, 0}
        };
    char file_name_wav[100]={0,};

    char file_name_pcm[100]={0,};
    while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1)  {
            switch(c) {
                case 'h':
                    printf("help\n");
                    return 0;
                case 'C':
                    strcpy(file_name_wav,optarg);

                    break;
                case 'P':
                    strcpy(file_name_pcm,optarg);

                    break;
                case 'r':
                    rate = strtol(optarg, NULL, 0);
                    break;
                default:
                    printf("unsupport cmd,try -h for help\n");
                    return 1;
            }
        }

struct WAVFLIEHEAD DestionFileHeader;
DestionFileHeader.RIFFNAME[0] = 'R';
DestionFileHeader.RIFFNAME[1] = 'I';
DestionFileHeader.RIFFNAME[2] = 'F';
DestionFileHeader.RIFFNAME[3] = 'F';

DestionFileHeader.WAVNAME[0] = 'W';
DestionFileHeader.WAVNAME[1] = 'A';
DestionFileHeader.WAVNAME[2] = 'V';
DestionFileHeader.WAVNAME[3] = 'E';

DestionFileHeader.FMTNAME[0] = 'f';
DestionFileHeader.FMTNAME[1] = 'm';
DestionFileHeader.FMTNAME[2] = 't';
DestionFileHeader.FMTNAME[3] = 0x20;
DestionFileHeader.nFMTLength =16;  //  ��ʾ FMT �ij���
DestionFileHeader.nAudioFormat = 1; //�����ʾa lawPCM

DestionFileHeader.DATANAME[0] = 'd';
DestionFileHeader.DATANAME[1] = 'a';
DestionFileHeader.DATANAME[2] = 't';
DestionFileHeader.DATANAME[3] = 'a';
DestionFileHeader.nBitsPerSample = 16;
DestionFileHeader.nBytesPerSample =2;    //
DestionFileHeader.nSampleRate =rate;   //
DestionFileHeader.nBytesPerSecond = rate * DestionFileHeader.nBytesPerSample;
DestionFileHeader.nChannleNumber = 1;


int nFileLen = 0;
int nSize = sizeof(DestionFileHeader);

FILE *fp_s = NULL;
FILE *fp_d = NULL;

fp_s = fopen(file_name_pcm, "rb");
if (fp_s == NULL)
  return -1;

fp_d = fopen(file_name_wav, "wb+");
if (fp_d == NULL)
  return -2;


int nWrite =fwrite(&DestionFileHeader, 1, nSize, fp_d);
if (nWrite != nSize)
{
  fclose(fp_s);
  fclose(fp_d);
  return -3;
}

while( !feof(fp_s))
{
  char readBuf[4096];
  int nRead = fread(readBuf, 1,4096, fp_s);
  if (nRead >0)
  {
   fwrite(readBuf,1, nRead, fp_d);
  }

  nFileLen += nRead;
}
fseek(fp_d, 0L, SEEK_SET);

DestionFileHeader.nRIFFLength = nFileLen - 8 +nSize;
DestionFileHeader.nDataLength = nFileLen;
nWrite =fwrite(&DestionFileHeader, 1, nSize, fp_d);
if (nWrite != nSize)
{
  fclose(fp_s);
  fclose(fp_d);
  return -4;
}

fclose(fp_s);
fclose(fp_d);

return nFileLen;
}

我在Ubuntu上做測試,所有轉換也就在Ubuntu上進行了,就在上邊編譯工具好讓他能夠執行在系統裡面。檔名假定位 pcm_to_wav.c
編譯命令就是:

gcc  pcm_to_wav.c -o pcm_to_wav

工具使用設定了三個引數:
-C 轉換成的wav檔案的檔名
-P 待轉換的pcm 檔案的檔名
-r pcm 的波特率
因為我自己一般都是使用16bit 位寬的,如果有其他位寬需求可以增加引數.

工具使用命令:

pcm_to_wav -C wav_out.wav -P to_wav.dat -r 16000

相關文章