zoukankan      html  css  js  c++  java
  • 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.
    ");
            return -1;
        }
        fpout = fopen(wavepath, "wb+");
        if(fpout==NULL)
        {
            printf("Create wav file error.
    ");
            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

  • 相关阅读:
    个人不断学习的真正起因(值得收藏)——北漂18年(24)
    IPython基础使用_Round2
    IPython基础使用_Round2
    Mysql 创建查询用户
    8.11.3 Concurrent Inserts 并发插入:
    8.11.2 Table Locking Issues 表锁发生
    8.11.1 Internal Locking Methods
    Oracle timestamp
    报表引擎API开发入门— EJB程序数据源
    8.10.3 The MySQL Query Cache
  • 原文地址:https://www.cnblogs.com/Allen-win/p/9940242.html
Copyright © 2011-2022 走看看