Навигация
Библиотеки
Движки


Genesis3D
Программирование
Моделирование

AURAN Jet
Статьи

Список движков

 

Создание игр


Советы по разработке
Физика
Интеллект
Алгоритмы
Поиск текстур
Поиск моделей

Ваши игры

 

DirectSound Tutorial

Автор: Jack Hackslay


Обзор DirectSound

Теория- Нормальный режим

DS довольно прост для обучения, возможно, это самая легкая часть DirectX. Если вы не планируете создание трехмерной игры, DirectSound3D не должен вас волновать. Для полного восприятия режима 3D пользователю будет необходима 3D звуковая система (обычно система из четырех динамиков).

Прим. перев.: Для тех, кто занимается созданием трехмерных игрушек, раздел "3D режим" выйдет чуть позже и в отдельном учебнике, т.к. в оригинале он почти не освещен.


Теория DirectSound

Нормальный режим - Обзор

DirectSound, как можно понять из названия, проигрывает звуки. Обычно он используется для создания звуковых эффектов в играх, благодаря своей способности проигрывать больше, чем один звук в одно и то же время ("Микширование"). Также, вы можете более точно контролировать звучание в динамиках пользователя используя эффекты громкости и баланса звука(panning). Также, есть возможность задания координат x, y и z для источника звука, но в полной мере эта опция, называемая DirectSound3D работает на компьютерах, оснащенных звуковой системой из 4-х динамиков. Лучше всего 3D звук используется в шутерах от первого лица, где игрок может слышать звуки изо всех направлений.

DirectSound очень важен для игр. Многие обозреватели трехмерных игр забывают о звуке. Попробуйте играть в игру с выключенным звуком и вы поймете разницу.

К сожалению, многие компоненты DirectX, ограничены в Visual Basic. И поэтому имеется очень маленькая поддержка действительно 3D позиционированного звука. Причина этого в самом языке, ведь Visual Basic в основе своей инструмент для баз данных (поэтому в нем так много инструментов для управления данными), и язык никогда не планировался для разработки игр. Профессиональные компании используют C++ для создания игр, поэтому DirectX имеет больше поддержки в C++, чем в Visual Basic.


Нормальный режим DirectSound

Обзор- Теория

Этот учебник покажет вам как создать простое приложение, которое проигрывает несколько звуков в одно и то же время. У него будут опции для баланса звука (Право <-> Лево) и громкости (ну это вы знаете!).
Код из этого приложения затем может быть добавлен в любую вашу игру, где будут использоваться звуковые эффекты.

Сначала, несколько понятий:
Буфер - место, в котором содержатся звуковые данные
Wav файл - тип файлов, которые использует DSound: *.wav

Щелкните в списке, чтобы перейти к нужной секции:


СЕКЦИЯ

СОДЕРЖАНИЕ

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

Создание проекта для работы с Direct Sound

 Объявление переменных

Переменные и их объяснения

 Создание интерфейса

Как должна выглядеть форма, и код, которые все соединит

 Создание кода загрузки звука

Заставим программу загрузить звуковые данные

  Заставим ее проигрывать

Ну этим все сказано! Получим полезный результат от программы.

  Добавим эффекты

Финальный аккорд

  Приложение

Готовый проект с примером

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

Этот проект использует DirectX 7, поэтому добавьте соответствующую библиотеку к вашему проекту.

