添加声音Add sound

备注

本主题是 使用 DirectX 教程系列 (UWP) 游戏创建简单通用 Windows 平台 的一部分。This topic is part of the Create a simple Universal Windows Platform (UWP) game with DirectX tutorial series. 该链接上的主题设置了序列的上下文。The topic at that link sets the context for the series.

在本主题中,我们将使用 XAudio2 api 创建一个简单的声音引擎。In this topic, we create a simple sound engine using XAudio2 APIs. 如果你不熟悉 XAudio2,我们将在 音频概念下提供简短的简介。If you are new to XAudio2, we have included a short intro under Audio concepts.

备注

如果尚未下载此示例的最新游戏代码,请参阅 Direct3D 示例游戏If you haven't downloaded the latest game code for this sample, go to Direct3D sample game. 此示例是大型 UWP 功能示例集合的一部分。This sample is part of a large collection of UWP feature samples. 有关如何下载示例的说明,请参阅从 GitHub 获取 UWP 示例For instructions on how to download the sample, see Get the UWP samples from GitHub.

目标Objective

使用 XAudio2向示例游戏添加声音。Add sounds into the sample game using XAudio2.

定义音频引擎Define the audio engine

在示例游戏中,音频对象和行为在三个文件中定义:In the sample game, the audio objects and behaviors are defined in three files:

  • /.Cpp Audio.h:定义__音频__对象,其中包含用于播放声音的__XAudio2__资源。Audio.h/.cpp: Defines the Audio object, which contains the XAudio2 resources for sound playback. 它还定义了在游戏暂停或停用的情况下暂停音频播放和恢复音频播放的方法。It also defines the method for suspending and resuming audio playback if the game is paused or deactivated.
  • __ MediaReader/.cpp__:定义从本地存储读取音频 .wav 文件的方法。MediaReader.h/.cpp: Defines the methods for reading audio .wav files from local storage.
  • __ SoundEffect/.cpp__:定义用于游戏中音频播放的对象。SoundEffect.h/.cpp: Defines an object for in-game sound playback.

概述Overview

设置音频播放到游戏中有三个主要部分。There are three main parts in getting set up for audio playback into your game.

  1. 创建和初始化音频资源Create and initialize the audio resources
  2. 加载音频文件Load audio file
  3. 将声音关联到对象Associate sound to object

它们都是在 Simple3DGame:: Initialize 方法中定义的。They are all defined in the Simple3DGame::Initialize method. 接下来,让我们先查看此方法,然后深入了解每个部分中的更多详细信息。So let's first examine this method and then dive into more details in each of the sections.

设置完成后,我们将了解如何触发声音效果播放。After setting up, we learn how to trigger the sound effects to play. 有关详细信息,请参阅 播放声音For more info, go to Play the sound.

Simple3DGame:: Initialize 方法Simple3DGame::Initialize method

在 __Simple3DGame:: Initialize__中,其中 m _ 控制器m _ 呈现 器也被初始化,我们设置了音频引擎并使其可以播放声音。In Simple3DGame::Initialize, where m_controller and m_renderer are also initialized, we set up the audio engine and get it ready to play sounds.

  • 创建 m _ audioController,它是 音频 类的实例。Create m_audioController, which is an instance of the Audio class.
  • 使用 audio:: CreateDeviceIndependentResources 方法创建所需的音频资源。Create the audio resources needed using the Audio::CreateDeviceIndependentResources method. 此处,两个 XAudio2 对象 — 是一个音乐引擎对象和一个声音引擎对象,并为每个对象创建一个控制。Here, two XAudio2 objects — a music engine object and a sound engine object, and a mastering voice for each of them were created. 音乐引擎对象可用于播放游戏的背景音乐。The music engine object can be used to play background music for your game. 声音引擎可用于在游戏中播放声音效果。The sound engine can be used to play sound effects in your game. 有关详细信息,请参阅 创建和初始化音频资源For more info, see Create and initialize the audio resources.
  • 创建 mediaReader,它是 mediaReader 类的实例。Create mediaReader, which is an instance of MediaReader class. MediaReaderSoundEffect 类的帮助器类,它从文件位置同步读取小的音频文件,并将声音数据作为字节数组返回。MediaReader, which is a helper class for the SoundEffect class, reads small audio files synchronously from file location and returns sound data as a byte array.
  • 使用 MediaReader:: LoadMedia 从其位置加载声音文件,并创建 targetHitSound 变量来保存加载的 .wav 声音数据。Use MediaReader::LoadMedia to load sound files from its location and create a targetHitSound variable to hold the loaded .wav sound data. 有关详细信息,请参阅 Load audio fileFor more info, see Load audio file.

