Поделиться через


Простой проект XAudio2 полностью

В предыдущих разделах показано, как инициализировать XAudio2, загрузить данные в звуковой буфер, а затем воспроизвести этот звук с помощью голосов XAudio2. В этом разделе показано, как объединить все шаги в один, работоспособный пример кода C++/WinRT, который создает очень простое приложение XAudio2, которое играет 220Гц синусовую волну.

Создание проекта в Visual Studio

В Visual Studio создайте новый проект C++/WinRT Blank App, Packaged (WinUI 3 в Desktop). Если вы назовете проект MyXAudio2Project, вы сможете скопировать исходный код прямо ниже в файлы исходного кода проекта без каких-либо проблем.

Откройте каждый из следующих файлов исходного кода, в свою очередь, и измените их, чтобы выглядеть как список исходного кода.

MainWindow.xaml.idl

namespace MyXAudio2Project
{
    [default_interface]
    runtimeclass MainWindow : Microsoft.UI.Xaml.Window
    {
        MainWindow();
    }
}

MainWindow.xaml.h

#pragma once

#include "MainWindow.g.h"
#include <xaudio2.h>

// Constant literals.
constexpr WORD   BITSPERSSAMPLE = 16;                                                    // 16 bits per sample.
constexpr DWORD  SAMPLESPERSEC = 44100;                                                  // 44,100 samples per second.
constexpr double CYCLESPERSEC = 220.0;                                                   // 220 cycles per second (frequency of the audible tone).
constexpr double VOLUME = 0.5;                                                           // 50% volume.
constexpr WORD   AUDIOBUFFERSIZEINCYCLES = 10;                                           // 10 cycles per audio buffer.
constexpr double PI = 3.14159265358979323846;

// Calculated constants.
constexpr DWORD  SAMPLESPERCYCLE = (DWORD)(SAMPLESPERSEC / CYCLESPERSEC);                // 200 samples per cycle.
constexpr DWORD  AUDIOBUFFERSIZEINSAMPLES = SAMPLESPERCYCLE * AUDIOBUFFERSIZEINCYCLES;   // 2,000 samples per buffer.
constexpr UINT32 AUDIOBUFFERSIZEINBYTES = AUDIOBUFFERSIZEINSAMPLES * BITSPERSSAMPLE / 8; // 4,000 bytes per buffer.

namespace winrt::MyXAudio2Project::implementation
{
    struct MainWindow : MainWindowT<MainWindow>
    {
        std::array<byte, AUDIOBUFFERSIZEINBYTES> m_buffer{};
        winrt::com_ptr<IXAudio2> m_xAudio2{};
        IXAudio2MasteringVoice* m_pXAudio2MasteringVoice{};
        IXAudio2SourceVoice* m_pXAudio2SourceVoice{};

        MainWindow()
        {
            // Xaml objects should not call InitializeComponent during construction.
            // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent
        }

        void myButton_Click(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args);
    };
}

namespace winrt::MyXAudio2Project::factory_implementation
{
    struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow>
    {
    };
}

MainWindow.xaml.cpp

#include "pch.h"
#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif

using namespace winrt;
using namespace Microsoft::UI::Xaml;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace winrt::MyXAudio2Project::implementation
{
    void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&)
    {
        myButton().Content(box_value(L"Clicked"));

        // Initialize XAudio2 (create an engine and a mastering voice).
        winrt::check_hresult(::XAudio2Create(m_xAudio2.put(), 0, XAUDIO2_DEFAULT_PROCESSOR));
        winrt::check_hresult(m_xAudio2->CreateMasteringVoice(&m_pXAudio2MasteringVoice));

        // Define a format.
        WAVEFORMATEX waveFormatEx{};
        waveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
        waveFormatEx.nChannels = 1; // 1 channel
        waveFormatEx.nSamplesPerSec = SAMPLESPERSEC;
        waveFormatEx.nBlockAlign = waveFormatEx.nChannels * BITSPERSSAMPLE / 8;
        waveFormatEx.nAvgBytesPerSec = waveFormatEx.nSamplesPerSec * waveFormatEx.nBlockAlign;
        waveFormatEx.wBitsPerSample = BITSPERSSAMPLE;
        waveFormatEx.cbSize = 0;

        // Create a source voice with that format.
        winrt::check_hresult(m_xAudio2->CreateSourceVoice(&m_pXAudio2SourceVoice, &waveFormatEx));

        // Fill a buffer.
        double phase{};
        uint32_t bufferIndex{};
        while (bufferIndex < AUDIOBUFFERSIZEINBYTES)
        {
            phase += (2 * PI) / SAMPLESPERCYCLE;
            int16_t sample = (int16_t)(sin(phase) * INT16_MAX * VOLUME);
            this->m_buffer[bufferIndex++] = (byte)sample; // Values are little-endian.
            this->m_buffer[bufferIndex++] = (byte)(sample >> 8);
        }

        XAUDIO2_BUFFER xAudio2Buffer{};
        xAudio2Buffer.Flags = XAUDIO2_END_OF_STREAM;
        xAudio2Buffer.AudioBytes = AUDIOBUFFERSIZEINBYTES;
        xAudio2Buffer.pAudioData = m_buffer.data();
        xAudio2Buffer.PlayBegin = 0;
        xAudio2Buffer.PlayLength = 0;
        xAudio2Buffer.LoopBegin = 0;
        xAudio2Buffer.LoopLength = 0;
        xAudio2Buffer.LoopCount = XAUDIO2_LOOP_INFINITE;

        // Submit the buffer to the source voice, and start the voice.
        winrt::check_hresult(m_pXAudio2SourceVoice->SubmitSourceBuffer(&xAudio2Buffer));
        winrt::check_hresult(m_pXAudio2SourceVoice->Start(0));
    }
}

Сборка и запуск

Теперь проект должен выполнять сборку и запуск. Нажмите кнопку, чтобы услышать тон теста 220Гц.