サウンドエンジンを開発しない方法



アプリケーションやゲームでサウンドをプログラミングするとき、サウンドモジュールのコードベース全体を書き直さなければならないことがよくありました。それらの多くはアーキテクチャが複雑すぎるか、逆に単純なサウンドの再生以外は何もできなかったためです。



ゲームで画像をレンダリングすることとの類似性は、サウンドエンジンでうまく機能します。多数の抽象化を伴う単純すぎるパイプラインがある場合、ギアを備えたキューブよりも複雑なものを適切にプログラムすることはほとんどできません。一方、コード全体が直接の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