• 操作pcm数据,pcm转wav


    参考资料
    视音频数据处理入门:PCM音频采样数据处理: https://blog.csdn.net/leixiaohua1020/article/details/50534316
    WAV文件格式详解: https://blog.csdn.net/imxiangzi/article/details/80265978
    在看雷神的pcm采样数据处理的文章时,看到了最后一个章节pcm转wav,测试了下,但是最后生成的wav文件没法用windowsplayer打开。
    下载了一个正常的wav文件,发现可以播放,可以肯定的是代码里封装的格式有问题。
    用ultraedit比对了下,发现了有几处不正常的地方,就顺便给改了。
    代码如下:

    #include <stdio.h>
    /**
     * Split Left and Right channel of 16LE PCM file.
     * @param url  Location of PCM file.
     *
     */
    int simplest_pcm16le_split(char *url){
        FILE *fp=fopen(url,"rb+");
        FILE *fp1=fopen("output_l.pcm","wb+");
        FILE *fp2=fopen("output_r.pcm","wb+");
     
        unsigned char *sample=(unsigned char *)malloc(4);
     
        while(!feof(fp)){
            fread(sample,1,4,fp);
            //L
            fwrite(sample,1,2,fp1);
            //R
            fwrite(sample+2,1,2,fp2);
        }
     
        free(sample);
        fclose(fp);
        fclose(fp1);
        fclose(fp2);
        return 0;
    }
    
    
    /**
     * Halve volume of Left channel of 16LE PCM file
     * @param url  Location of PCM file.
     */
    int simplest_pcm16le_halfvolumeleft(char *url){
        FILE *fp=fopen(url,"rb+");
        FILE *fp1=fopen("output_halfleft.pcm","wb+");
     
        int cnt=0;
     
        unsigned char *sample=(unsigned char *)malloc(4);
     
        while(!feof(fp)){
            short *samplenum=NULL; // short 占用2字节
            fread(sample,1,4,fp);
     
            samplenum=(short *)sample;
            *samplenum=*samplenum/2;
            //L
            fwrite(sample,1,2,fp1);
            //R
            fwrite(sample+2,1,2,fp1);
     
            cnt++;
        }
        printf("Sample Cnt:%d
    ",cnt);
     
        free(sample);
        fclose(fp);
        fclose(fp1);
        return 0;
    }
    
    
    /**
     * Re-sample to double the speed of 16LE PCM file
     * @param url  Location of PCM file.
     */
    int simplest_pcm16le_doublespeed(char *url){
        FILE *fp=fopen(url,"rb+");
        FILE *fp1=fopen("output_doublespeed.pcm","wb+");
     
        int cnt=0;
     
        unsigned char *sample=(unsigned char *)malloc(4);
     
        while(!feof(fp)){
     
            fread(sample,1,4,fp);
     
            if(cnt%2!=0){
                //L
                fwrite(sample,1,2,fp1);
                //R
                fwrite(sample+2,1,2,fp1);
            }
            cnt++;
        }
        printf("Sample Cnt:%d
    ",cnt);
     
        free(sample);
        fclose(fp);
        fclose(fp1);
        return 0;
    }
    
    /**
     * Convert PCM-16 data to PCM-8 data.
     * @param url  Location of PCM file.
     */
    int simplest_pcm16le_to_pcm8(char *url){
        FILE *fp=fopen(url,"rb+");
        FILE *fp1=fopen("output_8.pcm","wb+");
     
        int cnt=0;
     
        unsigned char *sample=(unsigned char *)malloc(4);
     
        while(!feof(fp)){
     
            short *samplenum16=NULL;
            char samplenum8=0;
            unsigned char samplenum8_u=0;
            fread(sample,1,4,fp);
            //(-32768-32767)
            samplenum16=(short *)sample;
            samplenum8=(*samplenum16)>>8;
            //(0-255)
            samplenum8_u=samplenum8+128;
            //L
            fwrite(&samplenum8_u,1,1,fp1);
     
            samplenum16=(short *)(sample+2);
            samplenum8=(*samplenum16)>>8;
            samplenum8_u=samplenum8+128;
            //R
            fwrite(&samplenum8_u,1,1,fp1);
            cnt++;
        }
        printf("Sample Cnt:%d
    ",cnt);
     
        free(sample);
        fclose(fp);
        fclose(fp1);
        return 0;
    }
    
    /**
     * Cut a 16LE PCM single channel file.
     * @param url        Location of PCM file.
     * @param start_num  start point
     * @param dur_num    how much point to cut
     */
    int simplest_pcm16le_cut_singlechannel(char *url,int start_num,int dur_num){
        FILE *fp=fopen(url,"rb+");
        FILE *fp1=fopen("output_cut.pcm","wb+");
        FILE *fp_stat=fopen("output_cut.txt","wb+");
     
        unsigned char *sample=(unsigned char *)malloc(2);
     
        int cnt=0;
        while(!feof(fp)){
            fread(sample,1,2,fp);
            if(cnt>start_num&&cnt<=(start_num+dur_num)){
                fwrite(sample,1,2,fp1);
     
                short samplenum=sample[1];
                samplenum=samplenum*256;
                samplenum=samplenum+sample[0];
     
                fprintf(fp_stat,"%6d,",samplenum);
                if(cnt%10==0)
                    fprintf(fp_stat,"
    ",samplenum);
            }
            cnt++;
        }
     
        free(sample);
        fclose(fp);
        fclose(fp1);
        fclose(fp_stat);
        return 0;
    }
    
    
    /**
     * Convert PCM16LE 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 simplest_pcm16le_to_wave(const char *pcmpath,int channels,int sample_rate,int bits,
        const char *wavepath)
    {
            //int bits = 16; // 每个channel每次采样的精度,占多少位 BitsPerSample
    typedef unsigned int uint32;
    typedef unsigned short uint16;
    
        typedef struct WAVE_HEADER{  
            char             fccID[4];    // "RIFF"
            uint32            dwSize;     // 44 + WAVE_DATA->dwSize   小端模式    
            char             fccType[4]; // "WAVE"   
        }WAVE_HEADER;  
    
        // 24
        typedef struct WAVE_FMT{  
            char                  fccID[4];          // "fmt "    
            uint32       dwSize;           // 16 小端模式     表示该区块数据的长度(不包含ID和Size的长度)      
            uint16     wFormatTag;        // AudioFormat表示Data区块存储的音频数据的格式,PCM音频数据的值为1   小端模式    
            uint16     wChannels;         // NumChannels表示音频数据的声道数,1:单声道,2:双声道 小端模式    
            uint32       dwSamplesPerSec;  // 采样率 小端模式    
            uint32       dwAvgBytesPerSec;  //  小端模式    
            uint16     wBlockAlign; // BlockAlign每个采样所需的字节数 = NumChannels * BitsPerSample / 8 小端模式    
            uint16     uiBitsPerSample;  //BitsPerSample每个采样存储的bit数,8:8bit,16:16bit,32:32bit 小端模式    
        }WAVE_FMT;  
    
        // 8B
        typedef struct WAVE_DATA{  
            char       fccID[4]; // "data"         
            uint32         dwSize;    // Size表示音频数据的长度,N = ByteRate * seconds 小端模式            
        }WAVE_DATA;  
     
     
        if(channels==0||sample_rate==0){
        channels = 2;
        sample_rate = 44100;
        }
        
     
        WAVE_HEADER   pcmHEADER;  
        WAVE_FMT   pcmFMT;  
        WAVE_DATA   pcmDATA;  
     
        unsigned   short   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",strlen("RIFF"));                    
        memcpy(pcmHEADER.fccType,"WAVE",strlen("WAVE"));  
        fseek(fpout,sizeof(WAVE_HEADER),1); 
        //WAVE_FMT
        pcmFMT.dwSamplesPerSec=sample_rate; 
        //  比特率 = SampleRate * NumChannels * BitsPerSample / 8
        pcmFMT.dwAvgBytesPerSec=pcmFMT.dwSamplesPerSec*channels*bits/8;  
        pcmFMT.uiBitsPerSample=bits;    
        memcpy(pcmFMT.fccID,"fmt ",strlen("fmt "));  
        pcmFMT.dwSize=16; 
        // BlockAlign每个采样所需的字节数 = NumChannels * BitsPerSample / 8
        pcmFMT.wBlockAlign=channels * bits / 8;  
        pcmFMT.wChannels=channels;  
        pcmFMT.wFormatTag=1;  
     
        fwrite(&pcmFMT,sizeof(WAVE_FMT),1,fpout); 
     
        //WAVE_DATA;
        memcpy(pcmDATA.fccID,"data",strlen("data"));  
        pcmDATA.dwSize=0;
        fseek(fpout,sizeof(WAVE_DATA),SEEK_CUR);
     
        fread(&m_pcmData,sizeof(unsigned short),1,fp);
        while(!feof(fp)){  
            pcmDATA.dwSize+=2;
            fwrite(&m_pcmData,sizeof(unsigned short),1,fpout);
            fread(&m_pcmData,sizeof(unsigned short),1,fp);
        }  
     
        pcmHEADER.dwSize=sizeof(WAVE_FMT) + sizeof(WAVE_DATA) + 4 +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()
    {
        simplest_pcm16le_split("NocturneNo2inEflat_44.1k_s16le.pcm");
    
        simplest_pcm16le_halfvolumeleft("NocturneNo2inEflat_44.1k_s16le.pcm");
    
        simplest_pcm16le_doublespeed("NocturneNo2inEflat_44.1k_s16le.pcm");
    
        simplest_pcm16le_to_pcm8("NocturneNo2inEflat_44.1k_s16le.pcm");
        
        //simplest_pcm16le_cut_singlechannel("drum.pcm",2360,120);
        
        simplest_pcm16le_to_wave("NocturneNo2inEflat_44.1k_s16le.pcm",2,
                                 44100, 16, "output_nocturne.wav");
        return 0;
    }
  • 相关阅读:
    Silverlight实例教程
    c#.net大文件上传(切片)
    ASP.NET大文件上传(切片)
    jsp大文件上传(切片)
    php大文件上传(切片)
    本地图文直接复制到博客编辑器中
    本地图文直接复制到CMS编辑器中
    本地图文直接复制到SiteFactory编辑器中
    本地图文直接复制到动易CMS编辑器中
    本地图文直接复制到帝国CMS编辑器中
  • 原文地址:https://www.cnblogs.com/micoblog/p/13152394.html
Copyright © 2020-2023  润新知