声音效果与游戏对象相关联。Sound effects are associated with the game object. 因此,当游戏对象发生冲突时,它会触发要播放的声音效果。So when a collision occurs with that game object, it triggers the sound effect to be played. 在此示例游戏中,我们将对 ammo (使用) 和目标来拍摄目标的效果。In this sample game, we have sound effects for the ammo (what we use to shoot targets with) and for the target.

  • GameObject 类中,有一个 HitSound 属性,该属性用于将声音效果与对象相关联。In the GameObject class, there's a HitSound property that is used to associate the sound effect to the object.
  • 创建 SoundEffect 类的新实例,并对其进行初始化。Create a new instance of the SoundEffect class and initialize it. 在初始化期间,会创建声音效果的源语音。During initialization, a source voice for the sound effect is created.
  • 此类使用从 音频 类提供的主控语音播放声音。This class plays a sound using a mastering voice provided from the Audio class. 使用 MediaReader 类从文件位置读取声音数据。Sound data is read from file location using the MediaReader class. 有关详细信息,请参阅 将声音与对象关联For more info, see Associate sound to object.

备注

播放声音的实际触发器由这些游戏对象的移动和冲突决定。The actual trigger to play the sound is determined by the movement and collision of these game objects. 因此,实际播放这些声音的调用是在 Simple3DGame:: UpdateDynamics 方法中定义的。Hence, the call to actually play these sounds are defined in the Simple3DGame::UpdateDynamics method. 有关详细信息,请参阅 播放声音For more info, go to Play the sound.

void Simple3DGame::Initialize(
    _In_ std::shared_ptr<MoveLookController> const& controller,
    _In_ std::shared_ptr<GameRenderer> const& renderer
    )
{
    // The following member is defined in the header file:
    // Audio m_audioController;

    ...

    // Create the audio resources needed.
    // Two XAudio2 objects are created - one for music engine,
    // the other for sound engine. A mastering voice is also
    // created for each of the objects.
    m_audioController.CreateDeviceIndependentResources();

    m_ammo.resize(GameConstants::MaxAmmo);

    ...

    // Create a media reader which is used to read audio files from its file location.
    MediaReader mediaReader;
    auto targetHitSoundX = mediaReader.LoadMedia(L"Assets\\hit.wav");

    // Instantiate the targets for use in the game.
    // Each target has a different initial position, size, and orientation.
    // But share a common set of material properties.
    for (int a = 1; a < GameConstants::MaxTargets; a++)
    {
        ...
        // Create a new sound effect object and associate it
        // with the game object's (target) HitSound property.
        target->HitSound(std::make_shared<SoundEffect>());

        // Initialize the sound effect object with
        // the sound effect engine, format of the audio wave, and audio data
        // During initialization, source voice of this sound effect is also created.
        target->HitSound()->Initialize(
            m_audioController.SoundEffectEngine(),
            mediaReader.GetOutputWaveFormatEx(),
            targetHitSoundX
            );
        ...
    }

    // Instantiate a set of spheres to be used as ammunition for the game
    // and set the material properties of the spheres.
    auto ammoHitSound = mediaReader.LoadMedia(L"Assets\\bounce.wav");

    for (int a = 0; a < GameConstants::MaxAmmo; a++)
    {
        m_ammo[a] = std::make_shared<Sphere>();
        m_ammo[a]->Radius(GameConstants::AmmoRadius);
        m_ammo[a]->HitSound(std::make_shared<SoundEffect>());
        m_ammo[a]->HitSound()->Initialize(
            m_audioController.SoundEffectEngine(),
            mediaReader.GetOutputWaveFormatEx(),
            ammoHitSound
            );
        m_ammo[a]->Active(false);
        m_renderObjects.push_back(m_ammo[a]);
    }
    ...
}

创建和初始化音频资源Create and initialize the audio resources

  • 使用 XAudio2Create(XAudio2 API)来创建两个新的 XAudio2 对象,这些对象定义音乐和声音效果引擎。Use XAudio2Create, an XAudio2 API, to create two new XAudio2 objects which define the music and sound effect engines. 此方法返回指向对象的 IXAudio2 接口的指针,该接口管理所有音频引擎状态、音频处理线程、语音图形等。This method returns a pointer to the object's IXAudio2 interface that manages all audio engine states, the audio processing thread, the voice graph, and more.
  • 在实例化引擎后,使用 IXAudio2:: CreateMasteringVoice 为每个声音引擎对象创建一个控制声音。After the engines have been instantiated, use IXAudio2::CreateMasteringVoice to create a mastering voice for each of the sound engine objects.

有关详细信息,请参阅 如何:初始化 XAudio2For more info, go to How to: Initialize XAudio2.

Audio:: CreateDeviceIndependentResources 方法Audio::CreateDeviceIndependentResources method

void Audio::CreateDeviceIndependentResources()
{
    UINT32 flags = 0;

    winrt::check_hresult(
        XAudio2Create(m_musicEngine.put(), flags)
        );

    HRESULT hr = m_musicEngine->CreateMasteringVoice(&m_musicMasteringVoice);
    if (FAILED(hr))
    {
        // Unable to create an audio device
        m_audioAvailable = false;
        return;
    }

    winrt::check_hresult(
        XAudio2Create(m_soundEffectEngine.put(), flags)
        );

    winrt::check_hresult(
        m_soundEffectEngine->CreateMasteringVoice(&m_soundEffectMasteringVoice)
        );

    m_audioAvailable = true;
}

加载音频文件Load audio file

在示例游戏中,用于读取音频格式文件的代码是在 MediaReader/cpp__ 中定义的。In the sample game, the code for reading audio format files is defined in MediaReader.h/cpp__. 若要读取编码的 .wav 音频文件,请调用 MediaReader:: LoadMedia,并将 .wav 的文件名作为输入参数传入。To read an encoded .wav audio file, call MediaReader::LoadMedia, passing in the filename of the .wav as the input parameter.

MediaReader:: LoadMedia 方法MediaReader::LoadMedia method

此方法使用媒体基础 API 作为脉冲编码调制 (PCM) 缓冲区读入 .wav 音频文件。This method uses the Media Foundation APIs to read in the .wav audio file as a Pulse Code Modulation (PCM) buffer.

设置源读取器Set up the Source Reader

  1. 使用 MFCreateSourceReaderFromURL (IMFSourceReader) 创建媒体源读取器。Use MFCreateSourceReaderFromURL to create a media source reader (IMFSourceReader).
  2. 使用 MFCreateMediaType (IMFMediaType) 对象 (媒体 类型) 创建媒体类型。Use MFCreateMediaType to create a media type (IMFMediaType) object (mediaType). 它表示媒体格式的说明。It represents a description of a media format.
  3. 指定 _媒体_类型的解码输出为 PCM 音频,这是 XAudio2 可以使用的音频类型。Specify that the mediaType's decoded output is PCM audio, which is an audio type that XAudio2 can use.
  4. 通过调用 IMFSourceReader:: SetCurrentMediaType为源读取器设置已解码的输出媒体类型。Sets the decoded output media type for the source reader by calling IMFSourceReader::SetCurrentMediaType.

有关为何使用源读取器的详细信息,请参阅 源读取器For more info on why we use the Source Reader, go to Source Reader.

描述音频流的数据格式Describe the data format of the audio stream

  1. 使用 IMFSourceReader:: GetCurrentMediaType 获取流的当前媒体类型。Use IMFSourceReader::GetCurrentMediaType to get the current media type for the stream.
  2. 使用 IMFMediaType:: MFCreateWaveFormatExFromMFMediaType 将之前操作的结果作为输入,以将当前音频媒体类型转换为 WAVEFORMATEX 缓冲区。Use IMFMediaType::MFCreateWaveFormatExFromMFMediaType to convert the current audio media type to a WAVEFORMATEX buffer, using the results of the earlier operation as input. 此结构指定加载音频后使用的波形音频流的数据格式。This structure specifies the data format of the wave audio stream that is used after audio is loaded.

__WAVEFORMATEX__格式可用于描述 PCM 缓冲区。The WAVEFORMATEX format can be used to describe the PCM buffer. WAVEFORMATEXTENSIBLE 结构相比,它仅可用于描述一小部分音频波形格式。As compared to the WAVEFORMATEXTENSIBLE structure, it can only be used to describe a subset of audio wave formats. 有关 WAVEFORMATEX 与 __WAVEFORMATEXTENSIBLE__之间的差异的详细信息,请参阅 可扩展波形格式说明符For more info about the differences between WAVEFORMATEX and WAVEFORMATEXTENSIBLE, see Extensible Wave-Format Descriptors.

读取音频流Read the audio stream

  1. 通过调用 IMFSourceReader:: GetPresentationAttribute 获取音频流的持续时间(以秒为单位),然后将持续时间转换为字节。Get the duration, in seconds, of the audio stream by calling IMFSourceReader::GetPresentationAttribute and then converts the duration to bytes.
  2. 通过调用 IMFSourceReader:: ReadSample,将中的音频文件作为流进行读取。Read the audio file in as a stream by calling IMFSourceReader::ReadSample. ReadSample 读取媒体源中的下一个示例。ReadSample reads the next sample from the media source.
  3. 使用 IMFSample:: ConvertToContiguousBuffer 将音频示例缓冲区 (示例) 的内容复制到 (mediaBuffer) 的数组中。Use IMFSample::ConvertToContiguousBuffer to copy contents of the audio sample buffer (sample) into an array (mediaBuffer).
std::vector<byte> MediaReader::LoadMedia(_In_ winrt::hstring const& filename)
{
    winrt::check_hresult(
        MFStartup(MF_VERSION)
        );

    // Creates a media source reader.
    winrt::com_ptr<IMFSourceReader> reader;
    winrt::check_hresult(
        MFCreateSourceReaderFromURL(
        (m_installedLocationPath + filename).c_str(),
            nullptr,
            reader.put()
            )
        );

    // Set the decoded output format as PCM.
    // XAudio2 on Windows can process PCM and ADPCM-encoded buffers.
    // When using MediaFoundation, this sample always decodes into PCM.
    winrt::com_ptr<IMFMediaType> mediaType;
    winrt::check_hresult(
        MFCreateMediaType(mediaType.put())
        );

    // Define the major category of the media as audio. For more info about major media types,
    // go to: https://msdn.microsoft.com/library/windows/desktop/aa367377.aspx
    winrt::check_hresult(
        mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)
        );

    // Define the sub-type of the media as uncompressed PCM audio. For more info about audio sub-types,
    // go to: https://msdn.microsoft.com/library/windows/desktop/aa372553.aspx
    winrt::check_hresult(
        mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)
        );

    // Sets the media type for a stream. This media type defines that format that the Source Reader 
    // produces as output. It can differ from the native format provided by the media source.
    // For more info, go to https://msdn.microsoft.com/library/windows/desktop/dd374667.aspx
    winrt::check_hresult(
        reader->SetCurrentMediaType(static_cast<uint32_t>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), 0, mediaType.get())
        );

    // Get the current media type for the stream.
    // For more info, go to:
    // https://msdn.microsoft.com/library/windows/desktop/dd374660.aspx
    winrt::com_ptr<IMFMediaType> outputMediaType;
    winrt::check_hresult(
        reader->GetCurrentMediaType(static_cast<uint32_t>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), outputMediaType.put())
        );

    // Converts the current media type into the WaveFormatEx buffer structure.
    UINT32 size = 0;
    WAVEFORMATEX* waveFormat;
    winrt::check_hresult(
        MFCreateWaveFormatExFromMFMediaType(outputMediaType.get(), &waveFormat, &size)
        );

    // Copies the waveFormat's block of memory to the starting address of the m_waveFormat variable in MediaReader.
    // Then free the waveFormat memory block.
    // For more info, go to https://msdn.microsoft.com/library/windows/desktop/aa366535.aspx and
    // https://msdn.microsoft.com/library/windows/desktop/ms680722.aspx
    CopyMemory(&m_waveFormat, waveFormat, sizeof(m_waveFormat));
    CoTaskMemFree(waveFormat);

    PROPVARIANT propVariant;
    winrt::check_hresult(
        reader->GetPresentationAttribute(static_cast<uint32_t>(MF_SOURCE_READER_MEDIASOURCE), MF_PD_DURATION, &propVariant)
        );

    // 'duration' is in 100ns units; convert to seconds, and round up
    // to the nearest whole byte.
    LONGLONG duration = propVariant.uhVal.QuadPart;
    unsigned int maxStreamLengthInBytes =
        static_cast<unsigned int>(
            ((duration * static_cast<ULONGLONG>(m_waveFormat.nAvgBytesPerSec)) + 10000000) /
            10000000
            );

    std::vector<byte> fileData(maxStreamLengthInBytes);

    winrt::com_ptr<IMFSample> sample;
    winrt::com_ptr<IMFMediaBuffer> mediaBuffer;
    DWORD flags = 0;

    int positionInData = 0;
    bool done = false;
    while (!done)
    {
        // Read audio data.
        ...
    }

    return fileData;
}

