[toc]

使用C语言在Windows中创建WAV格式的音频文件

1. 创建WAV格式的音频文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

#define SAMPLE_RATE 44100
#define DURATION 0.1 // 每个音符的持续时间(秒)
#define AMPLITUDE 32767 // 最大振幅(16位音频)

// 定义 M_PI
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

// 音符频率(C4, D4, E4, F4, G4, A4, B4, C5)
double frequencies[] = { 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25 };

// WAV 文件头结构
typedef struct {
char riff[4]; // "RIFF"
uint32_t overall_size; // 文件总大小
char wave[4]; // "WAVE"
char fmt_chunk_marker[4]; // "fmt "
uint32_t length_of_fmt; // 4
uint16_t format_type; // 1
uint16_t channels; // 1
uint32_t sample_rate; // 44100
uint32_t byterate; // SampleRate * NumChannels * BitsPerSample/8
uint16_t block_align; // NumChannels * BitsPerSample/8
uint16_t bits_per_sample; // 16
char data_chunk_header[4]; // "data"
uint32_t data_size; // 采样数据大小
} WavHeader;

void writeWavHeader(FILE* file, int dataSize) {
WavHeader header;
memcpy(header.riff, "RIFF", 4);
header.overall_size = 36 + dataSize; // 36 + Subchunk2Size
memcpy(header.wave, "WAVE", 4);
memcpy(header.fmt_chunk_marker, "fmt ", 4);
header.length_of_fmt = 16; // 16 for PCM
header.format_type = 1; // PCM
header.channels = 1; // 单声道
header.sample_rate = SAMPLE_RATE; // 44.1kHz
header.byterate = SAMPLE_RATE * header.channels * (16 / 8);
header.block_align = header.channels * (16 / 8);
header.bits_per_sample = 16; // 16位
memcpy(header.data_chunk_header, "data", 4);
header.data_size = dataSize;

fwrite(&header, sizeof(WavHeader), 1, file);
}

void generateTone(FILE* file, double frequency) {
int numSamples = (int)(SAMPLE_RATE * DURATION);
for (int i = 0; i < numSamples; i++) {
double sample = AMPLITUDE * sin(2.0 * M_PI * frequency * ((double)i / SAMPLE_RATE));
int16_t sampleValue = (int16_t)sample;
fwrite(&sampleValue, sizeof(int16_t), 1, file);
}
}

int main() {
FILE* file = fopen("notes.wav", "wb");
if (!file) {
printf("无法创建文件\n");
return 1;
}

// 生成音符
for (int i = 0; i < 8; i++) {
generateTone(file, frequencies[i]);
}

// 写入 WAV 文件头
fseek(file, 0, SEEK_END);
int dataSize = ftell(file) - sizeof(WavHeader);
fseek(file, 0, SEEK_SET);
writeWavHeader(file, dataSize);

fclose(file);
printf("WAV 文件已生成:notes.wav\n");
return 0;
}