1. 程式人生 > >pcm檔案轉wav C語言

pcm檔案轉wav C語言

 

 

 

#include <stdio.h>
#include <string.h>

/**
 * Convert PCM raw data to WAVE format
 * @param pcmpath       Input PCM file.
 * @param channels      Channel number of PCM file.
 * @param sample_rate   Sample rate of PCM file.
 * @param wavepath      Output WAVE file.
 
*/ int transform_pcm_to_wave(const char *pcmpath, int channels, int sample_rate, const char *wavepath) { typedef struct WAVE_HEADER{ char fccID[4]; //內容為"RIFF" unsigned int dwSize; //最後填寫,WAVE格式音訊的大小 char fccType[4]; //內容為"WAVE" }WAVE_HEADER; typedef struct
WAVE_FMT{ char fccID[4]; //內容為"fmt " unsigned int dwSize; //內容為WAVE_FMT佔的位元組數,為16 short int wFormatTag; //如果為PCM,改值為 1 short int wChannels; //通道數,單通道=1,雙通道=2 unsigned int dwSamplesPerSec;//取樣頻率 unsigned int dwAvgBytesPerSec;/* ==dwSamplesPerSec*wChannels*uiBitsPerSample/8
*/ short int wBlockAlign;//==wChannels*uiBitsPerSample/8 short int uiBitsPerSample;//每個取樣點的bit數,8bits=8, 16bits=16 }WAVE_FMT; typedef struct WAVE_DATA{ char fccID[4]; //內容為"data" unsigned int dwSize; //==NumSamples*wChannels*uiBitsPerSample/8 }WAVE_DATA; if(channels==2 || sample_rate==0) { channels = 2; sample_rate = 44100; } WAVE_HEADER pcmHEADER; WAVE_FMT pcmFMT; WAVE_DATA pcmDATA; short int m_pcmData; FILE *fp, *fpout; fp = fopen(pcmpath, "rb+"); if(fp==NULL) { printf("Open pcm file error.\n"); return -1; } fpout = fopen(wavepath, "wb+"); if(fpout==NULL) { printf("Create wav file error.\n"); return -1; } /* WAVE_HEADER */ memcpy(pcmHEADER.fccID, "RIFF", 4); memcpy(pcmHEADER.fccType, "WAVE", 4); fseek(fpout, sizeof(WAVE_HEADER), 1); //1=SEEK_CUR /* WAVE_FMT */ memcpy(pcmFMT.fccID, "fmt ", 4); pcmFMT.dwSize = 16; pcmFMT.wFormatTag = 0x0001; pcmFMT.wChannels = 1; pcmFMT.dwSamplesPerSec = 16000; pcmFMT.uiBitsPerSample = 16; /* ==dwSamplesPerSec*wChannels*uiBitsPerSample/8 */ pcmFMT.dwAvgBytesPerSec = pcmFMT.dwSamplesPerSec*pcmFMT.wChannels*pcmFMT.uiBitsPerSample/8; /* ==wChannels*uiBitsPerSample/8 */ pcmFMT.wBlockAlign = pcmFMT.wChannels*pcmFMT.uiBitsPerSample/8; fwrite(&pcmFMT, sizeof(WAVE_FMT), 1, fpout); /* WAVE_DATA */ memcpy(pcmDATA.fccID, "data", 4); pcmDATA.dwSize = 0; fseek(fpout, sizeof(WAVE_DATA), 1); fread(&m_pcmData, sizeof(short int), 1, fp); while(!feof(fp)) { pcmDATA.dwSize += sizeof(short int); fwrite(&m_pcmData, sizeof(short int), 1, fpout); fread(&m_pcmData, sizeof(short int), 1, fp); } //
// pcmDATA.dwSize 表示pcm檔案的大小,單位是位元組,http://soundfile.sapp.org/doc/WaveFormat/ 中給出的計算方法是NumSamples * NumChannels * BitsPerSample/8
// 試了一下不行,只能播出大概一秒的時間,我覺得上面那個公式 * 秒數就能表示pcm中資料的位元組數了。
// pcmDATA.dwSize = (unsigned int)(pcmFMT.dwSamplesPerSec * (unsigned int)pcmFMT.wChannels * (unsigned int)pcmFMT.uiBitsPerSample / 8); pcmHEADER.dwSize = 36 + pcmDATA.dwSize; rewind(fpout); fwrite(&pcmHEADER, sizeof(WAVE_HEADER), 1, fpout); fseek(fpout, sizeof(WAVE_FMT), SEEK_CUR); fwrite(&pcmDATA, sizeof(WAVE_DATA), 1, fpout); fclose(fp); fclose(fpout); return 0; } int main() { transform_pcm_to_wave("/freeswitch/scripts/file/tts_resp_audio.pcm", 1, 16000, "/freeswitch/scripts/file/tts_resp_pcm_to_wav.wav"); return 0; }

本文的程式碼適用於64位的編譯器。對於位數不同的編譯器,就需要更改下這段程式碼結構體中欄位的資料型別,以滿足wav標頭檔案的規範(對每個欄位的位元組數都有詳細的描述),可參考文獻【1】【3】。

【1】https://blog.csdn.net/lyl0625/article/details/7350045

【2】https://blog.csdn.net/zhangxinbin5/article/details/7929591

【3】http://soundfile.sapp.org/doc/WaveFormat/  

【4】https://blog.csdn.net/xiunai78/article/details/6867331

【5】https://blog.csdn.net/u010011236/article/details/53026127#commentBox