C语言编写程序将多个wav文件拼接成一个音频wav文件并播放

播放单个的我会,但怎么将几个合并成一个呢,不是连续播放而是合成一个wav。... 播放单个的我会,但怎么将几个合并成一个呢,不是连续播放而是合成一个wav。 展开
 我来答
478617
2015-01-26 · TA获得超过875个赞
知道小有建树答主
回答量:725
采纳率:100%
帮助的人:92.3万
展开全部
#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;
}
更多追问追答
追问
为什么我打出来是数据错误呢?那两个文件的路径和名称是不是直接填在打开函数的,1 和2位置上?3那里还是留着3.wav吗
追答
这个文件名改成你要很成文件的名字,3是合成后文件
多个Wave ,一个一个的合成就可以了

要不然就是你的Wav文件不是最基本的wav格式
数据错误,说明不是标准的Wav文件
来自:求助得到的回答
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式