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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM