Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Мультимедиа для Windows

© Александр Фролов, Григорий Фролов
Том 15, М.: Диалог-МИФИ, 1994, 284 стр.

[Назад] [Содеожание] [Дальше]

2.1. Самые простые способы воспроизведения звука

В самом простейшем случае приложение должно уметь выдавать звуковые сигналы или проигрывать небольшие звуковые сообщения при появлении каких-либо непредвиденных событий, когда нужно привлечь внимание пользователя. Для этого можно воспользоваться функциями MessageBeep и sndPlaySound .

Функция MessageBeep

Ранее, в предыдущих томах "Библиотеки системного программиста", мы упоминали функцию MessageBeep :

void MessageBeep(UINT uAlert);

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

Если же звуковой драйвер установлен, в зависимости от значения параметра uAlert функция MessageBeep может воспроизводить один из звуковых фрагментов, записанных в wav-файле.

Обратите внимание, что в файле win.ini имеется раздел [sound], в котором перечислены различные ситуации. Для ситуации может быть указано имя wav-файла, который должен быть воспроизведен при ее возникновении:

[sounds]
SystemAsterisk=chimes.wav,Asterisk
SystemHand=ding.wav,Critical Stop
SystemDefault=,Default Beep
SystemExclamation=ding.wav,Exclamation
SystemQuestion=ding.wav,Question
SystemExit=bye.wav,Windows Exit
SystemStart=,Windows Start

У вас нет необходимости изменять этот раздел вручную, так как это можно сделать при помощи приложения Control Panel (рис. 1.8).

Возможные значения параметра uAlert для функции MessageBeep приведены в следующей таблице.

Значение Описание
-1 Стандартный звуковой сигнал, который выдается на встроенный в компьютер динамик
MB_ICONASTERISK Проигрывается wav-файл, определенный в строке SystemAsterisk раздела [sound] файла win.ini
MB_ICONEXLAMATION Аналогично для строки SystemExclamation
MB_ICONHAND Аналогично для строки SystemHand
MB_ICONQUESTION Аналогично для строки SystemQuestion
MB_OK Аналогично для строки SystemDefault

Функция MessageBeep пытается проиграть звуковой фрагмент в асинхронном (фоновом) режиме, если это позволяет звуковой драйвер. Если в системе установлен драйвер Sound Driver for PC Speaker, функция MessageBeep возвращает управление только после того, как проигрывание будет закончено. Если же функция не может проиграть нужный фрагмент, будет "исполнен" стандартный системный звук, определенный в строке SystemDefault раздела [sound] файла win.ini. Если же и это невозможно, вы услышите "бип" из встроенного в компьютер динамика.

Функция sndPlaySound

А есть ли простой способ проигрывания произвольного wav-файла?

Есть, и он действительно прост. Этот способ основан на использовании функции sndPlaySound , которая находится в библиотеке mmsystem.dll. Ее прототип определен в файле mmsystem.h:

BOOL sndPlaySound(LPCSTR lpszSoundFile, UINT wFlags);

Через параметр lpszSoundFile этой функции можно передать путь к wav-файлу, идентификатор ресурса, содержащего звуковой фрагмент (вы можете записать звуковой фрагмент в ресурсы приложения), или текстовую строку, определенную в разделе [sound] файла win.ini.

Параметр wFlags определяет способ проигрывания звукового фрагмента. Используются следующие значения (некоторые из них можно комбинировать при помощи операции ИЛИ):

Значение Описание
SND_SYNC Синхронный режим работы. Функция sndPlaySound вернет управление только после завершения проигрывания звукового фрагмента
SND_ASYNC Асинхронный режим работы. Функция вернет управление немедленно, проигрывание звукового фрагмента будет выполняться в фоновом режиме параллельно с работой приложения
SND_NODEFAULT Если указанный файл не найден, функция "тихо" возвращает управление, не проигрывая никаких звуков. Если же этот флаг не указан, и файл не найден, будет проигран стандартный системный звук, определенный в строке SystemDefault раздела [sound] файла win.ini. А если и это невозможно, функция не будет ничего проигрывать и вернет значение FALSE
SND_MEMORY Это значение используется для проигрывания звуковых файлов, загруженных в оперативную память, например, из ресурсов приложения
SND_LOOP Если указано значение SND_ASYNC, проигрывание звукового фрагмента будет зациклено. Для того чтобы остановить проигрывание, необходимо вызвать функцию sndPlaySound, указав ей в качестве параметра lpszSoundFile значение NULL
SND_NOSTOP При указании этого значения функция проверяет, выполняется ли в настоящий момент проигрывание фрагмента. Если да, функция возвращает значение FALSE

