在应用程序和游戏中对声音进行编程时,我经常不得不重写声音模块的整个代码库,因为它们中的许多结构要么太复杂,要么相反,除了简单的播放声音外,无能为力。
与在游戏中渲染图像的类比与声音引擎配合得很好:如果您的管道过于简单且包含大量抽象,则几乎无法编写比带有齿轮的立方体更复杂的东西。另一方面,如果您的整个代码都包含直接的OpenGL或D3D调用,则无法轻松地缩放意大利面条式代码。
比较与图形渲染的相关性如何?
在声音渲染中,与图形渲染中的过程相同:从游戏逻辑更新资源,将数据处理为可消化的形式,后处理,输出最终结果。所有这些可能要花费相当长的时间,因此为了便于说明,我使用音频库来测试渲染性能。
SSD , Opus , , DSP (, ), . , : Inte Core i9 9900 4.5GHz, 32GB RAM, SSD 480GB SATA. 48000 44100.
FRESPONZE_BEGIN_TEST
if (!pFirstListener) return false;
// -
if (RingBuffer.GetLeftBuffers()) return false;
RingBuffer.SetBuffersCount(RING_BUFFERS_COUNT);
RingBuffer.Resize(Frames * Channels);
OutputBuffer.Resize(Frames * Channels);
tempBuffer.Resize(Channels, Frames);
mixBuffer.Resize(Channels, Frames);
for (size_t i = 0; i < RING_BUFFERS_COUNT; i++) {
tempBuffer.Clear();
mixBuffer.Clear();
pListNode = pFirstListener;
while (pListNode) {
/* */
EmittersNode* pEmittersNode = nullptr;
if (!pListNode->pListener) break;
pListNode->pListener->GetFirstEmitter(&pEmittersNode);
while (pEmittersNode) {
tempBuffer.Clear();
pEmittersNode->pEmitter->Process(tempBuffer.GetBuffers(), Frames);
//
for (size_t o = 0; o < Channels; o++) {
MixerAddToBuffer(mixBuffer.GetBufferData((fr_i32)o), tempBuffer.GetBufferData((fr_i32)o), Frames);
}
pEmittersNode = pEmittersNode->pNext;
}
pListNode = pListNode->pNext;
}
/* */
PlanarToLinear(mixBuffer.GetBuffers(), OutputBuffer.Data(), Frames * Channels, Channels);
RingBuffer.PushBuffer(OutputBuffer.Data(), Frames * Channels);
RingBuffer.NextBuffer();
}
FRESPONZE_END_TEST("Audio render")
[00:00:59:703]: 'Audio render' operation passed: 551 microseconds
[00:00:59:797]: 'Audio render' operation passed: 512 microseconds
[00:00:59:906]: 'Audio render' operation passed: 541 microseconds
[00:01:00:000]: 'Audio render' operation passed: 583 microseconds
, , , . , , .
?
, . — -, C++, SoLoud OpenAL. , — . API , OpenAL Wwise.
. — ref_sound
ISoundManager
, , , , , . — , UAudioComponent
Unreal Engine.
void Class::Function()
{
//
snd.play_at_pos(0, Position(), false);
//
if (IsHappened())
{
// ...
}
// ...
}
, — CSoundRender_Target
, API OpenAL DirectSound, CSoundRender_Cache
— Vorbis . target
— , source
+ emitter
.
, Core (FMOD Wwise), API (PortAudio).
,
, — (hardware) (mixer). , , API. .
:
void GameScheduler::Update() {
// ...
// , .
// ,
// .
SoundManager::StopSound(id);
// ...
}
// ...
void AudioHardware::Update() {
// ...
// :
// ,
// .
AudioMixer::Render(input, frames);
memcpy(output, input, frames * channels * frame_size);
// ...
}
- . AudioHardware
PortAudio, Windows Audio Session API. SoundManager
— FMOD Wwise. AudioHardware
, .
: routing
emitters-source
. DAW, , . , side-chain
, . , - .
— emitters-source
. 2 — (source), , , (emitter) — , , -. emitters-source
( Wwise FMOD virtual emitters
), .