PCM 与WAV相互转换代码

最近整理了下wav与pcm相互转换的代码,虽然wav和pcm只是44个字节头的差别,但是实际上写了调试还是花了点时间,代码写完还是会有些没注意到的bug,这也许就是纸上谈兵和实践的差别吧,代码还是要多码一下,简单的过程也可能会出错;
当然调试也是有收获的,我发现wav文件头除了基本的44个字节,还可能有别的信息,具体还不知道代码啥意思,感觉和音频播放没关系,该部分是在data 和data长度的信息之前,感觉类似对文件做出的标记,去掉了之后再将pcm转成wav也是能正常播放的;

下面是wav转pcm的代码

pragma warning (disable :4996)

define uint32_t unsigned int

define uint16_t unsigned short

typedef struct _riff_t {
char riff[4]; /* “RIFF” (ASCII characters) */
uint32_t len; /* Length of package (binary, little endian) */
char wave[4]; /* “WAVE” (ASCII characters) */
} riff_t;

/* The FORMAT chunk */

typedef struct _format_t {
char fmt[4]; /* “fmt_” (ASCII characters) */
uint32_t len; /* length of FORMAT chunk (always 0x10) */
uint16_t type; /* codec type*/
uint16_t channel; /* Channel numbers (0x01 = mono, 0x02 = stereo) */
uint32_t rate; /* Sample rate (binary, in Hz) */
uint32_t bps; /* Average Bytes Per Second */
uint16_t blockalign; /number of bytes per sample /
uint16_t bitpspl; /* bits per sample */
} format_t;

typedef struct _data_t {
char data[4]; /* “data” (ASCII characters) */
uint32_t len; /* length of data */
}data_t;

typedef struct _wav_head
{
riff_t riff;
format_t format;
data_t data;
}wav_head;

int main(int argc, char **argv)
{
//char *src_file = “aa.wav”;
char *src_file = “aa.wav”;

uint32_t pcm_data_size = 0;
int pcm_channel = 0;
int pcm_samplerate = 0;

//以下是为了建立.wav头而准备的变量    
wav_head header;
FILE   *fp=NULL, *fpCpy=NULL;

int flen;



if ((fp = fopen(src_file, "rb")) == NULL) //读取文件    
{
    printf("open pcm file %s error\n", argv[1]);
    return -1;
}


//简单粗暴方式
//if ((flen=fread(&header,1,44,fp))!=44) 
//{
//  goto error;
//}

if ((flen = fread(&header.riff.riff, 1, 4, fp)) != 4)
    goto error;

if (memcmp(&header.riff.riff, "RIFF", 4))
    goto error;

if ((flen = fread(&header.riff.len, 1, 4, fp)) != 4)
    goto error;

//pcm_data_size = header.riff.len - 36;

if ((flen = fread(&header.riff.wave, 1, 4, fp)) != 4)
    goto error;

if (memcmp(&header.riff.wave, "WAVE", 4))
    goto error;

if ((flen = fread(&header.format.fmt, 1, 4, fp)) != 4)
    goto error;

if (memcmp(&header.format.fmt, "fmt ", 4))
    goto error;

if ((flen = fread(&header.format.len, 1, 4, fp)) != 4)
{
    goto error;
}
if (header.format.len!=0x10)
{
    printf("header.format.len!=0x10 :value:%d\n", header.format.len);
}
if ((flen = fread(&header.format.type, 1, 2, fp)) != 2)
{
    goto error;
}
if (header.format.type != 0x1)
{
    printf("header.format.type != 0x1 :value:%d\n", header.format.type);
}
if ((flen = fread(&header.format.channel, 1, 2, fp)) != 2)
{
    goto error;
}
pcm_channel = header.format.channel;

if ((flen = fread(&header.format.rate, 1, 4, fp)) != 4)
{
    goto error;
}
pcm_samplerate = header.format.rate;

if ((flen = fread(&header.format.bps, 1, 4, fp)) != 4)
{
    goto error;
}

if ((flen = fread(&header.format.blockalign, 1, 2, fp)) != 2)
{
    goto error;
}

if ((flen = fread(&header.format.bitpspl, 1, 2, fp)) != 2)
{
    goto error;
}

int p = 0;
//后面的结构可能不是直接为“data”
do {
    if ((flen = fread(&header.data.data, 1, 4, fp)) != 4)
    {
        goto error;
    }
    if (memcmp(&header.data.data, "data", 4) == 0)
    {
        printf("find data chunk.");
        if ((flen = fread(&header.data.len, 1, 4, fp)) != 4)
        {
            goto error;
        }
        pcm_data_size = header.data.len;
        break;
    }
    else
        p += 4;

} while (!feof(fp));


printf("解析成功,二个PCM数据长度分别为:%d, %d\n", pcm_data_size, header.riff.len - 36);

int otherdataSize = header.riff.len - 36 - pcm_data_size;
if (otherdataSize>0)
{
    printf("多余的数据部分大小:%d , %d", p, otherdataSize);

    char *otherdata = (char *)malloc(otherdataSize + 1);
    memset(otherdata, 0, otherdataSize + 1);
    fseek(fp, -otherdataSize - 8, SEEK_CUR);
    fread(otherdata, 1, otherdataSize, fp);
    *(otherdata + otherdataSize) = '\0';

    fseek(fp, 8, SEEK_CUR);

    printf("other data:%s", otherdata);
}
fseek(fp, otherdataSize + 44, SEEK_SET);

//fseek(fp, 0, SEEK_CUR);

unsigned char *buffer = (unsigned char*)malloc((pcm_data_size) * sizeof(char));

memset(buffer, 0, pcm_data_size);


int count1= fread(buffer, 1, pcm_data_size, fp);


char output[1024] = { 0 };
sprintf(output, "%d_%d_.pcm", pcm_samplerate, pcm_channel);

if ((fpCpy = fopen(output, "wb+")))
{
    //fwrite(buffer, 1, sizeof(buffer), fpCpy);  写了段常犯错的代码
    fwrite(buffer, 1, pcm_data_size, fpCpy);
}
else
    goto error;


free(buffer);
fclose(fp); //关闭文件    
fclose(fpCpy);   //关闭文件    

return 0;

error :
if (fp)
{
fclose(fp);
}
if (fpCpy)
{
fclose(fpCpy);
}
return -1;
}

需要整个wav转pcm以及pcm转wav的项目的可以去该链接下载:
https://download.csdn.net/download/liuliu0322/10312627

你可能感兴趣的:(C)