簡體   English   中英

Stream 正弦波轉 XAudio2

[英]Stream sine wave to XAudio2

我正在嘗試編寫一個通過 XAudio2 播放的非常簡單的正弦波發生器。

目前有聲音播放,如果我調用 Win32XAudioInit() 然后 Win32PlayTone() 會播放一個音調,並且在隨后調用 Win32PlayTone() 時音調會改變,但是幾乎每次音調改變時都會有明顯的點擊。

我知道有幾個原因可能會導致這種情況:

  1. 我沒有跟蹤相位偏移,這意味着新的波會錯位。
  2. 我只是在更新緩沖區指向的 Memory,而不考慮正在播放的內容。

關於#2,我不確定 XAudio 是否希望我創建一個新的 XAUDIO2_BUFFER 並在每次更改音調時重新提交,或者我是否應該以某種方式跟蹤“播放頭”的位置(因為沒有更好的術語) 並且只更新已經播放過的字節。

我知道 #2 是否有問題,如果我修復它我將聽不到我仍然受到問題 #1 的困擾。 我已經通讀了XAudio2 - Play generated sine, when changed frequency click sound ,如果我知道 XAudio2 設置正確,我想我可以找出正弦波問題。

任何想法都會有所幫助,謝謝!

struct win32_audio_buffer
{
    real32 Memory[44100 * 1];  // samples per buffer (44100) * channels 1
    int BytesPerBuffer;
    XAUDIO2_BUFFER XBuffer;
    IXAudio2 *XEngine;
    IXAudio2SourceVoice *SourceVoice;
    WAVEFORMATEX WaveFormat;
};

// NOTE XAUDIO2
internal HRESULT
Win32XAudioInit(win32_audio_buffer *AudioBuffer)
{
    // Initialize a COM:
    HRESULT HRes;
    HRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if(FAILED(HRes)) { return(HRes); }
    
    // Init XAUDIO Engine
    AudioBuffer->XEngine = {};
    if (FAILED(HRes = XAudio2Create(&AudioBuffer->XEngine, 0, XAUDIO2_DEFAULT_PROCESSOR)))
    { return HRes; }
    
    // MASTER VOICE
    IXAudio2MasteringVoice* XAudioMasterVoice = nullptr;
    if (FAILED(HRes = AudioBuffer->XEngine->CreateMasteringVoice(&XAudioMasterVoice)))
    { return HRes; }
    
    AudioBuffer->WaveFormat = {};
    
    //int32 SamplesPerBuffer = 4410;
    int SampleHz = 44100;
    WORD Channels = 1;
    WORD BitsPerChannel = 32; // 4 byte samples
    int32 BufferSize = Channels * BitsPerChannel * SampleHz;
    AudioBuffer->BytesPerBuffer = SampleHz * Channels;
    
    AudioBuffer->WaveFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; // or could use WAVE_FORMAT_PCM WAVE_FORMAT_IEEE_FLOAT
    AudioBuffer->WaveFormat.nChannels = Channels;
    AudioBuffer->WaveFormat.nSamplesPerSec = SampleHz;
    AudioBuffer->WaveFormat.wBitsPerSample = BitsPerChannel; // 32
    AudioBuffer->WaveFormat.nBlockAlign = (Channels * BitsPerChannel) / 8;
    AudioBuffer->WaveFormat.nAvgBytesPerSec = SampleHz * Channels * BitsPerChannel / 8;
    AudioBuffer->WaveFormat.cbSize = 0;    // set to zero for PCM or IEEE float
    
    AudioBuffer->XBuffer.Flags = 0;
    AudioBuffer->XBuffer.AudioBytes = SampleHz * Channels * BitsPerChannel / 8;
    AudioBuffer->XBuffer.PlayBegin = 0;
    AudioBuffer->XBuffer.PlayLength = 0;
    AudioBuffer->XBuffer.LoopBegin = 0;
    AudioBuffer->XBuffer.LoopLength = 0;
    AudioBuffer->XBuffer.LoopCount = XAUDIO2_LOOP_INFINITE;
    AudioBuffer->XBuffer.pContext = NULL;
    AudioBuffer->XBuffer.pAudioData = (BYTE *)&AudioBuffer->Memory;
    
    if(FAILED(HRes = AudioBuffer->XEngine->CreateSourceVoice(&AudioBuffer->SourceVoice, (WAVEFORMATEX*)&AudioBuffer->WaveFormat))) 
    { return HRes; }
    
    if(FAILED(HRes = AudioBuffer->SourceVoice->Start(0)))
    { return HRes; }
    
    if(FAILED(HRes = AudioBuffer->SourceVoice->SubmitSourceBuffer(&AudioBuffer->XBuffer)))
    { return HRes; }
    
    return(S_OK);
}

internal HRESULT
Win32PlayTone(win32_audio_buffer *Buffer, int32 Hz)
{
    real32 PI2 = (real32)6.28318; //530718;
    
    for(int i = 0;
        i < Buffer->BytesPerBuffer;
        i++)
    {
        real32 CurrentSample = sinf(i * PI2 / 44100 * Hz);
        Buffer->Memory[i] = CurrentSample;
    }
    
    return(S_OK);
}

XAudio2 是完全異步的,因此在播放數據包完成之前,您不應更改播放數據包指向的 memory,否則您將獲得您所描述的點擊。

此外,當當前數據包完成時,如果您希望聲音連續,您希望另一個已經排隊。

請參閱以下資源以了解如何對 XAudio2 進行編程:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM