Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Статьи / Программирование звука с использованием XAudio2.

Программирование звука с использованием XAudio2.

Страницы: 1 2 3 Следующая

Автор:

Всем доброго времени суток! Это моя первая статья на GameDev.ru, которая появилась в связи с тем, что в недавнем времени решил я сам перейти на библиотеку XAudio2. Документации по ней в Интернете на русском нет.

Введение
XAudio2
  Первые приготовления
  Сохраняем аудио-данные
  Источник звука
  Тестируем
Заключение

Введение

Помимо XAudio2 существует несколько библиотек для вывода звука: DirectSound, OpenAL, FMOD, BASS. Но мне хочется поговорить именно об XAudio2, так как об этом нет русских статей.

Как заявляет сама Microsoft (смотреть тут), она больше не поддерживает DirectSound, и новые проекты, в зависимости от типа, должны использовать новое программное обеспечение. Для игр это XAudio2 и X3DAudio, для всего остального — Windows Core Audio.

Библиотека XAudio2 входят в состав Microsoft DirectX SDK и при её использовании может возникнуть такая же проблема, как и с библиотекой D3DX9 — постоянно нужно пользователю обновлять Microsoft DirectX. Самая последняя версия Microsoft DirectX (июнь 2010) включает следующие библиотеки XAudio2:

  • XAudio2_0.dll;
  • XAudio2_1.dll;
  • XAudio2_2.dll;
  • XAudio2_3.dll;
  • XAudio2_4.dll;
  • XAudio2_5.dll;
  • XAudio2_6.dll;
  • XAudio2_7.dll;
  • XAudioD2_7.dll.

Так что если ваша программа не заработала на другом компьютере, то возможны два варианта:

  • Вы что-то сделали не так;
  • У пользователя не стоят те же самые библиотеки, которые вы использовали для создания программы.

А теперь перейдём к рассмотрению XAudio2...

XAudio2

Первые приготовления

В XAudio2 имеются два основных интерфейса: IXAudio2 и IXAudio2Voice.

  • IXAudio2 - это интерфейс, который работает со всеми аудио-голосами (IXAudio2Voice).
  • IXAudio2Voice - это базовый интерфейс для трёх других: IXAudio2SourceVoice, IXAudio2SubmixVoice и IXAudio2MasteringVoice.

Все эти интерфейсы (IXAudio2SourceVoice, IXAudio2SubmixVoice и IXAudio2MasteringVoice) обрабатывают несжатые аудио-данные.

  • IXAudio2SourceVoice этот интерфейс, который непосредственно получает несжатый аудио-данные. Далее он передаёт данные в IXAudio2SubmixVoice, если конечно тот существует (что является необязательным) или же в IXAudio2MasteringVoice.
  • IXAudio2SubmixVoice служит для всевозможных преобразований аудио-данных. Результат своей работы он передаёт IXAudio2MasteringVoice.
  • IXAudio2MasteringVoice тоже может производить некоторые операции над аудио-данными, и именно через этот интерфейс данные попадают в аудио-устройство. Данных интерфейсом может быть создано несколько, но одновременно может работать только один.

Структур для обработки голоса может быть несколько, их разнообразие велико. От простого:

00 | Программирование звука с использованием XAudio2.

До:

01 | Программирование звука с использованием XAudio2.

Перейдём к коду...

Создадим в Visual C++ новый пустой проект Win32 приложения. Укажем где у нас находятся заголовочные файлы (include) и библиотеки (lib) от Microsoft DirectX SDK.


Замечание: Для работы с XAudio2 не нужно линковщику указывать статическую библиотеку (lib), достаточно к проекту подключить заголовочный файл XAudio2.h.

Начнём с создания класса для всех операций с аудио-библиотекой, назовём его Audio. Добавим к проекту файл Audio.h и внесём в него:

#pragma once

#define AUDIO_OK                               0
#define AUDIO_ERROR_CREATE_AUDIO              -1
#define AUDIO_ERROR_CREATE_MASTERING_VOICE    -2

#include <XAudio2.h>

class Audio
{
  private:
    static Audio* instance;

    int resultCode;

    bool isCreate;

    IXAudio2* audio;
    IXAudio2MasteringVoice* masteringVoice;

    Audio(void);
    ~Audio(void);

  public:
    static Audio* GetInstance(void);

    void Release(void);

    int GetResult(void) const;

    bool Create(void);
};

Теперь разберём что к чему...


#define AUDIO_OK                               0
#define AUDIO_ERROR_CREATE_AUDIO              -1
#define AUDIO_ERROR_CREATE_MASTERING_VOICE    -2

Нам это будет нужно для контроля выполнения функций. Пока у нас будет всего одна функция, которая возможно выполнится с ошибкой.


int GetResult(void) const;

Возвращает тот самый код выполнения.


static Audio* instance;
static Audio* GetInstance(void);

void Release(void);

Для того чтобы в памяти находился только один экземпляр класса Audio, мы будем хранить его адрес в статической переменной.


bool Create(void);

Служит для создания двух интерфейсов: IXAudio2 и IXAudio2MasteringVoice.