Во всех случаях, если не указан параметр SND_NOSTOP, функция sndPlaySound возвращает значение TRUE, если выполняется проигрывание, и FALSE - если нет. Учтите, что при использовании функций MessageBeep и sndPlaySound есть ограничение на размер wav-файла - он должен целиком помещаться в физическую память. Поэтому самые простые способы проигрывания звуковых фрагментов хороши только для относительно небольших файлов.

Приложение SNDPLAY

Наше первое приложение SNDPLAY, имеющее зачатки мультимедиа, предназначено для демонстрации различных способов работы с функцией sndPlaySound (листинг 2.1).


Листинг 2.1. Файл sndplay\sndplay.cpp


// ----------------------------------------
// Использование функций
// MessageBeep и sndPlaySound
// ----------------------------------------
#define STRICT
#include <windows.h>
#include <mmsystem.h>

#pragma argsused
int PASCAL
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpszCmdLine, int nCmdShow)
{
   HANDLE hWaveRes, hRes;
   LPSTR lpRes;
   BOOL rc;
   HFILE hf;
   DWORD dwFileSize;
   HGLOBAL hWave;
   char huge *lpBuf;

   // Проигрываем звук, соответствующий строке
   // SystemQuestion раздела [sound] файла win.ini
   MessageBeep(MB_ICONQUESTION);

   MessageBox(NULL, "Начнем, что ли?",
     "SndPlay", MB_OK | MB_ICONQUESTION);

   // Проигрываем файл sndplay.snd в синхронном режиме
   rc = sndPlaySound((LPSTR)"sndplay.wav", SND_SYNC);
   if(!rc)
   {
     MessageBeep(MB_ICONHAND);
     MessageBox(NULL, "Не могу проиграть файл sndplay.wav",
       "SndPlay", MB_OK | MB_ICONHAND);
     return -1;
   }

   // Загружаем звуковой фрагмент из ресурсов приложения
   // и проигрываем его

   // Находим нужный ресурс
   hWaveRes = FindResource(hInstance, "APP_SOUND", "WAVE");
   if(hWaveRes)
   {
     // Загружаем ресурс в память
     hRes = LoadResource(hInstance, (HRSRC)hWaveRes);
     if(hRes)
     {
       // Фиксируем ресурс в памяти, получая
       // указатель на данные
       lpRes = (LPSTR)LockResource(hRes);
       if(lpRes)
       {
         // Проигрываем звук в цикле
         rc = sndPlaySound(lpRes, SND_MEMORY | SND_ASYNC | SND_LOOP);

         MessageBox(NULL,
           "Для завершения нажмите кнопку OK",
           "SndPlay", MB_OK | MB_ICONINFORMATION);

         // Останавливаем проигрывание
         sndPlaySound(NULL, 0);

         // Расфиксируем и освобождаем ресурс
         UnlockResource(hRes);
         FreeResource(hRes);

         // Загружаем звуковой фрагмент непосредственно из
         // wav-файла в память и проигрываем его

         // Открываем wav-файл
         hf = _lopen((LPSTR)"uff.wav", OF_READ);

         // Определяем размер файла
         dwFileSize = _llseek(hf, 0l, 2);
         _llseek(hf, 0l, 0);

         // Заказываем глобальный блок памяти,
         // размер которого равен длине файла
         hWave = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwFileSize);

         // Фиксируем блок памяти
         lpBuf = (char huge *)GlobalLock(hWave);
         if(lpBuf != NULL)
         {
           // Читаем файл в полученный блок памяти
           _hread(hf, lpBuf, dwFileSize);

           // Проигрываем звуковой фрагмент, загруженный в память
           rc = sndPlaySound((LPCSTR)lpBuf, SND_MEMORY | SND_SYNC);
           if(!rc)
           {
             MessageBeep(MB_ICONHAND);
             MessageBox(NULL, "Не могу проиграть файл uff.wav",
               "SndPlay", MB_OK | MB_ICONHAND);
           }

           // Расфиксируем и освобождаем память
           GlobalUnlock(hWave);
           GlobalFree(hWave);

           // Закрываем файл
           _lclose(hf);
         }
       }
     }
   }
   return 0;
}

