概述
(本文中的代码在VS2022中编译通过)
简单地实现一个给PCM编码加上WAV头的东西
(提前声明一下)
// 这是输入,输出和配置
FILE* in, * out, * conf;
// 缓冲区长度
unsigned char buffer[1048576];
首先,获取文件长度
// unsigned int i;
fseek(in, 0, SEEK_END);
i = ftell(in);
fseek(in, 0, SEEK_SET);
写入RIFF标识
fwrite("RIFF", 1, 4, out);
RIFF块的数据长度,即WAV文件大小减8
(就是将所以子块的长度加上"WAVE"四个字节)
SIGN是我自定义的子块,实际不需要
c = /*fmt*/(16 + 8) +/*data*/(8 + i) +
/*Sign*/+(8 + sign_size) +/*WAVE*/4;
fwrite(&c, 4, 1, out);
fwrite("WAVEfmt ", 1, 8, out);
按顺序写入fmt子块
c = 16;
fwrite(&c, 4, 1, out);
// Format
//编码格式,1 是PCM编码
fwrite(&AudioFormat, 2, 1, out);
//声道数
fwrite(&NumChannels, 2, 1, out);
//采样率
fwrite(&SampleRate, 4, 1, out);
//(每秒的字节数)
ByteRate = SampleRate * NumChannels * BitPerSample / 8;
fwrite(&ByteRate, 4, 1, out);
//对齐字节数,即一次采样所占用的字节数
BlockAlign = NumChannels * BitPerSample / 8;
fwrite(&BlockAlign, 2, 1, out);
//采样深度
fwrite(&BitPerSample, 2, 1, out);
我发现只要添加的子块正确,即
{子块标识符,子块数据大小,子块数据},
WAV应该还是可以播放的?
所以我添加了SIGN子块
// Sign
fwrite("SIGN", 1, 4, out);
fwrite(&sign_size, 4, 1, out);
fwrite(sign, 1, sign_size, out);
data子块,即声音数据
//Data
fwrite("data", 1, 4, out);
fwrite(&i, 4, 1, out);
do {
c = fread(buffer, 1, 1048576, in);
fwrite(buffer, 1, c, out);
} while (c);
关于自定义子块
子块的定义
typedef struct _SubChunk{
// 子块ID
unsigned char m_id[4];
// 子块数据大小
unsigned int m_size;
// 数据
unsigned char *dat;
} SubChunk,*rSubChunk
注意,自定义子块的ID不能与特殊的ID重复
LIST块用于存储歌曲信息,如歌手等,这是一个可以包含子块的块,
它被包含于RIFF块
项目代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
unsigned char buffer[1048576];
FILE* in, * out, * conf;
char config[256];
char sign[256];
int main(int count, char* strings[]) {
unsigned int SampleRate=64000;
unsigned short int NumChannels=1;
unsigned short int BitPerSample=8;
unsigned int ByteRate;
unsigned short BlockAlign;
unsigned short AudioFormat = 1;
unsigned int c;
char get;
unsigned int i;
unsigned int sign_size;
puts("Hanako - Wav Head Writer");
if (count == 4) {
in = fopen(strings[1], "rb");
conf = fopen(strings[3], "r");
}
else {
puts("wav-headwriter <input-file> <output-file> <config-file>");
return -2;
}
if (in == NULL || conf == NULL) {
puts("Cannot open file.");
if (in)fclose(in);
if (conf)fclose(conf);
return -1;
}
out = fopen(strings[2], "wb");
do {
memset(config, 0, 256);
for (i = 0; i < 255; i++) {
config[i] = fgetc(conf);
if (config[i] == EOF || config[i] == 'n') {
config[i] = 0;
break;
}
}
if (i >= 255)while (fgetc(conf) == 'n' || fgetc(conf) == EOF);
sscanf(config, "WAV.SampleRate=%u", &SampleRate);
sscanf(config, "WAV.NumChannels=%hu", &NumChannels);
sscanf(config, "WAV.BitPerSample=%hu", &BitPerSample);
sscanf(config, "WAV.Signature=%s", sign);
} while (feof(conf)==0);
printf("SampleRate:%unNumChannels:%hunBitPerSample:%hunn", SampleRate, NumChannels, BitPerSample);
printf("Signature:%snn", sign);
sign_size = strlen(sign);
fseek(in, 0, SEEK_END);
i = ftell(in);
fseek(in, 0, SEEK_SET);
c = /*fmt*/(16 + 8) +/*data*/(8 + i) +/*Sign*/+(8 + sign_size) +/*WAVE*/4;
// RIFF
fwrite("RIFF", 1, 4, out);
fwrite(&c, 4, 1, out);
fwrite("WAVEfmt ", 1, 8, out);
c = 16;
fwrite(&c, 4, 1, out);
// Format
fwrite(&AudioFormat, 2, 1, out);
fwrite(&NumChannels, 2, 1, out);
fwrite(&SampleRate, 4, 1, out);
ByteRate = SampleRate * NumChannels * BitPerSample / 8;
fwrite(&ByteRate, 4, 1, out);
BlockAlign = NumChannels * BitPerSample / 8;
fwrite(&BlockAlign, 2, 1, out);
fwrite(&BitPerSample, 2, 1, out);
// Sign
fwrite("SIGN", 1, 4, out);
fwrite(&sign_size, 4, 1, out);
fwrite(sign, 1, sign_size, out);
//Data
fwrite("data", 1, 4, out);
fwrite(&i, 4, 1, out);
do {
c = fread(buffer, 1, 1048576, in);
fwrite(buffer, 1, c, out);
} while (c);
if (in)fclose(in);
if (conf)fclose(conf);
if (out)fclose(out);
return 0;
}
忘记写注释了呐
BLOG #1
最后
以上就是矮小雪碧为你收集整理的#1 给PCM编码加上WAV头的全部内容,希望文章能够帮你解决#1 给PCM编码加上WAV头所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复