Также, вам потребуется несколько звуковых файлов для проигрывания. Найдите пару wav файлов (попробуйте через пункт "Поик" из меню "пуск". Скпируйте два РАЗНЫХ файла в папку с вашим проектом, переименовав их в Tester1.wav и Tester2.wav

Сохраните проект и переходите к следующей секции...

Объявление переменных

В этом проекте будет довольно мало переменных, но все же надо по ним пробежаться. Добавьте эти строки в секцию Declarations для Form1:


Option Explicit     'Очень полезное требование, когда работаете с DirectX
Dim m_dx As New DirectX7  'Это главный объект DirectX. DirectSound создается из этого объекта
Dim m_ds As DirectSound    'Это объект DirectSound. Позже, мы "Создадим" его из главного объекта DirectX
Dim m_dsBuffer(1) As DirectSoundBuffer 'Это массив буферов, использовать который не обязательно, но это сделает программирование намного легче. m_dsBuffer(0) будет содержать tester1.wav, а m_dsBuffer(1) tester2.wav

 

Позже, каждый буфер будет вызываться, чтобы проигрывать/остановить его содержимое.

Создание интерфейса

Примерно так же должно быть и у Вас

Интерфейс, как вы можете видеть, довольно мудреный. Интерфейс содержит набор элементов, управляющих каждым буфером и набор общих элементов управления. Вот таблица свойств элементов:


(1) Сначала, создайте два фрейма с любыми именами. Свойство Caption одного должно быть "Громкость", а другого "Баланс"
(2) Затем, внутри первого фрейма поместите два скролл бара
scrlTester1_Vol

     .Max=0
     .Min=-5000
     .LargeChange=20
     .SmallChange=255
scrlTester2_Vol
     .Max=0
     .Min=-5000
     .LargeChange=20
     .SmallChange=255
Можете, если хотите, добавить метки.
(3) Затем, поместите еще два скролл бара во второй фрейм
scrlTester1_Pan

     .Max=10000
     .Min=-10000
     .LargeChange=1000
     .SmallChange=500
scrlTester2_Pan
     .Max=10000
     .Min=-10000
     .LargeChange=1000
     .SmallChange=500
(4) Используйте рисунок, как подмогу, создавая главную "Контрольную панель"
cmdTester1_Play

     .Caption="Play Tester1.Wav"
cmdTester2_Play
    .Caption="Play Tester2.Wav"
cmdBoth_Play
    .Caption="Play Both"
cmdTester1_Stop
   .Caption="Stop Tester1.Wav"
cmdTester2_Stop
   .Caption="Stop Tester2.Wav"
cmdBoth_Stop
   .Caption="Stop Both"
cmdTester1_Pause
   .Caption="Pause Tester1.Wav"
cmdTester2_Pause
   .Caption="Pause Tester2.Wav"
cmdBoth_Pause
   .Caption="Pause Both"
(5) Затем финальная часть (уфф!) - флажки
chTester1_Loop

    .Caption="Tester1.Wav Loop"
chTester2_Loop
    .Caption="Tester2.Wav Loop"
chBoth_Loop
    .Caption="Loop Both Sounds"

Теперь, у вас должен быть интерфейс.

Затем, нам надо создать код, который будет все это связывать воедино. Это короткие отрезки кода для каждого элемента управления, которые будут задавать работу этих элементов управления. Помните, не запускайте проект после того как напишете эти строки, вы получите кучу сообщений об ошибках (Мы ведь не написали еще весь код!). Код для скролл баров будет показан позже, так как для него требуется более тщательный разбор...

Если вы присваивали элементам управления такие же имена, как у меня, можете просто копировать эти строки в вашу программу.

Private Sub Form_Load()
    Me.Show
    On Local Error Resume Next

    'Сначала нам надо создать объект DSound. Это должно быть сделано прежде, чем использовать любые его возможности
    'Это также должно быть сделано перед созданием.
    Set m_ds = m_dx.DirectSoundCreate("")
    'Эти строки проверяют наличие ошибок, если ошибок нет, то у пользователя установлен DirectX7 и работающая звуковая карта
    If Err.Number <> 0 Then
        MsgBox "Unable to start DirectSound. Check to see that your sound card is properly installed"
        End
    End If

    'ЭТО ДОЛЖНО БЫТЬ УСТАНОВЛЕНО ПЕРЕД СОЗДАНИЕМ БУФЕРОВ
    'DSSCL_PRIORITY=нет совместной работы. Эксклюзивный доступ к звуковой карте 
        ' Нужно для игр
    'DSSCL_NORMAL=совместная работа с другими приложениями
        'GПолезен для мультимедийных приложений Windows 
    m_ds.SetCooperativeLevel Me.hwnd, DSSCL_PRIORITY
    LoadWave  'Эта процедура будет создана позже. Потерпите...
End Sub

')))))))))))))))))))))(КОД ЦИКЛА ПРОИГРЫВАНИЯ)(((((((((((((((((((((((((((((((((((((((((((((
'Я сгруппировал все эти части вместе, так как они почти идентичны
'Во всех 3 случаях проверяется состояние флажков. Если он не установлен,
'тогда смотрим, есть ли что-нибудь в буферах? (Звк уже загружен?)
'В конце, проигрывание останавливается и "перематывается" в начало

'Проверка буфера - это ловушка для ошибки. Вы не можете изменять состояние буфера, когда
'он пуст. Если вмы бы попытались вызвать метод Stop для пустого буфера, получили бы ошибку

Private Sub chBoth_Loop_Click()
If chBoth_Loop.Value = 0 Then
If m_dsBuffer(0) Is Nothing And m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
m_dsBuffer(0).SetCurrentPosition 0
m_dsBuffer(1).Stop
m_dsBuffer(1).SetCurrentPosition 0
End If
End Sub

Private Sub chTester1_Loop_Click()
If chTester1_Loop.Value = 0 Then
If m_dsBuffer(0) Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
m_dsBuffer(0).SetCurrentPosition 0
End If
End Sub

Private Sub chTester2_Loop_Click()
If chTester2_Loop.Value = 0 Then
If m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(1).Stop
m_dsBuffer(1).SetCurrentPosition 0
End If
End Sub

'))))))))))))))))))))))))))(КОНЕЦ ЦИКЛА ПРОИГРЫВАНИЯ)((((((((((((((((((((((((((((

')))))))))))))))))))))))))))))))(КОД ПАУЗЫ)(((((((((((((((((((((((((
'И снова я сгруппировал их вместе, потому что они почти одинаковы
'Метод buffer.Stop вызывает паузу в проигрывании содержимого буфера.
'Чтобы исполнить команду "Стоп", т. е. с перемоткой назад, вам надо указать еще вернуться
'назад (это позже). Если вы прикажете выполнить паузу, то следующий вызов команды
'Play продолжит проигрывание с прерванного места

Private Sub cmdBoth_Pause_Click()
If m_dsBuffer(0) Is Nothing And m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
m_dsBuffer(1).Stop
End Sub

Private Sub cmdTester1_Pause_Click()
If m_dsBuffer(0) Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
End Sub

Private Sub cmdTester2_Pause_Click()
If m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(1).Stop
End Sub
')))))))))))))))))))))))))(КОНЕЦ КОДА ПАУЗЫ)((((((((((((((((((((((((((((((((

')))))))))))))))))))))))))))))))(КОД ОСТАНОВКИ)((((((((((((((((((((((
' И опять все вместе

'Эти процедуры останавливают звук и "перематывают" его на начало.

Private Sub cmdBoth_Stop_Click()
If m_dsBuffer(0) Is Nothing And m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
m_dsBuffer(0).SetCurrentPosition 0 
m_dsBuffer(1).Stop
m_dsBuffer(1).SetCurrentPosition 0
End Sub

Private Sub cmdTester1_Stop_Click()
If m_dsBuffer(0) Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
m_dsBuffer(0).SetCurrentPosition 0
End Sub

Private Sub cmdTester2_Stop_Click()
If m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(1).Stop
m_dsBuffer(1).SetCurrentPosition 0
End Sub

'))))))))))))))))))))))))))))))))))))))))))))))))))(КОНЕЦ КОДА ОСТАНОВКИ)((((((((((((((((((((((((((((((

Это первая ступень в создании кода. Помните, что пока нельзя запускать проект, вы получите сообщение об ошибке 

Создание загрузочной процедуры

Слудующей ступенью создания программы будет написание процедуры, загружающей звук в буфер. Назовем ее "LoadWave". Помните, мы ее еще упоминали в процедуре Form_Load? Вот код:


Sub LoadWave()

    Dim bufferDesc As DSBUFFERDESC 'этот новый объект передается DS, чтобы описать, какой буфер создается
    'Очень похоже на описание поверхности DirectDraw
    Dim waveFormat As WAVEFORMATEX
    'Эти утановки выполняются почти для каждого приложения 
    bufferDesc.lFlags = DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLPAN Or DSBCAPS_CTRLVOLUME Or DSBCAPS_STATIC

    waveFormat.nFormatTag = WAVE_FORMAT_PCM
    waveFormat.nChannels = 2    'Два канала
    waveFormat.lSamplesPerSec = 22050 '22 kHz можете конечно менять, если разбираетесь.......
    waveFormat.nBitsPerSample = 16  '16 бит лучше чем 8 (лучше качество)
    waveFormat.nBlockAlign = waveFormat.nBitsPerSample / 8 * waveFormat.nChannels
    waveFormat.lAvgBytesPerSec = waveFormat.lSamplesPerSec * waveFormat.nBlockAlign
    'Следующие строки создают буфер с указанным файлом, загруженным в него
    '"BufferDesc" и "WaveFormat" описывают свойства буфера. Их можно менять только при создании буфера...

    Dim sFile As String
    sFile = App.Path & "\tester1.wav" 'Этот файл должен быть в папке проекта......
    Set m_dsBuffer(0) = m_ds.CreateSoundBufferFromFile(sFile, bufferDesc, waveFormat)
    sFile = App.Path & "\tester2.wav"
    Set m_dsBuffer(1) = m_ds.CreateSoundBufferFromFile(sFile, bufferDesc, waveFormat)
    'Проверяет на ошибки
    If Err.Number <> 0 Then ' Просто выдает сообщение об ошибке (0 = все нормально)
        MsgBox "unable to find " + sFile
        End
    End If

    'Проверяет "свойства" паннинга и громкости
    scrlTester1_Pan_Change 'Вместо того, чтобы писать код снова, просто
    scrlTester1_Vol_Change 'вызывается процедура, в которой он находится.........
    scrlTester2_Pan_Change
    scrlTester2_Vol_Change
End Sub

Примечание: если вы получите сообщение об ошибке, но вы знаете, что файлы находятся на своих местах, возможно то, что они записаны в неправильном формате. Вы не можете заметить разницу, пока не загрузите их, но некоторые wav файлы записаны в формате PCM (то, что требует DirectSound), а некоторые нет. Если это произойдет, выберите другие файлы.

Пусть она заиграет!

Наконец-то мы получим полезные свойства от нашей программы...
Следующий код можете скопировать в поцедуры
cmdBoth_Play
cmdTester1_Play
cmdTester2_Play


Private Sub cmdBoth_Play_Click()
Dim flag As Long
flag = 0 'Значение будет меняться при изменении флажка
If chBoth_Loop.Value <> 0 Then flag = 1 'Решим, зацикливать ли проигрывание
m_dsBuffer(0).Play flag
m_dsBuffer(1).Play flag
'Когда вы применяете метод "m_dsbuffer(*).play", вы можете указать режим "DSBPLAY_NORMAL" 
'и "DSBPLAY_LOOPING", переменная flag выполняет то же, 0 = нормально, 1=зацикленно.
End Sub

'Следующие две процедуры почти идентичны
Private Sub cmdTester1_Play_Click()
Dim flag As Long
flag = 0
If chTester1_Loop.Value <> 0 Then flag = 1
m_dsBuffer(0).Play flag
End Sub

Private Sub cmdTester2_Play_Click()
Dim flag As Long
flag = 0
If chTester2_Loop.Value <> 0 Then flag = 1 
m_dsBuffer(1).Play flag
End Sub

OK, теперь у нас есть хоть что-то полезное. Следующий раздел будет еще интересней.

Добавление эффектов громкости и паннинга

Использование громкости очень просто, а паннинг вам обязательно пригодится. Если вы делаете "приставочную" игру, вы можете использовать эту функцию, чтобы звук исходил справа или слева от игрока, добавляя новое измерение в окружение. Это также очень просто.

Вы уже должны были нарисовать ScrollBar'ы и установить их свойства, так что просто скопируйте этот код в ваш проект.


Private Sub scrlTester1_Pan_Change()
If m_dsBuffer(0) Is Nothing Then Exit Sub 'Если буфер пуст, то с ним нельзя что-либо делать
m_dsBuffer(0).SetPan scrlTester1_Pan.Value
End Sub

Private Sub scrlTester1_Vol_Change()
If m_dsBuffer(0) Is Nothing Then Exit Sub
m_dsBuffer(0).SetVolume scrlTester1_Vol.Value
End Sub

Private Sub scrlTester2_Pan_Change()
If m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(1).SetPan scrlTester2_Pan.Value
End Sub

Private Sub scrlTester2_Vol_Change()
If m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(1).SetVolume scrlTester2_Vol.Value
End Sub

Все ужасно просто. Но вы наверное хотите узнать максимальные/минимальные установки громкости и паннинга:

Громкость колеблется от -5000 (тишина) до 0 (самая громкая). Это всего лишь "проценты " от громкости, установленной в Панели Управления Windows. Если громкость там установлена очень тихой, то любые изощрения не приведут к более громкому результату.

Паннинг принимает значения от -10 000 (Левое ухо) до 0 (Все ухи :-) и до 10 000 (Правое ухо)

Ну вот и все!

Обзор сделанного

OK, чего это мы тут натворили?
Мы сделали программу, которая помещает Wav файлы в память и проигрывает их с установленными значениями громкости и баланса звука (паннинг).

На что надо обратить внимание:

Хранение звуков занимает RAM, так что разумные пределы 5-6 маленьких звуков. Если вы занрузите 10 или больше больших звуков в память, быстродействие оставит желать лучшего. В моих планах размещение учебника, в котором показано как проигрывать файл по мере загружения (streaming) вместо хранения его в памяти (как только так сразу - переведем! :) Прим. перев.)

А самые любопытные могут загрузить готовую программу прямо сейчас. Размер 100кб.

Have fun.

Перевод на русский язык (c)2000 Antiloop
Публикуется с разрешения автора.
Полное или частичное цитирование перевода
только с разрешения переводчика. Пишите!

Р Е К Л А М А