Приложение не имеет главного окна и функции окна. Сразу после запуска приложение SNDPLAY вызывает функцию MessageBeep, с помощью которой проигрывается звук, соответствующий строке SystemQuestion раздела [sound] файла win.ini.

Затем приложение вызывает функцию sndPlaySound для проигрывания файла sndplay.wav в синхронном режиме:

rc = sndPlaySound((LPSTR)"sndplay.wav", SND_SYNC);

Как только этот файл будет проигран, функция sndPlaySound вернет управление и работа приложения будет продолжена.

Далее приложение загружает звуковой фрагмент из ресурсов и проигрывает его асинхронно в циклическом режиме. При этом на экран выводится диалоговая панель с сообщением о то, что для прекращения циклического проигрывания следует нажать кнопку OK. Методика работы с ресурсами была описана нами в 12 томе "Библиотеки системного программиста". После поиска и фиксирования ресурса адрес соответствующего блока памяти передается в качестве первого параметра функции sndPlaySound:

rc = sndPlaySound(lpRes, SND_MEMORY | SND_ASYNC | SND_LOOP);

Так как звуковой файл находится в памяти, во втором параметре этой функции необходимо указать флаги SND_MEMORY и SND_ASYNC. Для циклического проигрывания следует также указать флаг SND_LOOP.

Для прерывания циклического проигрывания функция sndPlaySound вызывается с нулевыми параметрами:

sndPlaySound(NULL, 0);

В некоторых случаях может оказаться удобным проигрывать звуковой фрагмент, загруженный в память не из ресурсов приложения, а непосредственно из wav-файла. Финальная часть приложения SNDPLAY демонстрирует этот способ.

Вначале приложение открывает wav-файл с помощью функции _lopen и определяет его размер, вызывая функцию _llseek :

hf = _lopen((LPSTR)"uff.wav", OF_READ);
dwFileSize = _llseek(hf, 0l, 2);
_llseek(hf, 0l, 0);

Далее приложение заказывает глобальный блок памяти такого размера, чтобы в нем мог поместиться весь wav-файл. Блок фиксируется в памяти:

hWave = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwFileSize);
lpBuf = (char huge *)GlobalLock(hWave);

Теперь, если передать адрес этого блока функции sndPlaySound, можно проиграть его в асинхронном или синхронном режиме. Так как мы освобождаем память сразу после возврата управления из функции sndPlaySound, для простоты мы выбрали синхронный режим:

rc = sndPlaySound((LPCSTR)lpBuf, SND_MEMORY | SND_SYNC);

Только после того, как проигрывание закончено, можно расфиксировать и освободить память с образом wav-файла:

GlobalUnlock(hWave);
GlobalFree(hWave);

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

Файл ресурсов приложения (листинг 2.2) содержит описание ресурса типа WAVE (можно использовать любой другой нестандартный тип ресурса):


Листинг 2.2. Файл sndplay\sndplay.rc


APP_SOUND WAVE loop.wav
APPICON ICON "sndplay.ico"

Файл определения модуля приложения SNDPLAY приведен в листинге 2.3.


Листинг 2.3. Файл sndplay\sndplay.def


NAME        SNDPLAY
DESCRIPTION 'Приложение SNDPLAY, (C) 1994, Frolov A.V.'
EXETYPE     windows
STUB        'winstub.exe'
STACKSIZE   5120
HEAPSIZE    1024
CODE        preload moveable discardable
DATA        preload moveable multiple

[Назад] [Содеожание] [Дальше]