将声音关联到对象Associate sound to object

Simple3DGame:: Initialize 方法中初始化游戏时,将声音关联到对象。Associating sounds to the object takes place when the game initializes, in the Simple3DGame::Initialize method.

Recap:Recap:

  • GameObject 类中,有一个 HitSound 属性,该属性用于将声音效果与对象相关联。In the GameObject class, there's a HitSound property that is used to associate the sound effect to the object.
  • 创建 SoundEffect 类对象的新实例,并将其与游戏对象相关联。Create a new instance of the SoundEffect class object and associate it with the game object. 此类使用 XAudio2 api 播放声音。This class plays a sound using XAudio2 APIs. 它使用由 音频 类提供的 "主控语音"。It uses a mastering voice provided by the Audio class. 可以使用 MediaReader 类从文件位置读取声音数据。The sound data can be read from file location using the MediaReader class.

SoundEffect:: Initialize 用于初始化具有以下输入参数的 SoundEffect 实例:指向声音引擎对象的指针 (在 音频:: CreateDeviceIndependentResources 方法中创建的 IXAudio2 对象) ,使用 __MediaReader:: GetOutputWaveFormatEx__的 .Wav 文件格式的指针,以及使用 MediaReader:: LoadMedia 方法加载的声音数据。SoundEffect::Initialize is used to initalize the SoundEffect instance with the following input parameters: pointer to sound engine object (IXAudio2 objects created in the Audio::CreateDeviceIndependentResources method), pointer to format of the .wav file using MediaReader::GetOutputWaveFormatEx, and the sound data loaded using MediaReader::LoadMedia method. 在初始化期间,还会创建声音效果的源声音。During initialization, the source voice for the sound effect is also created.

SoundEffect:: Initialize 方法SoundEffect::Initialize method

void SoundEffect::Initialize(
    _In_ IXAudio2* masteringEngine,
    _In_ WAVEFORMATEX* sourceFormat,
    _In_ std::vector<byte> const& soundData)
{
    m_soundData = soundData;

    if (masteringEngine == nullptr)
    {
        // Audio is not available so just return.
        m_audioAvailable = false;
        return;
    }

    // Create a source voice for this sound effect.
    winrt::check_hresult(
        masteringEngine->CreateSourceVoice(
            &m_sourceVoice,
            sourceFormat
            )
        );
    m_audioAvailable = true;
}

播放声音Play the sound

Simple3DGame:: UpdateDynamics 方法定义用于播放声音效果的触发器,因为在这种情况下,将更新对象的移动,并确定对象之间的冲突。Triggers to play sound effects are defined in Simple3DGame::UpdateDynamics method because this is where movement of the objects are updated and collision between objects is determined.

由于对象之间的交互差异很大,根据游戏的不同,我们不会在此处讨论游戏对象的动态。Since interaction of between objects differs greatly, depending on the game, we are not going to discuss the dynamics of the game objects here. 如果你有兴趣了解其实现,请参阅 Simple3DGame:: UpdateDynamics 方法。If you're interested to understand its implementation, go to Simple3DGame::UpdateDynamics method.

