pcm文件轉wav C語言
阿新 • • 發佈:2018-11-10
header ret pts 內容 comm pre fmt ntb 一秒
#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(constchar *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 */ shortint 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
pcm文件轉wav C語言