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

猜你喜欢

转载自www.cnblogs.com/Allen-win/p/9940242.html