C语言编写程序将多个wav文件拼接成一个音频wav文件并播放
发布网友
发布时间:2022-04-23 04:00
我来回答
共1个回答
热心网友
时间:2022-04-27 07:08
#include <stdio.h>
#include <string.h>
#define RIFF_SIGN_ID 0x46464952ul
#define WAVE_SIGN_ID 0x45564157ul
#define FMT__SIGN_ID 0x20746D66ul
#define FACT_SIGN_ID 0x74636166ul
#define DATA_SIGN_ID 0x61746164ul
#ifndef DWORD
typedef unsigned long DWORD;
#endif
#ifndef WORD
typedef unsigned short WORD;
#endif
#ifndef BYTE
typedef unsigned char BYTE;
#endif
struct RIFF_HEADER
{
DWORD RiffID; // 资源交换文件标志 0x46464952 'R','I','F','F'
DWORD RiffSize; // 从下个地址开始到文件尾的总字节数
DWORD RiffFormat; // WAV文件标志 0x45564157 'W','A','V','E'
};
struct WAVE_FORMAT
{
WORD FormatTag; // 格式种类(值为1时,表示数据为线性PCM编码)
WORD Channels; // 通道数,单声道为1,双声道为2
DWORD SamplesPerSec; // 采样频率
DWORD AvgBytesPerSec; // 每秒所需字节数
WORD BlockAlign; // 数据块对齐单位(每个采样需要的字节数)
WORD BitsPerSample; // 每个采样需要的bit数
WORD otherInfo; // 附加信息(可选,通过Size来判断有无)
};
struct FMT_BLOCK
{
DWORD FmtID; // 波形格式标志 0x20746D66 'f','m','t',' '
DWORD FmtSize; // 波形格式部分长度(一般为00000010H)
WAVE_FORMAT wavFormat; // 波形数据格式
};
struct UNKNOW_BLOCK
{
DWORD ID; // 未知块
DWORD Size; // 未知块长度
};
struct FACT_BLOCK
{
DWORD FactID; // 可选部分标识 0x74636166 'f','a','c','t'
DWORD FactSize; // 可选部分长度
BYTE Data[1]; // 可选部分数据
};
struct DATA_BLOCK
{
DWORD DataID; // 数据标志符 0x61746164, 'd','a','t','a'
DWORD DataSize; // DATA总数据长度字节
BYTE Data[1]; // 数据
};
BYTE * openWaveFile(const char *name);
BYTE * getWaveData(BYTE * wav, int * dLen);
void printWaveFormat(BYTE * wav);
int saveWaveFile(const char * name, BYTE * wav);
BYTE * catWave(BYTE *& wav1, BYTE *& wav2);
size_t getTotalLen(BYTE * wav);
int main(int argc, char* argv[])
{
int dLen;
BYTE * data1 = openWaveFile("1.wav");
printWaveFormat(data1);
BYTE * data2 = openWaveFile("2.wav");
printWaveFormat(data2);
data1 = catWave(data1, data2);
printWaveFormat(data1);
saveWaveFile("3.wav", data1);
return 0;
}
BYTE * openWaveFile(const char *name)
{
size_t readByte;
FILE * fp = fopen(name, "rb");
if(fp==NULL) return NULL;
RIFF_HEADER fh;
if(fread(&fh, sizeof(fh), 1, fp) != 1)
{
fclose(fp);
printf("Riff Header 文件长度错误\n");
return NULL;
}
if(fh.RiffFormat != WAVE_SIGN_ID || fh.RiffID != RIFF_SIGN_ID)
{
fclose(fp);
printf("文件标识符错误 ID:%08X Format:%08X\n", fh.RiffID, fh.RiffFormat);
return NULL;
}
BYTE * r = new BYTE[fh.RiffSize + 10], *pr;
if(r==NULL)
{
fclose(fp);
printf("内存申请错误\n");
return NULL;
}
readByte = fread(r, 1, fh.RiffSize-4, fp);
if(readByte != fh.RiffSize-4)
{
delete [] r;
printf("wave 文件长度错误 %d %d\n", readByte, fh.RiffSize);
return NULL;
}
fclose(fp);
FMT_BLOCK *fb = (FMT_BLOCK *)r;
if(fb->FmtID != FMT__SIGN_ID)
{
printf("格式标识符错误或格式大小错误ID:%08X\n", fb->FmtID);
delete [] r;
return NULL;
}
if(fb->wavFormat.FormatTag != 1)
{
delete [] r;
printf("不支持的格式 Format:%d\n", fb->wavFormat.FormatTag);
return NULL;
}
pr = r + 8 + fb->FmtSize;
while(1)
{
UNKNOW_BLOCK * ub = (UNKNOW_BLOCK *)pr;
if(ub->ID == FACT_SIGN_ID)
{
printf("Fact 标签 length: %d\n", ub->Size);
pr += 8 + ub->Size ;
}
else break;
}
DATA_BLOCK * db = (DATA_BLOCK *)pr;
if(db->DataID != DATA_SIGN_ID)
{
delete [] r;
printf("数据错误\n");
return NULL;
}
return r;
}
BYTE * getWaveData(BYTE * wav, int * dLen)
{
UNKNOW_BLOCK * ub = (UNKNOW_BLOCK *)wav;
while(ub->ID != DATA_SIGN_ID)
{
switch(ub->ID)
{
case DATA_SIGN_ID:
break;
case FMT__SIGN_ID:
case FACT_SIGN_ID:
ub = (UNKNOW_BLOCK *)(((BYTE *)ub) + ub->Size + 8);
break;
default:
printf("错误标签 %08X\n", ub->ID );
return NULL;
}
}
DATA_BLOCK * db = (DATA_BLOCK *)ub;
*dLen = db->DataSize;
return db->Data;
}
size_t getTotalLen(BYTE * wav)
{
size_t r = 0;
UNKNOW_BLOCK * ub = (UNKNOW_BLOCK *)wav;
while(1)
{
switch(ub->ID)
{
case DATA_SIGN_ID:
r += ub->Size + 8;
return r;
case FMT__SIGN_ID:
case FACT_SIGN_ID:
r += ub->Size + 8;
ub = (UNKNOW_BLOCK *)(((BYTE *)ub) + ub->Size + 8);
break;
default:
printf("错误标签 %08X\n", ub->ID );
return NULL;
}
}
return -1;
}
void printWaveFormat(BYTE * wav)
{
int len;
getWaveData(wav, &len);
FMT_BLOCK *fb = (FMT_BLOCK *)wav;
printf("Wave 格式:PCM\n");
printf("通道数量:%d\n", fb->wavFormat.Channels );
printf("采样频率:%dHz\n", fb->wavFormat.SamplesPerSec );
printf("每秒所需字节数:%d字节\n", fb->wavFormat.AvgBytesPerSec );
printf("数据块对齐单位:%d字节\n", fb->wavFormat.BlockAlign );
printf("每个采样需要的bit数:%dbit\n", fb->wavFormat.BitsPerSample );
printf("长度:%.2f 秒\n", (double)len / fb->wavFormat.AvgBytesPerSec);
}
BYTE * catWave(BYTE *& wav1, BYTE *& wav2)
{
FMT_BLOCK * fb1 = (FMT_BLOCK *)wav2;
const FMT_BLOCK * fb2 = (const FMT_BLOCK *)wav2;
if(
fb1->wavFormat.AvgBytesPerSec == fb2->wavFormat.AvgBytesPerSec &&
fb1->wavFormat.BitsPerSample == fb2->wavFormat.BitsPerSample &&
fb1->wavFormat.BlockAlign == fb2->wavFormat.BlockAlign &&
fb1->wavFormat.Channels == fb2->wavFormat.Channels &&
fb1->wavFormat.FormatTag == fb2->wavFormat.FormatTag &&
fb1->wavFormat.SamplesPerSec == fb2->wavFormat.SamplesPerSec)
{
int len1 = getTotalLen(wav1), len2;
BYTE * Data2 = getWaveData(wav2, &len2);
BYTE * nD = new BYTE[len1 + len2 + 10];
if(nD == NULL) return NULL;
memcpy(nD, wav1, len1);
delete [] wav1;
wav1 = nD;
BYTE * Data1 = getWaveData(wav1, &len1);
DATA_BLOCK * db1 = (DATA_BLOCK *)(Data1 - 8);
db1->DataSize += len2;
memcpy(Data1 + len1, Data2, len2);
return wav1;
}
return NULL;
}
int saveWaveFile(const char * name, BYTE * wav)
{
FILE *fp = fopen(name, "wb");
if(fp == 0) return 0;
int len = getTotalLen(wav);
RIFF_HEADER rh;
rh.RiffFormat = WAVE_SIGN_ID;
rh.RiffID = RIFF_SIGN_ID;
rh.RiffSize = len + 4;
fwrite(&rh, sizeof(rh), 1, fp);
fwrite(wav, 1, len, fp);
fclose(fp);
return 1;
}