bool isCreate;

Так мы будем знать создали ли мы главные интерфейсы.


Теперь создадим файл Audio.cpp:

#include "Audio.h"

// Пока у нас нет экземпляра в памяти
Audio* Audio::instance=0;

// Конструктор
Audio::Audio(void)
{
  resultCode=AUDIO_OK;
  isCreate=false;

  audio=0;
  masteringVoice=0;
}

// Деструктор
Audio::~Audio(void)
{
  // Сначала освобождаем все голоса (у нас пока только IXAudio2MasteringVoice)
  if(masteringVoice) masteringVoice->DestroyVoice();

  // Теперь освобождаем главный интерфейс
  if(audio) audio->Release();

  // Если была инициализирована работа с COM, то деинициализируем её
  if(isCreate) CoUninitialize();
}

// Получаем указатель на единственный экземпляр класса
// Если экземпляр ещё не создан, то создаём его и возвращает на него указатель
Audio* Audio::GetInstance(void)
{
  if(!instance) instance=new Audio();

  return instance;
}

// Удаляем экземпляр
void Audio::Release(void)
{
  if(instance)
  {
    delete instance;
    instance=0;
  }
}

// Получение кода выполнения
int Audio::GetResult(void) const
{
  return resultCode;
}

// Создание
bool Audio::Create(void)
{
  // Пока будем считать что у нас всё хорошо
  resultCode=AUDIO_OK;

  // Иницилизируем работы с COM в отдельном потоке
  CoInitializeEx(0,COINIT_MULTITHREADED);

  // Создаём главный интерфейс
  if(XAudio2Create(&audio,0,XAUDIO2_DEFAULT_PROCESSOR)!=S_OK)
  {
    CoUninitialize();
    resultCode=AUDIO_ERROR_CREATE_AUDIO;
    return false;
  }

  // Создаём главный голос
  if(audio->CreateMasteringVoice(
    &masteringVoice,
    XAUDIO2_DEFAULT_CHANNELS,
    XAUDIO2_DEFAULT_SAMPLERATE,
    0,
    0,
    0)!=S_OK)
  {
    CoUninitialize();
    resultCode=AUDIO_ERROR_CREATE_MASTERING_VOICE;
    return false;
  }

  // Если дошли сюда, то всё в порядке
  isCreate=true;

  return true;
}

Тут разберём только функцию Create()...

Функция XAudio2Create используется для создания главного интерфейса (IXAudio2). Выглядит следующим образом:

HRESULT XAudio2Create(
    IXAudio2** ppXAudio2,
    UINT32 Flags=0,
    XAUDIO2_PROCESSOR XAudio2Processor=XAUDIO2_DEFAULT_PROCESSOR)

Замечание: При работе с COM не обязательно у функции заполнять все параметры если им присваиваются значения по умолчанию.
  • ppXAudio2 указатель на указатель интерфейса IXAudio2.
  • Flags используется для установки режима работы. Может быть либо 0, либо XAUDIO2_DEBUG_ENGINE (в этом случае будет запрашивать отладочную информация из библиотеки).
  • XAudio2Processor указывает какой процессор использовать для обработки аудио. Тут мы оставили значение по умолчанию, а полный список можно посмотреть в структуре XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER.

Если функция завершается успешно, то обратная величина S_OK.

Далее мы создаём главный интерфейс для передачи аудио-данных на аудио-устройство через функцию CreateMasteringVoice интерфейса IXAudio2. Вот как она выглядит:

HRESULT CreateMasteringVoice(
    IXAudio2MasteringVoice** ppMasteringVoice,
    UINT32 InputChannels=XAUDIO2_DEFAULT_CHANNELS,
    UINT32 InputSampleRate=XAUDIO2_DEFAULT_SAMPLERATE,
    UINT32 Flags=0,
    UINT32 DeviceIndex=0,
    const XAUDIO2_EFFECT_CHAIN* pEffectChain=NULL)
  • ppMasteringVoice указатель на указать интерфейса IXAudio2MasteringVoice.
  • InputChannels указывает сколько каналов будет обрабатывать IXAudio2MasteringVoice.
  • InputSampleRate устанавливает норму отбора. Это значение должно быть кратно XAUDIO2_QUANTUM_DENOMINATOR и лежать в промежутки от XAUDIO2_MIN_SAMPLE_RATE до XAUDIO2_MAX_SAMPLE_RATE (включая сами промежутки). По умолчанию используется значение XAUDIO2_DEFAULT_SAMPLERATE.
  • Flags определяет поведение и всегда должен быть равен нулю.
  • DeviceIndex указывает на какое аудио-устройство прикрепить IXAudio2MasteringVoice. Указав значение 0 мы прикрепим IXAudio2MasteringVoice к глобальному аудио-устройству.
  • pEffectChain указатель на список эффектов. Нам он пока не нужен, поэтому поставим 0.

Если функция завершается успешно, то обратная величина S_OK.

Теперь приступим к созданию аудио-буферов...

Страницы: 1 2 3 Следующая

23 апреля 2011

#программирование, #звук

2001—2017 © GameDev.ru — Разработка игр