如何不开发声音引擎



在应用程序和游戏中对声音进行编程时,我经常不得不重写声音模块的整个代码库,因为它们中的许多结构要么太复杂,要么相反,除了简单的播放声音外,无能为力。



与在游戏中渲染图像的类比与声音引擎配合得很好:如果您的管道过于简单且包含大量抽象,则几乎无法编写比带有齿轮的立方体更复杂的东西。另一方面,如果您的整个代码都包含直接的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), .



emitters-source . miniaudio, .




All Articles