原则上,当发生冲突时,它会触发声音效果,方法是调用 SoundEffect::P laysoundIn principle, when a collision occurs, it triggers the sound effect to play by calling SoundEffect::PlaySound. 此方法停止当前正在播放的任何声音效果,并将内存中缓冲区与所需的声音数据进行排队。This method stops any sound effects that's currently playing and queues the in-memory buffer with the desired sound data. 它使用源语音设置卷、提交声音数据并开始播放。It uses source voice to set the volume, submit sound data, and start the playback.

SoundEffect::P laySound 方法SoundEffect::PlaySound method

void SoundEffect::PlaySound(_In_ float volume)
{
    XAUDIO2_BUFFER buffer = { 0 };

    if (!m_audioAvailable)
    {
        // Audio is not available so just return.
        return;
    }

    // Interrupt sound effect if it is currently playing.
    winrt::check_hresult(
        m_sourceVoice->Stop()
        );
    winrt::check_hresult(
        m_sourceVoice->FlushSourceBuffers()
        );

    // Queue the memory buffer for playback and start the voice.
    buffer.AudioBytes = (UINT32)m_soundData.size();
    buffer.pAudioData = m_soundData.data();
    buffer.Flags = XAUDIO2_END_OF_STREAM;

    winrt::check_hresult(
        m_sourceVoice->SetVolume(volume)
        );
    winrt::check_hresult(
        m_sourceVoice->SubmitSourceBuffer(&buffer)
        );
    winrt::check_hresult(
        m_sourceVoice->Start()
        );
}

Simple3DGame:: UpdateDynamics 方法Simple3DGame::UpdateDynamics method

