cpp
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#define SAMPLE_RATE 44100 // 采样率
#define AMPLITUDE 32767 // 振幅
#define NO_SAMPLES 44100 // 样本数
// 声明一个结构体用于表示音符
typedef struct {
double frequency; // 频率
double duration; // 持续时间
} note;
// 声明一个函数用于计算给定音符的采样值
int calculate_sample(note n, double time) {
int sample = AMPLITUDE * sin(2 * M_PI * n.frequency * time);
return sample;
}
// 声明一个函数用于播放单个音符
void play_single_note(note n) {
int samples_per_note = SAMPLE_RATE * n.duration; // 计算每个音符的样本数
double time_per_sample = 1.0 / SAMPLE_RATE; // 计算每个样本的时间间隔
// 循环遍历每一个样本并计算采样值,然后将其写入标准输出
for (int i = 0; i < samples_per_note; i++) {
double time = i * time_per_sample;
int sample = calculate_sample(n, time);
putchar(sample & 0xFF);
putchar((sample >> 8) & 0xFF);
}
}
// 声明一个函数用于播放和弦
void play_chord(note* notes, int num_notes) {
int samples_per_chord = SAMPLE_RATE * notes[0].duration; // 计算每个和弦的样本数
double time_per_sample = 1.0 / SAMPLE_RATE; // 计算每个样本的时间间隔
// 循环遍历每一个样本并计算采样值,然后将其写入标准输出
for (int i = 0; i < samples_per_chord; i++) {
double time = i * time_per_sample;
int sample = 0;
// 对于和弦中的每个音符,计算其采样值并将其添加到当前样本上
for (int j = 0; j < num_notes; j++) {
int note_sample = calculate_sample(notes[j], time);
sample += note_sample;
}
// 将样本缩放到正确的振幅范围内并将其写入标准输出
sample /= num_notes;
sample = fmin(sample, AMPLITUDE);
sample = fmax(sample, -AMPLITUDE);
putchar(sample & 0xFF);
putchar((sample >> 8) & 0xFF);
}
}
int main() {
// 声明一些简单的音符
note c = {261.63, 1};
note d = {293.66, 1};
note e = {329.63, 1};
note f = {349.23, 1};
note g = {392.00, 1};
note a = {440.00, 1};
note b = {493.88, 1};
// 播放一些简单的旋律和和弦
play_single_note(c);
play_single_note(d);
play_single_note(e);
play_single_note(f);
play_single_note(g);
play_single_note(a);
play_single_note(b);
note c_chord[] = {c, e, g};
play_chord(c_chord, 3);
note f_chord[] = {f, a, c};
play_chord(f_chord, 3);
// 完成
return 0;
}
该代码使用正弦函数来计算采样值,并使用标准输出来播放音乐。它支持单独播放单个音符和播放和弦。通常,音符和和弦中的每个音符都表示为持续时间和频率的组合。