Глава 7 - як відтворити файл wav
Як відтворити файл WAV
Я не ідіот - по крайней мере, моя дружина не називає так мене в відкриту, - так що тримаю парі, що ви головним чином хочете дізнатися про те, як відтворювати файли WAV. Я не можу придумати кращого способу навчання, ніж чудовий світ вихідних кодів. Так що завантажуйте проект DMusic_PlaySound з супровідних файлів до книги.
Програма DMusic_PlaySound демонструє як форматувати інтерфейси виконавця і завантажувача, завантажити сегмент і відтворити його.
проект DMusic_PlaySound
Програма містить кілька вихідних файлів: main.cpp. main.h і DXUtil.cpp. Всі вони є унікальними для даного проекту, за винятком файлу DXUtil.cpp. який є частиною набору допоміжних файлів DirectX SDK.
Проект використовує такі бібліотеки: dxguid.lib. winmm.lib і dsound.lib. Ви можете запитати, чому немає бібліотеки з ім'ям dmusic.lib. Я не знаю що вам відповісти. Microsoft вирішила помістити функції DirectMusic в бібліотеку DirectSound. Я припускаю, що це викликано тим, що вони здебільшого спільно використовують одну і ту ж логіку.
Щось я давно не показував вам нових ілюстрацій. Погляньте на рис. 7.1, де показаний основний потік виконання прикладу програми.

Мал. 7.1. Потік виконання програми DMusic_PlaySound
На рис. 7.1 видно, що WinMain () викликає функцію bInitializeSoundSystem (). Ця функція ініціалізації виконує кілька викликів функцій DirectX для ініціалізації звукової системи. Потім програма очікує події миші і відтворює файл WAV за допомогою функції vPlaySound (). Якщо ви ще цього не зробили, запустіть програму і клацніть по її вікна лівою кнопкою миші щоб відтворити файл WAV. Хіба вам не сподобався цей чудовий тестовий файл WAV? Гей, я знаю, що він не особливо вражає. Якщо ви хочете поекспериментувати, замініть файл testsound.wav одним з ваших власних звукових файлів. Програма повинна працювати з будь-яким WAV-файлом.
Заголовки Main.h
Відкрийте заголовки main.h і йдіть за мною. Заголовки в цьому прикладі дуже простий і короткий. Ось він цілком:
Список включення файл не повинен піднести вам багато сюрпризів. В основному це звичайні файли, що включаються для Windows-програми. Єдиний файл, що додається спеціально для DirectMusic - це dmusici.h.
У розділі прототипів функцій з'явилися дві нові функції: bInitializeSoundSystem () і vPlaySound (). Призначення обох очевидно з їх назв. (Хіба ви не любите самодокументіруемий код?)
Наступний блок коду заголовки містить глобальні змінні, які я використовую в програмі. Якщо ви прочитали попередній розділ цієї глави, вони повинні виглядати для вас дуже знайоме. Інтерфейс g_pLoader використовується для завантаження звукового файлу, інтерфейс g_pPerformance призначений для відтворення звуку, а інтерфейс g_pSound містить завантажувані з звукового файлу дані.
Я зовсім не заохочую вас використовувати глобальні змінні в коді. Я застосовую їх в прикладах тільки для того, щоб зробити код як можна простіше.
Файл програми Main.cpp
Головна частина коду розташована в файлі програми main.cpp. Прийшов час відкрити його. Як завжди, на нашу увагу вимагає функція WinMain (). Вона містить стандартний код ініціалізації програми Windows і кілька нових викликів функцій. Ось фрагмент коду, який повинен зацікавити вас:
Я викликаю функцію bInitializeSoundSystem () відразу після того, як створено вікно програми. Функція отримує один параметр - дескриптор вікна. Якщо функція повертає 0, значить її виконання закінчилося невдало. В цьому випадку я виводжу на екран вікно з повідомленням про помилку і завершую роботу програми після того, як користувач клацне по кнопці OK. В іншому випадку все працює як передбачалося і виконання коду триває.
Функція bInitializeSoundSystem ()
Ох хлопці, зараз почнеться справжні веселощі. Ця функція містить весь код, необхідний для ініціалізації DirectMusic. Крім того, вона виконує завантаження звукового файлу, що відтворюється програмою.
Як форматувати COM
Перша річ, яку повинен зробити код, - ініціалізація COM. DirectX використовує COM-інтерфейси, так що це неминуче зло (або добро). Якщо ви не знайомі з COM, я рекомендую вам піти в улюблений книжковий магазин і подивитися кілька книг, присвячених цій технології. Виклик для ініціалізації виглядає наступним чином:
Виключно просто, правда? На щастя, це все, що потрібно зробити для ініціалізації COM. Після цього ви можете створювати інтерфейси DirectX.
Створення інтерфейсу завантажувача
Наступний фрагмент коду створює інтерфейс завантажувача. Як ви, можливо, пам'ятаєте, інтерфейс завантажувача відповідає за завантаження звукових даних, таких як файли WAV і файли MIDI. Ось як виглядає відповідний код:
Для отримання інтерфейсу завантажувача я викликаю функцію CoCreateInstance (). Інтерфейс IDirectMusicLoader8 використовує CLSID CLSID_DirectMusicLoader і ідентифікатор інтерфейсу IID_IDirectMusicLoader8. Покажчик на інтерфейс зберігається в глобальній змінній g_pLoader.
Я знаю, що якщо ви не знайомі з COM, все це може здаватися вам трохи чужим, але приводів для занепокоєння немає. Вам достатньо просто скопіювати цей код в свою власну програму. Потреба модифікувати наведений тут код ініціалізації DirectMusic виникає вкрай рідко.
Створення інтерфейсу виконавця
Інтерфейс завантажувача зайняв призначене йому місце, а наступним етапом буде створення інтерфейсу виконавця. Інтерфейс виконавця відповідає за відтворення аудіо та життєво важливий для DirectMusic. Ось як виглядає код ініціалізації цього інтерфейсу:
І знову для створення інтерфейсу я застосовую функцію CoCreateInstance (). Інтерфейс IDirectPerformance8 використовує CLSID CLSID_DirectMusicPerformance і ідентифікатор інтерфейсу IID_DirectMusicPerformance8. Покажчик на інтерфейс я зберігаю в глобальній змінній g_pPerformance.
ініціалізація аудіосистеми
На відміну від завантажувача, виконавець вимагає, щоб після успішного створення інтерфейсу була виконана його ініціалізація. Це завдання здійснюється функцією IDirectMusicPerformance8 :: InitAudio (). яка ініціалізує виконавця і встановлює для нього аудіо-шлях. Ось як виглядає прототип функції:
Перший параметр, ppDirectMusic. дозволяє функції повернути створений інтерфейс DirectMusic. Якщо значення цього параметра дорівнює NULL. то інтерфейс DirectMusic створюється і використовується всередині об'єкта виконавця. Я вважаю за краще використовувати NULL. оскільки це спрощує код.
Другий параметр призначений для тих же цілей, що і перший, за винятком того, що від зберігає або повертає інтерфейс DirectSound. Для цього параметра я також вважаю за краще використовувати значення NULL.
Третій параметр, hWnd. призначений для передачі дескриптора того вікна для якого створюється інтерфейс DirectSound. Якщо значення параметра дорівнює NULL. використовується фонове вікно. Я вважаю за краще використовувати тут NULL.
Четвертий параметр, dwDefaultPathType. задає тип аудіо-шляху за замовчуванням. Можливі значення перераховані в таблиці 7.4.
Таблиця 7.4. Типи аудіо-шляху
З доступних типів я зазвичай використовую DMUS_APATH_DYNAMIC_STEREO оскільки він надає можливості, необхідні для стереофонічного звукового супроводу.
П'ятий параметр, dwPChannelCount. задає кількість використовуваних в аудіо шляху каналів виконавця. У розглянутому прикладі я використовую чотири канали.
Шостий параметр, dwFlags. дозволяє вам задати набір функціональних можливостей, які ви хочете бачити в об'єкті виконавця. Доступні прапори і їх призначення описані в таблиці 7.5.
Таблиця 7.5. Прапори функціональних можливостей виконавця
У розглянутому прикладі я використовую прапор DMUS_AUDIOF_ALL. Він вказує об'єкту виконавця використовувати будь-які доступні можливості. Це зручний варіант, що дозволяє користувачеві відключити окремі можливості, які можуть привести до зниження швидкодії.
Сьомий параметр, pParams. дозволяє задати бажані аудіо параметри у вигляді структури даних DMUS_AUDIOPARAMS. Я зазвичай використовую повернуться до стандартних значень і вказую тут NULL.
Функція ініціалізації аудіосистеми виконала свою роботу. Останній крок, необхідний для ініціалізації інтерфейсу виконавця - виклик функції IDirectMusicPerformance8 :: GetDefaultAudioPath (). повертає аудіо-шлях за замовчуванням, створений функцією ініціалізації аудіосистеми. Аудіо-шлях потрібно для установки рівня гучності. Якщо ви не бажаєте зв'язуватися з регулюванням гучності, можна пропустити цей етап.
Ось як виглядає код, описуваний в наведеному вище тексті:
Як регулювати гучність
Як я натякав раніше, інтерфейс IDirectMusicAudioPath8 дозволяє вам регулювати рівень гучності. Для цього призначена функція SetVolume (). прототип якої виглядає наступним чином:
Перший параметр, lVolume. встановлює бажаний рівень гучності в сотнях децибел. Допустимі значення від -9600 до 0. Значення 0 відповідає максимальній гучності.
Другий параметр, dwDuration. задає період часу за який здійснюється зміна гучності. Якщо його значення дорівнює 0, система змінить гучність як тільки це буде можливо.
Ось як виглядає використовуваний в прикладі код:
Завантаження звукового файлу
Ви пам'ятаєте інтерфейс завантажувача, який створили хвилину назад? Пора знову скористатися ним для завантаження тестового файлу WAV, включеного до файлів. Щоб зробити це, звернемося до функції LoadObjectFromFile (). Перед тим, як я покажу вам її прототип, погляньте на код з програми:
У коді я використовую функцію завантаження файлу, щоб завантажити WAV-файл з жорсткого диска. Потім я завантажую сегмент в об'єкт виконавця для відтворення. Ось що видно з висоти пташиного польоту.
Прототип функції LoadObjectFromFile () виглядає наступним чином:
У першому параметрі, rguidClassID. повинен бути переданий унікальний ідентифікатор класу. Для завантаження в сегмент використовуйте ідентифікатор класу CLSID_DirectMusicSegment.
Другий параметр, iidInterfaceID. повинен бути унікальним ідентифікатором інтерфейсу. Для завантаження в сегмент використовуйте IID_IDirectMusicSegment8.
Третій параметр, pwzFilePath. є ім'ям завантаження. У розглянутому прикладі я використовую файл testsound.wav. Ви можете помітити букву L перед рядком з ім'ям файлу. Я помістив її тому, що в даному параметрі має наймення в кодуванні Unicode (де для представлення одного символу використовуються два байти).
Як завантажити сегмент
Тепер ви повинні завантажити сегмент в об'єкт виконавця. Це завдання виконує функція IDirectMusicSegment8 :: Download (). прототип якої виглядає так:
Як приємно і просто. Всього один параметр, який є покажчиком на інтерфейс, в який завантажується сегмент. Я в даному параметрі передаю покажчик на об'єкт виконавця g_pPerformance.
Погляньте на рис. 7.2, щоб побачити описані до цього моменту етапи.
Мал. 7.2. Етапи ініціалізації DirectMusic
На рис. 7.2 видно, як ви ініціалізували COM, створили завантажувач, створили виконавця, ініціалізували аудіосистему, отримали аудіо-шлях за замовчуванням, встановили рівень гучності, завантажили файл і, нарешті, завантажили сегмент WAV. Цей набір кроків буде повторюватися кожен раз, коли ви будете використовувати в своїх програмах DirectMusic, так що запам'ятайте його (або принаймні, закладіть цю сторінку).
Функція vPlaySound ()
Приклад програми обробляє події лівої кнопки миші і викликає при кожній події функцію vPlaySound (). Обробкою подій займається функція fnMessageProcessor (). але що представляє інтерес код виконується в функції відтворення звуку. Давайте поглянемо на код цієї функції:
Функція vPlaySound () дуже проста. Фактично вона складається з єдиного виклику функції IDirectMusicPerformance8 :: PlaySegmentEx ().
відтворення звуку
Функція PlaySegmentEx () починає відтворення завантаженого сегмента. У неї є кілька параметрів, але як бачите, в коді мого прикладу значення багатьох з них рівні NULL. Ось як виглядає прототип функції:
У першому параметрі, pSource. передається покажчик на інтерфейс відтвореного об'єкта. У даній програмі я використовую глобальний покажчик на сегмент, завантаження якого була виконана раніше.
Другий параметр, pwzSegmentName. в DirectX 9.0 не використовується.
Третій параметр, pTransition. дозволяє задати модуляцію для сегмента. Я передаю в цьому параметрі NULL.
Четвертий параметр, dwFlags. дозволяє вам вказати набір прапорів, що визначають різні параметри відтворення. У розглянутому прикладі для цього параметра я використовую прапори DMUS_SEGF_DEFAULT і DMUS_SEGF_SECONDARY. Ці прапори вказують, що сегмент відтворюється в його межах за замовчуванням і що сегмент відтворюється як вторинний звук. Доступно ще багато інших прапорів, і я рекомендую вам подивитися їх опис в документації DirectX SDK.
П'ятий параметр, i64StartTime. задає потрібний проміжок часу для сегмента. Я передаю в цьому параметрі NULL щоб відтворення звуку почалося негайно.
Сьомий параметр, pFrom. дозволяє вказати інтерфейс для зупинки відтворення коли стартує новий сегмент. Тут я також передаю NULL.
Восьмий параметр, pAudioPath. повідомляє системі який аудіо-шлях використовується для відтворення сегмента. Я привласнюю цим параметром значення NULL щоб для відтворення використовувався аудіо-шлях за замовчуванням.
Тепер запустіть програму і натисніть кілька разів по її вікна лівою кнопкою миші. Важлива особливість програми полягає в тому, що вона може одночасно відтворювати кілька звуків. Це може не справити на вас великого враження, якщо ви ніколи раніше не займалися відтворенням звуку, але повірте мені - це дуже круто. Чудово те, що DirectMusic за вас виконує всю необхідну буферизацию.