我正在为C中的复古游戏开发引擎。我正在寻找一个声音库,该声音库可以从代码中产生芯片声音...我想为引擎创建自己的简单Chiptune跟踪器,以创建音乐。这样的事情存在吗?
我也对在项目中使用.nsf文件的库感兴趣。
我正在使用Linux进行开发。
我正在为C中的复古游戏开发引擎。我正在寻找一个声音库,该声音库可以从代码中产生芯片声音...我想为引擎创建自己的简单Chiptune跟踪器,以创建音乐。这样的事情存在吗?
我也对在项目中使用.nsf文件的库感兴趣。
我正在使用Linux进行开发。
Answers:
当然可以,让它听起来“不错”并不是一件容易的事。
我不知道如何在Linux中执行此操作,但是如果您可以播放PCM缓冲区,那么您所需要做的就是将其填充为所需的内容。
因此,假设您的缓冲区设置为以每秒44100个样本的速度在单声道,带符号的16位样本中播放,那么创建纯净(正弦)A4声音(440 Hz)非常简单
int16_t buffer[44100];
float frequency = 440.0f;
float sampling_ratio = 44100.0f;
float amplitude = 0.5f;
float t;
for (int i = 0; i < 44100; i++)
{
float theta = ((float)i / sampling_ratio) * PI;
buffer[i] = (int16_t)(sin(theta * frequency) * 32767.0f * amplitude);
}
但是,这种声音可能对您的兴趣非常沉闷,因此您必须做一些更复杂的事情。通常,声音合成有两种类型:加性和减性。还有很多,但是这两个可能是最简单的。今天,我将讨论加法合成。
对于加法合成,您执行的操作与我刚才所做的相同,但是您不只是使用一个频率的一个振幅,而是将多个波加在一起。就像同时按下钢琴上的几个键一样。因此,您将代码修改为如下所示:
void add_sine_wave(int16_t* buffer, int buffer_length, float frequency, float sampling_ratio, float amplitude)
{
for (int i = 0; i < buffer_length; i++)
{
float theta = ((float)i / sampling_ratio) * M_PI;
// make sure to correct for overflows and underflows
buffer[i] += (int16_t)(sin(theta * frequency) * 32767.0f * amplitude);
}
}
然后像这样使用它:
int16_t buffer[44100];
memset(buffer, 0, sizeof(buffer));
// Create an A Major chord
add_sine_wave(buffer, 44100, 440.0f, 44100.0f, 0.5f);
add_sine_wave(buffer, 44100, 554.37f, 44100.0f, 0.5f);
add_sine_wave(buffer, 44100, 659.26f, 44100.0f, 0.5f);
顺便说一句,我是从得到我的频率这里(我使用的是相同的气质,但也有很多 的 其他可用调音)。
请注意,到目前为止,我只是一直在使用正弦波,但老合成器还支持方形,三角形和锯齿波为好,每一个都有自己有趣的声音特性。实现这些非常简单。
您可以做的其他事情可以增加声音的多样性:
这里的要点是这些技术本身并不是很困难,因此您实际上并不需要一个库来为您抽象它们。使用它们来创建有趣的声音是困难的。
最后一点。在尝试这样的声音时,将数据保存到WAV文件,然后在诸如Audacity之类的某些软件中进行可视化可能非常有用。这样,您可以更清楚地看到自己在做什么。
short
之前,请确保该值适合short
。
对于Chiptune音效,有一个明确的答案:sfxr。
它是一个独立的应用程序,可用于生成示例,但如果要将其集成到代码中,也可以使用源代码。
我可以亲自推荐Blargg的音频库。您可能特别感兴趣的是他的Blip_Buffer。
Blargg的站点上有几个“复古”音频合成器,我正在积极使用他的Game_Music_Emu在我正在编写的《洛克人》克隆中播放NSF文件。
许多库都是用C ++编写的,但是有些库也提供C接口。