__Simple3DGame:: UpdateDynamics__方法负责处理游戏对象之间的交互和冲突。The Simple3DGame::UpdateDynamics method takes care the interaction and collision between game objects. 当对象) (或交集时,它将触发关联的声音效果播放。When objects collide (or intersect), it triggers the associated sound effect to play.

void Simple3DGame::UpdateDynamics()
{
    ...
    // Check for collisions between ammo.
#pragma region inter-ammo collision detection
if (m_ammoCount > 1)
{
    ...
    // Check collision between instances One and Two.
    ...
    if (distanceSquared < (GameConstants::AmmoSize * GameConstants::AmmoSize))
    {
        // The two ammo are intersecting.
        ...
        // Start playing the sounds for the impact between the two balls.
        m_ammo[one]->PlaySound(impact, m_player->Position());
        m_ammo[two]->PlaySound(impact, m_player->Position());
    }
}
#pragma endregion

#pragma region Ammo-Object intersections
    // Check for intersections between the ammo and the other objects in the scene.
    // ...
    // Ball is in contact with Object.
    // ...

    // Make sure that the ball is actually headed towards the object. At grazing angles there
    // could appear to be an impact when the ball is actually already hit and moving away.

    if (impact > 0.0f)
    {
        ...
        // Play the sound associated with the Ammo hitting something.
        m_objects[i]->PlaySound(impact, m_player->Position());

        if (m_objects[i]->Target() && !m_objects[i]->Hit())
        {
            // The object is a target and isn't currently hit, so mark
            // it as hit and play the sound associated with the impact.
            m_objects[i]->Hit(true);
            m_objects[i]->HitTime(timeTotal);
            m_totalHits++;

            m_objects[i]->PlaySound(impact, m_player->Position());
        }
        ...
    }
#pragma endregion

#pragma region Apply Gravity and world intersection
            // Apply gravity and check for collision against enclosing volume.
            ...
                if (position.z < limit)
                {
                    // The ammo instance hit the a wall in the min Z direction.
                    // Align the ammo instance to the wall, invert the Z component of the velocity and
                    // play the impact sound.
                    position.z = limit;
                    m_ammo[i]->PlaySound(-velocity.z, m_player->Position());
                    velocity.z = -velocity.z * GameConstants::Physics::GroundRestitution;
                }
                ...
#pragma endregion
}

后续步骤Next steps

我们介绍了 Windows 10 游戏的 UWP 框架、图形、控件、用户界面和音频。We have covered the UWP framework, graphics, controls, user interface, and audio of a Windows 10 game. 本教程的下一部分是 扩展示例游戏,说明了在开发游戏时可以使用的其他选项。The next part of this tutorial, Extending the sample game, explains other options that can be used when developing a game.

音频概念Audio concepts

对于 Windows 10 游戏开发,请使用 XAudio2 版本2.9。For Windows 10 games development, use XAudio2 version 2.9. 此版本随 Windows 10 一起提供。This version is shipped with Windows 10. 有关详细信息,请参阅 XAudio2 版本For more info, go to XAudio2 Versions.

AudioX2 是一种低级别 API,提供信号处理和混合基础。AudioX2 is a low-level API that provides signal processing and mixing foundation. 有关详细信息,请参阅 XAudio2 关键概念For more info, see XAudio2 Key Concepts.

XAudio2 语音XAudio2 voices

有三种类型的 XAudio2 voice 对象:源、submix 和控制声。There are three types of XAudio2 voice objects: source, submix, and mastering voices. 声音是 XAudio2 用于处理、操作和播放音频数据的对象。Voices are the objects XAudio2 use to process, to manipulate, and to play audio data.

  • 源语音对客户提供的音频数据操作。Source voices operate on audio data provided by the client.
  • 源语音和子混合语音将其输出发送到一个或多个子混合语音或主语音。Source and submix voices send their output to one or more submix or mastering voices.
  • 子混合语音和主语音将传入的所有音频混合在一起,并对结果进行操作。Submix and mastering voices mix the audio from all voices feeding them, and operate on the result.
  • "主控语音" 通过源语音和 submix 声音接收数据,并将该数据发送到音频硬件。Mastering voices receive data from source voices and submix voices, and sends that data to the audio hardware.

有关详细信息,请参阅 XAudio2 声音For more info, go to XAudio2 voices.

音频图形Audio graph

音频图形是 XAudio2 语音的集合。Audio graph is a collection of XAudio2 voices. 音频在源语音的音频图形的一侧开始,可以选择通过一个或多个 submix 声音,并结束控制声。Audio starts at one side of an audio graph in source voices, optionally passes through one or more submix voices, and ends at a mastering voice. 音频图形会为当前播放的每个声音、零个或多个 submix 声音以及一个控制声音提供源语音。An audio graph will contain a source voice for each sound currently playing, zero or more submix voices, and one mastering voice. 最简单的音频图形和在 XAudio2 中产生干扰所需的最小值是直接输出到主控语音的单个源语音。The simplest audio graph, and the minimum needed to make a noise in XAudio2, is a single source voice outputting directly to a mastering voice. 有关详细信息,请参阅 音频图For more info, go to Audio graphs.

其他阅读材料Additional reading

关键的音频 .h 文件Key audio .h files

Audio.hAudio.h

// Audio:
// This class uses XAudio2 to provide sound output. It creates two
// engines - one for music and the other for sound effects - each as
// a separate mastering voice.
// The SuspendAudio and ResumeAudio methods can be used to stop
// and start all audio playback.

class Audio
{
public:
    Audio();

    void Initialize();
    void CreateDeviceIndependentResources();
    IXAudio2* MusicEngine();
    IXAudio2* SoundEffectEngine();
    void SuspendAudio();
    void ResumeAudio();

private:
    ...
};

MediaReaderMediaReader.h

// MediaReader:
// This is a helper class for the SoundEffect class. It reads small audio files
// synchronously from the package installed folder and returns sound data as a
// vector of bytes.

class MediaReader
{
public:
    MediaReader();

    std::vector<byte> LoadMedia(_In_ winrt::hstring const& filename);
    WAVEFORMATEX* GetOutputWaveFormatEx();

private:
    winrt::Windows::Storage::StorageFolder  m_installedLocation{ nullptr };
    winrt::hstring                          m_installedLocationPath;
    WAVEFORMATEX                            m_waveFormat;
};

SoundEffect.hSoundEffect.h

// SoundEffect:
// This class plays a sound using XAudio2. It uses a mastering voice provided
// from the Audio class. The sound data can be read from disk using the MediaReader
// class.

class SoundEffect
{
public:
    SoundEffect();

    void Initialize(
        _In_ IXAudio2* masteringEngine,
        _In_ WAVEFORMATEX* sourceFormat,
        _In_ std::vector<byte> const& soundData
        );

    void PlaySound(_In_ float volume);

private:
    ...
};