英文:
How do I write a wav file in C?
问题
我试图在C中编写一个wav文件,但是audacity或者vlc无法识别该文件。
我知道一些头部数据是大端序的,但我不确定在C中编写二进制文件时如何确定这一点。我认为这可能是问题所在。
我参考了这些网站:
https://www.videoproc.com/resource/wav-file.htm,
https://docs.fileformat.com/audio/wav/
当前代码没有任何错误,但创建的wav文件无法识别。
wav规格:
16位,
96kHz,
2通道
英文:
I'm trying to write a wav file in C but the file is not recognized by audacity or vlc.
I know that some of the header data is big endian and I'm not sure how to determine that when writing a binary file in C. I think this is probably the issue.
I'm going off of these sites:
https://www.videoproc.com/resource/wav-file.htm,
https://docs.fileformat.com/audio/wav/
The current code doesn't have any errors but the wav file it creates isn't recognized.
wav specs:
16bit,
96kHz,
2 channel
// Writes data to wav file
FILE *fp = fopen("output/video_signal.wav", "w");
if (fp == NULL)
{
printf("Output file couldn't be opened!\n");
return 4;
}
int16_t byte;
uint32_t length = 160+(4800*frame_count);
float multiplier = 32767 / sync_level; // scales signal to use full 16bit resolution
//// WAVE Header Data
unsigned char riff[] = {'R', 'I', 'F', 'F'};
fwrite(&riff, 1, 4, fp);
uint32_t file_size = length + 44;
fwrite(&file_size, 4, 1, fp); // Overall file size
unsigned char wave[] = {'W', 'A', 'V', 'E'};
fwrite(&wave, 1, 4, fp);
unsigned char fmt[] = {'f', 'm', 't'}; // ?
fwrite(&fmt, 1, 4, fp);
uint32_t fmt_length = 16; // ?
fwrite(&fmt_length, 4, 1, fp);
uint16_t fmt_type = 1; // 1 = PCM
fwrite(&fmt_type, 2, 1, fp);
uint16_t chan_num = 2; // Number of channels
fwrite(&chan_num, 2, 1, fp);
uint32_t rate = 96000; // Sample rate
fwrite(&rate, 4, 1, fp);
uint32_t funny_number = rate * 16 * chan_num; // (Sample Rate * BitsPerSample * Channels) / 8
fwrite(&funny_number, 4, 1, fp);
uint16_t another_format = 4; // 4 = 16bit stereo
fwrite(&another_format, 2, 1, fp);
uint16_t bits = 16; // Bit depth / Bits per sample
fwrite(&bits, 2, 1, fp);
unsigned char data_start[] = {'d', 'a', 't', 'a'}; // Marks the start of the data
fwrite(&data_start, 1, 4, fp);
fwrite(&length, 4, 1, fp); // Data size
for (int i = 0; i < length; i++)
{
byte = (channel1[i] * multiplier);
fwrite(&byte, 2, 1, fp);
byte = (channel2[i] * multiplier);
fwrite(&byte, 2, 1, fp);
}
fclose(fp);
答案1
得分: 2
这是您的代码的修改版本,用于生成一秒钟的白噪声:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main()
{
uint32_t duration = 1;
uint32_t rate = 96000; // 采样率
uint32_t frame_count = duration * rate;
uint16_t chan_num = 2; // 通道数
uint16_t bits = 16; // 位深度
uint32_t length = frame_count * chan_num * bits / 8;
int16_t byte;
float sync_level = 1.0;
// 将信号缩放以使用完整的16位分辨率
float multiplier = 32767 / sync_level;
float *channel1 = (float *) malloc(frame_count * sizeof(float));
float *channel2 = (float *) malloc(frame_count * sizeof(float));
for (uint32_t i=0; i < frame_count; i++) {
channel1[i] = (float) (rand() - RAND_MAX / 2) / RAND_MAX;
channel2[i] = (float) (rand() - RAND_MAX / 2) / RAND_MAX;
}
// 将数据写入WAV文件
FILE *fp = fopen("video_signal.wav", "w");
if (fp == NULL)
{
printf("无法打开输出文件!\n");
return 4;
}
//// WAVE头数据
fwrite("RIFF", 1, 4, fp);
uint32_t chunk_size = length + 44 - 8;
fwrite(&chunk_size, 4, 1, fp);
fwrite("WAVE", 1, 4, fp);
fwrite("fmt ", 1, 4, fp); // 注意此处末尾有空格
uint32_t subchunk1_size = 16;
fwrite(&subchunk1_size, 4, 1, fp);
uint16_t fmt_type = 1; // 1 = PCM
fwrite(&fmt_type, 2, 1, fp);
fwrite(&chan_num, 2, 1, fp);
fwrite(&rate, 4, 1, fp);
// (采样率 * 每样本位数 * 通道数) / 8
uint32_t byte_rate = rate * bits * chan_num / 8;
fwrite(&byte_rate, 4, 1, fp);
uint16_t block_align = chan_num * bits / 8;
fwrite(&block_align, 2, 1, fp);
fwrite(&bits, 2, 1, fp);
// 标记数据的开始
fwrite("data", 1, 4, fp);
fwrite(&length, 4, 1, fp); // 数据大小
for (uint32_t i = 0; i < frame_count; i++)
{
byte = (channel1[i] * multiplier);
fwrite(&byte, 2, 1, fp);
byte = (channel2[i] * multiplier);
fwrite(&byte, 2, 1, fp);
}
fclose(fp);
free(channel1);
free(channel2);
return 0;
}
您的代码中存在一些问题:
- 奇怪的数字没有除以8
- "fmt "标记末尾的空格缺失
- 长度计算与数据大小不符合
英文:
Here is a modified version of your code that generates one second of white noise:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main()
{
uint32_t duration = 1;
uint32_t rate = 96000; // Sample rate
uint32_t frame_count = duration * rate;
uint16_t chan_num = 2; // Number of channels
uint16_t bits = 16; // Bit depth
uint32_t length = frame_count*chan_num*bits / 8;
int16_t byte;
float sync_level = 1.0;
// scales signal to use full 16bit resolution
float multiplier = 32767 / sync_level;
float *channel1 = (float *) malloc(frame_count * sizeof(float));
float *channel2 = (float *) malloc(frame_count * sizeof(float));
for (uint32_t i=0; i < frame_count; i++) {
channel1[i] = (float) (rand() - RAND_MAX / 2) / RAND_MAX;
channel2[i] = (float) (rand() - RAND_MAX / 2) / RAND_MAX;
}
// Writes data to wav file
FILE *fp = fopen("video_signal.wav", "w");
if (fp == NULL)
{
printf("Output file couldn't be opened!\n");
return 4;
}
//// WAVE Header Data
fwrite("RIFF", 1, 4, fp);
uint32_t chunk_size = length + 44 - 8;
fwrite(&chunk_size, 4, 1, fp);
fwrite("WAVE", 1, 4, fp);
fwrite("fmt ", 1, 4, fp);
uint32_t subchunk1_size = 16;
fwrite(&subchunk1_size, 4, 1, fp);
uint16_t fmt_type = 1; // 1 = PCM
fwrite(&fmt_type, 2, 1, fp);
fwrite(&chan_num, 2, 1, fp);
fwrite(&rate, 4, 1, fp);
// (Sample Rate * BitsPerSample * Channels) / 8
uint32_t byte_rate = rate * bits * chan_num / 8;
fwrite(&byte_rate, 4, 1, fp);
uint16_t block_align = chan_num * bits / 8;
fwrite(&block_align, 2, 1, fp);
fwrite(&bits, 2, 1, fp);
// Marks the start of the data
fwrite("data", 1, 4, fp);
fwrite(&length, 4, 1, fp); // Data size
for (uint32_t i = 0; i < frame_count; i++)
{
byte = (channel1[i] * multiplier);
fwrite(&byte, 2, 1, fp);
byte = (channel2[i] * multiplier);
fwrite(&byte, 2, 1, fp);
}
fclose(fp);
free(channel1);
free(channel2);
return 0;
}
There were a few problems in your code:
- the funny number was missing dividing by 8
- the "fmt " mark was missing the space at the end
- the length calculation didn't correspond to the data size
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论