Введение в Simple DirectMedia Layer

         

Что это такое?


SDL - бесплатный кроссплатформенный мультимедийный программный интерфейс приложения

- http://www.libsdl.org/

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

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



Что она может делать?




Видео

Установка видеорежима с любой глубиной цвета (от 8 бит и выше) с необязательным преобразованием, если режим не поддерживается аппаратно.

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

Создание поверхностей с атрибутами прозрачности или альфа-сопряжения (alpha blending).

Копирование поверхностей с автоматическим преобразованием в целевой формат, используя оптимизированные процедуры копирования и, по возможности, аппаратное ускорение. На платформе x86 имеется MMX оптимизированные процедуры копирования.

Используется аппаратное ускорение операций копирования и заполнения, если это поддерживается оборудованием.

Совет:

Вы можете установить строку заголовка вашего приложения и иконку, используя функции SDL_WM_SetCaption() и SDL_WM_SetIcon() соответственно.

События

Предусмотрены события для:

Изменения вида приложения

Ввода с клавиатуры

Ввода мыши

Выхода по требованию пользователя

Каждое событие может быть разрешено или запрещено функцией SDL_EventState().

События передаются через указанную пользователем фильтрующую функцию перед отправлением их во внутреннюю очередь событий.

Очередь событий надежна при использовании потоков (thread-safe).

Совет:

Используйте SDL_PeepEvents() для поиска событий конкретного типа в очереди событий.

Звук

Воспроизведение 8-ми и 16-ти битных звуков, моно или стерео, с необязательным преобразованием, если формат не поддерживается оборудованием.

Звук запускается независимо в отдельном потоке, используя для заполнения механизм пользовательской функции обратного вызова (callback).

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

Совет:

Используйте функции SDL_LockAudio()

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

CD-ROM аудио

Полный API для управления CD аудио

Совет:

Если вы передадите NULL в качестве дескриптора CD-ROM в любую функцию CD-ROM API, это будет действовать как последний открытый CD-ROM.

Потоки

Простой API для создания потоков

Простые двоичные семафоры для синхронизации

Совет:

Не используйте функции библиотеки C касающиеся ввода/вывода и управления памятью из потоков, если вы можете избежать их– они блокируют ресурсы, используемые другими потоками.

Таймеры

Получение прошедшего числа миллисекунд

Ожидание указанного числа миллисекунд

Установка одиночных периодических таймеров с точностью 10 мс

Совет:

Вы можете спокойно заменить Win32 GetTickCount() на SDL_GetTicks().

Независимость от порядка байтов в слове

Определение порядка байтов в текущей системе

Процедуры для быстрого обмена значений

Чтение и запись данных с указанным порядком байтов

Совет:

При чтении ваших файлов данных вам может потребоваться перестановка байтов в 16-битной графике.

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


Инициализация библиотеки


Используйте SDL_Init() для динамической загрузки и инициализации библиотеки. Эта функция принимает набор флагов, соответствующих частям, которые Вы хотите активизировать:

SDL_INIT_AUDIO

SDL_INIT_VIDEO

SDL_INIT_CDROM

SDL_INIT_TIMER

Используйте SDL_Quit() для выгрузки библиотеки и освобождения ресурсов по окончанию работы.

Совет:

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

Пример:

 #include <stdlib.h>#include "SDL.h" main(int argc, char *argv[]){    if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 ) {        fprintf(stderr, "Не могу инициализировать SDL: %s\n", SDL_GetError());        exit(1);    }    atexit(SDL_Quit);     ...}

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



Использование CD-ROM audio


Открытие CD-ROM устройства для последующего использования 

Во можете узнать количество CD-Rom устройств в системе вызвав функцию SDL_CDNumDrives() и затем открыть один из них, вызвав SDL_CDOpen(). 

Основной (по умолчанию) CD-ROM всегда 0. Заметьте, что CD-ROM устройство может быть открыто, даже если в дисковод не вставлен диск. 

Для определения текущего состояния устройства вы можете воспользоваться функцией SDL_CDStatus(). По завершении использования CD-ROM устройства, закройте его функцией SDL_CDClose(). 

Совет:

Вы можете определить системное имя CD-ROM дисковода используя SDL_CDName() функцию. 

Пример: 

{    SDL_CD *cdrom;     if ( SDL_CDNumDrives() > 0 ) {        cdrom = SDL_CDOpen(0);        if ( cdrom == NULL ) {            fprintf(stderr, "Не могу открыть CD-ROM по умолчанию: %s\n" SDL_GetError());            return;        }         ...         SDL_CDClose(cdrom);    }}

Воспроизведение CD-ROM дисков 

CD-ROM диски используют время в MSF формате (mins/secs/frames = минуты/секунды/кадры) или непосредственно в кадрах. Кард - это стандартная единица времени для CD, равная 1/75 секунды. SDL использует кадры вместо MFS формата когда определяет длину трека и текущее положение, но вы всегда можете конвертировать один формат в другой с помощью макросов FRAMES_TO_MSF() и MSF_TO_FRAMES(). 

SDL не обновляет автоматически информацию с структуре SDL_CD пока вы не вызовете SDL_CDStatus(), таким образом вы должны вызывать SDL_CDStatus каждый раз, когда вам надо узнать, что за диск вставлен в дисковод и какие треки на нем доступны. Заметьте, что первый трек имеет индекс 0. 

SDL имеет две функции для воспроизведения CD-ROM. Вы можете как играть определенный трек, используя функцию SDL_CDPlayTracks(), так и устанавливать смещение от начала всего диска, используя SDL_CDPlay(). 

SDL не предусматривает автоматическое оповещение при вставке CD или при завершении воспроизведения. Для отслеживания этих ситуаций вы должны периодически производить опрос состояния устройства с помощью SDL_CDStatus().

Совет:

Чтобы понять, какие треки - аудио треки, а какие - треки данных, вы можете прочитать cdrom->tracks[track].type, и сравнить с SDL_AUDIO_TRACK и SDL_DATA_TRACK. 

Пример: 

void PlayTrack(SDL_CD *cdrom, int track){    if ( CD_INDRIVE(SDL_CDStatus(cdrom)) ) {        SDL_CDPlayTracks(cdrom, track, 0, track+1, 0);    }    while ( SDL_CDStatus(cdrom) == CD_PLAYING ) {        SDL_Delay(1000);    }}

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



Использование таймеров


Получение текущего времени в миллисекундах 

SDL_GetTicks() говорит, сколько миллисекунд прошло с произвольно выбранного момента. 

Совет:

В основном, когда пишутся игры, оптимальным вариантом является движение объектов, основанное на времени (чем на количестве кадров). То есть, при очередном проходе по циклу следует смещать объект не на какое-то постоянное значение, а на значение, пропорциональное прошедшему с последнего прохода по циклу времени. Это позволит держаться игре с постоянной скоростью как на мощных, так и на слабых машинах. 

Пример: 

#define TICK_INTERVAL    30 Uint32 TimeLeft(void){    static Uint32 next_time = 0;    Uint32 now;     now = SDL_GetTicks();    if ( next_time <= now ) {        next_time = now+TICK_INTERVAL;        return(0);    }    return(next_time-now);}

Задержка 

Функция SDL_Delay() позволяет установить задержку на какое-то количество миллисекунд. 

Поскольку ОС, поддерживающие SDL, в большинстве своем многозадачные, вызов это функции не дает гарантии, что программа задержится ровно на данное время! Чаще эта функция просто вызывается для небольшой задержки. 

Совет:

Большинство ОС имеют планировщик временных участков с интервалом около 10 миллисекунд. Вы можете использовать SDL_Delay(1) как способ оставить CPU текущий временной участок, позволив выполниться остальным потокам. Так чаще всего делают, когда необходимо выпонять свой поток в быстром непрерывном цикле, но также необходимо, чтобы и другие потоки (например, аудио) тоже выполнялись.

Пример:

{    while ( game_running ) {        UpdateGameState();        SDL_Delay(TimeLeft());    }} 

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



На каких платформах выполняется?


Linux

Используется X11 в качестве дисплея, беря преимущества XFree86 DGA расширений и новое MTRR ускорение для полноэкранного режима.

Используется OSS API  для работы со звуком.

Потоки обеспечиваются использованием или системным вызовом clone()  и SysV IPC, или потоками библиотеки glibc-2.1.

Совет:

Вы можете получить часть скрытого интерфейса драйвера SDL через функцию SDL_GetWMInfo(). Это позволит вам делать вещи наподобие удаления оформления окна и задавать иконку вашего приложения.

Win32

Две версии, одна надежная для всех систем, основанна на Win32 API, а другая высокопроизводительная, основанна на DirectX API.

Надежная версия использует GDI для отображения графики. Высокопроизводительная версия использует DirectDraw для работы с видео, по возможности используя преимущества аппаратного ускорения.

Надежная версия использует waveOut API для воспроизведения звука. Высокопроизводительная версия использует DirectSound для воспроизведения звука.

Совет:

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

BeOS

BDirectWindow используется для графики.

BSoundPlayer API используется для звука.

Совет:

Linux и BeOS поддерживают флаг SDL_INIT_EVENTTHREAD, который при передачи в SDL_Init() запрашивает запуск обработки очереди сообщений в отдельном потоке. Это полезно для окраски курсора, реагируя, таким образом, когда приложение занято.

MacOS, MacOS X

Carbon и DrawSprockets используется для графики.

SoundManager API используется для звука.

Преимущественно родная поддержка потоков в MacOS X

Неофициально перенесены, в процессе переноса

Solaris, IRIX, FreeBSD, QNX, OSF/True64

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



Независимость от порядка байтов


Определение порядка байтов в текущей системе

Препроцессор C заменяет SDL_BYTEORDER на SDL_LIL_ENDIAN (младше-конечные) или SDL_BIG_ENDIAN (старше-конечные), в зависимости от порядка байтов в текущей системе.

Младше-конечные системы это те, которые пишут данные на диск размещая так:

     [младшие байты] [старшие байты]

Старше-конечные системы пишут данные на диск так:

     [старшие байты] [младшие байты]

Совет:

В системах x86 младший байт-первый (little-endian), PPC наоборот (big-endian).

Example:

 #include "SDL_endian.h" #if SDL_BYTEORDER == SDL_LIL_ENDIAN#define SWAP16(X)    (X)#define SWAP32(X)    (X)#else#define SWAP16(X)    SDL_Swap16(X)#define SWAP32(X)    SDL_Swap32(X)#endif

Обмен данных между системами с различным порядком байтов

SDL предоставляет совокупность быстродействующих макросов в SDL_endian.h, SDL_Swap16() и SDL_Swap32(), которые производят обмен данными с указаным вами порядком байтов. Также определены макросы для обмена данными со специфичным для данной системы порядком байтов.

Совет:

Если вам нужно знать порядок байтов в текущей системе, но не нужны все перестановочные функции, подключите SDL_byteorder.h вместо SDL_endian.h

Пример:

 #include "SDL_endian.h" void ReadScanline16(FILE *file, Uint16 *scanline, int length){    fread(scanline, length, sizeof(Uint16), file);    if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) {        int i;        for ( i=length-1; i >= 0; --i )            scanline[i] = SDL_SwapLE16(scanline[i]);    }}

[Назад] Содержание



О разработчике:


Sam Lantinga, Инженер по программному обеспечению в Blizzard Entertainment.

Фоновая деятельность:

Главный программист в Loki Software, Inc. с января 1999 по август 2001.

Автор Simple DirectMedia Layer (SDL)

Перенос Maelstrom с Macintosh в Linux

Работа по переносу Macintosh emulator Executor в Win32

Перенос утилит от DOOM из DOS (DEU, DHE, и др.)

Другие проекты: http://www.devolution.com/~slouken/

Связь:

slouken@libsdl.org



Перевод на русский язык:


Скиданов Александр

mailto:shd@bk.ru

http://morgeyz.narod.ru/

Сашнов Александр

mailto:sashnov@ngs.ru

http://sashnov.chat.ru/

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



Потоки


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

Создание потока делается через вызов функции SDL_CreateThread(). После успешного возврата из функции ваша функция теперь запущена одновременно с основным приложением в своем контексте задачи (стек, регистры и прочее) и может получать доступ к памяти и открытым файлам используемыми в основном приложении. 

Совет:

Второй аргумент для SDL_CreateThread() передается как параметр для  порожденного потока. Вы можете использовать его для передачи значений в стек или только как указатель на данные, которые будут использоваться в потоке.

Пример:

#include "SDL_thread.h" int global_data = 0; int thread_func(void *unused){    int last_value = 0;     while ( global_data != -1 ) {        if ( global_data != last_value ) {            printf("Data value changed to %d\n", global_data);            last_value = global_data;        }        SDL_Delay(100);    }    printf("Thread quitting\n");    return(0);} {    SDL_Thread *thread;    int i;     thread = SDL_CreateThread(thread_func, NULL);    if ( thread == NULL ) {        fprintf(stderr, "Unable to create thread: %s\n", SDL_GetError());        return;    }     for ( i=0; i<5; ++i ) {        printf("Changing value to %d\n", i);        global_data = i;        SDL_Delay(1000);    }     printf("Signaling thread to quit\n");    global_data = -1;    SDL_WaitThread(thread, NULL);}

<
Синхронизация доступа к ресурсу

Вы можете предотвращать доступ к ресурсу более чем из одного потока с помощью создания семафора и получать доступ к ресурсу, окружая доступ вызовом блокировки (SDL_mutexP()) и разблокировки (SDL_mutexV()).
Совет:

Любые данные, которые могут быть доступны более чем одному потоку одновременно, должны быть защищены семафорами.

Пример: 

#include "SDL_thread.h"#include "SDL_mutex.h" int potty = 0;int gotta_go; int thread_func(void *data){    SDL_mutex *lock = (SDL_mutex *)data;    int times_went;     times_went = 0;    while ( gotta_go ) {        SDL_mutexP(lock);    /* Lock  the potty */        ++potty;        printf("Thread %d using the potty\n", SDL_ThreadID());        if ( potty > 1 ) {            printf("Uh oh, somebody else is using the potty!\n");        }        --potty;        SDL_mutexV(lock);        ++times_went;    }    printf("Yep\n");    return(times_went);} {    const int progeny = 5;    SDL_Thread *kids[progeny];    SDL_mutex  *lock;    int i, lots;     /* Create the synchronization lock */    lock = SDL_CreateMutex();     gotta_go = 1;    for ( i=0; i<progeny; ++i ) {        kids[i] = SDL_CreateThread(thread_func, lock);    }     SDL_Delay(5*1000);    SDL_mutexP(lock);    printf("Everybody done?\n");    gotta_go = 0;    SDL_mutexV(lock);     for ( i=0; i<progeny; ++i ) {        SDL_WaitThread(kids[i], &lots);        printf("Thread %d used the potty %d times\n", i+1, lots);    }    SDL_DestroyMutex(lock);}
<


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


Для ожидания события воспользуйтесь функцией



Ожидание событий
Для ожидания события воспользуйтесь функцией SDL_WaitEvent().
Совет:

SDL имеет международную поддержку клавиатуры, трансляцию событий клавиатуры и помещение эквивалента UNICODE в event.key.keysym.unicode. Так как это требует дополнительной обработки, это должно быть разрешено функцией SDL_EnableUNICODE().


Пример:
 {    SDL_Event event;     SDL_WaitEvent(&event);     switch (event.type) {        case SDL_KEYDOWN:            printf("The %s key was pressed!\n",                   SDL_GetKeyName(event.key.keysym.sym));            break;        case SDL_QUIT:            exit(0);    }}


Опрос событий
Для опроса событий используйте SDL_PollEvent().
Совет:

Вы можете считывать события из очереди без их удаления оттуда, используя параметр SDL_PEEKEVENT в функции SDL_PeepEvents().


Пример:
 {    SDL_Event event;     while ( SDL_PollEvent(&event) ) {        switch (event.type) {            case SDL_MOUSEMOTION:                printf("Mouse moved by %d,%d to (%d,%d)\n",                        event.motion.xrel, event.motion.yrel,                       event.motion.x, event.motion.y);                break;            case SDL_MOUSEBUTTONDOWN:                printf("Mouse button %d pressed at (%d,%d)\n",                       event.button.button, event.button.x, event.button.y);                break;            case SDL_QUIT:                exit(0);        }    }}


Опрос состояния событий
В дополнение к обработке событий непосредственно, каждый тип события имеет функцию, которая позволяет проверить состояние приложения. Если вы используете только эту функцию, вы должны игнорировать все события от функции SDL_EventState() и периодически вызывать SDL_PumpEvents() для обработки приложением событий.
Совет:

Вы можете скрывать и показывать системный курсор мыши используя SDL_ShowCursor().


Пример:
 {    SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);} void CheckMouseHover(void){    int mouse_x, mouse_y;     SDL_PumpEvents();     SDL_GetMouseState(&mouse_x, &mouse_y);    if ( (mouse_x < 32) && (mouse_y < 32) ) {        printf("Mouse in upper left hand corner!\n");    }}
<

Содержание:


О разработчике и переводчиках

Simple DirectMedia Layer

Что это такое?

SDL – бесплатный кросс платформенный мультимедийный API для разработчиков

Использование для  игр

Использование для игровых SDK

Использование для эмуляторов

Использование для демонстраций

Использование для мультимедиа-приложений

Что она может делать?

Видео

События

Звук

CD-ROM аудио

Потоки

Таймеры

Независимость от порядка байтов (endian independence)

На каких платформах выполняется?

Linux

Win32

BeOS

Неофициально перенесены, в процессе переноса

Использование Simple DirectMedia Layer API

Инициализация библиотеки

Видео

Выбор и установка разрешения и глубины цвета (простой способ)

Рисование точек (pixels) на экране

Загрузка и отображение рисунков

События

Ожидание событий

Опрос событий

Опрос состояния события

Звук

Открытие аудио устройства

Загрузка и воспроизведение звука

CD-ROM аудио

Открытие CD-Rom привода для последующего использования

Проигрывание CD-Rom'а

Потоки

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

Синхронизация доступа к ресурсам

Таймеры

Получение текущего времени в миллисекундах

Ожидание указанного количества миллисекунд

Порядок байтов (endian independence)

Определение порядка байтов в текущей системе

Обмен данными между системами с различным порядком байтов

[Дальше]



Видео


Выбор и установка разрешения и глубины цвета  (простой способ)

Просто выберите свое любимое разрешение и глубину цвета и установите его!

Совет #1:

Вы можете узнать оптимальную глубину, поддерживаемую аппаратурой, используя функцию SDL_GetVideoInfo().

Совет #2:

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

Пример:

 { SDL_Surface *screen;     screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);    if ( screen == NULL ) {// Если установить разрешение не удалось        fprintf(stderr, "Невозможно установить разрешение 640x480: %s\n", SDL_GetError());        exit(1);    }}

Рисование точек (pixels) на экране

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

 
Совет:

Если вам предстоит рисовать много объектов, лучше заблокировать (lock) экран единожды перед рисованием, вывести все объекты на экран, сохраняя список областей, требующих обновления, и разблокировать (unlock) экран вновь перед обновлением экрана.

Пример:

Рисование точки на экране необходимым цветом

 void DrawPixel(SDL_Surface *screen, Uint8 R, Uint8 G, Uint8 B){    Uint32 color = SDL_MapRGB(screen->format, R, G, B);     if ( SDL_MUSTLOCK(screen) ) {        if ( SDL_LockSurface(screen) < 0 ) {            return;        }    }    // Смотрим, сколькими байтами кодируется каждый пиксель (bytes per pixel, bpp)    switch (screen->format->BytesPerPixel) {        case 1: { /* Если 8-bpp */            Uint8 *bufp;             bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;            *bufp = color;        }        break;         case 2: { /* Если 15-bpp или 16-bpp */            Uint16 *bufp;             bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;            *bufp = color;        }        break;         case 3: { /* Медленный 24-bpp режим, обычно не используется */            Uint8 *bufp;             bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;            *(bufp+screen->format->Rshift/8) = R;            *(bufp+screen->format->Gshift/8) = G;            *(bufp+screen->format->Bshift/8) = B;        }        break;         case 4: { /* Наверное, 32-bpp */            Uint32 *bufp;             bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;            *bufp = color;        }        break;    }    if ( SDL_MUSTLOCK(screen) ) {        SDL_UnlockSurface(screen);    }    SDL_UpdateRect(screen, x, y, 1, 1);}

<
Загрузка и отображение рисунков

Для вашего удобства, SDL предоставляет единственную функцию для загрузки изображений, SDL_LoadBMP().  Библиотека для загрузки изображений может быть найдена в архиве с демонстрациями SDL (SDL demos archive).

Вы можете отобразить загруженную картинку, используя SDL_BlitSurface() для копирования ее в видеобуфер. SDL_BlitSurface() автоматически усекает копируемую область, которая должна быть передана SDL_UpdateRects() для обновления изменившейся части экрана.

Совет #1:

Если вам необходимо показывать некоторую картинку много раз, вы можете ускорить вывод, конвертировав ее в формат дисплея. Для этого используется функция SDL_DisplayFormat()

Совет #2:

Большинство изображений спрайтов имеют прозрачный фон. Вы можете разрешит копирование с прозрачностью (colorkey blit) функцией SDL_SetColorKey().

Пример:

 void ShowBMP(char *file, SDL_Surface *screen, int x, int y){    SDL_Surface *image;    SDL_Rect dest;     /* Загрузим BMP файл на поверхность */    image = SDL_LoadBMP(file);    if ( image == NULL ) {        fprintf(stderr, "Couldn't load %s: %s\n", file, SDL_GetError());        return;    }     /* Блитируем (копируем) на экранную поверхность.       Поверхность не должна быть заблокирована (locked).     */    dest.x = x;    dest.y = y;    dest.w = image->w;    dest.h = image->h;    SDL_BlitSurface(image, NULL, screen, &dest);     /* Обновим измененную часть экрана */    SDL_UpdateRects(screen, 1, &dest);}
[Назад] Содержание [Дальше]


Звук


Открытие аудио устройства

Вам необходима callback-функция, которая будет смешивать ваши аудио данные и помещать их в аудио поток. Затем необходимо выбрать желательный аудио формат и частоту, и открыть аудио устройство.

Воспроизведение не начнется до тех пор, пока вы не вызовете SDL_PauseAudio(0). Эта функция позволяет выполнить действия, которые необходимо выполнить до вызова CallBack функции. Как только вы завершите использование звука, закройте его функцией SDL_CloseAudio().

Совет:

Если ваша программа оперирует с различными звуковыми форматами, передайте вторым параметром указатель на SDL_AudioSpec  в SDL_OpenAudio(), чтобы получить текущий аппаратный аудио формат. Если же вы оставите второй указатель равным NULL, аудио данные будут конвертированы в аппаратный аудио формат во время выполнения.

Пример:

 #include "SDL.h"#include "SDL_audio.h"{    extern void mixaudio(void *unused, Uint8 *stream, int len);    SDL_AudioSpec fmt;     /* Установить 16бит стерео с 22Khz */    fmt.freq = 22050;    fmt.format = AUDIO_S16;    fmt.channels = 2;    fmt.samples = 512;        /* Хорошее значение для игр */    fmt.callback = mixaudio;    fmt.userdata = NULL;     /* открыть аудио усройство и начать воспроизведение! */    if ( SDL_OpenAudio(&fmt, NULL) < 0 ) {        fprintf(stderr, "Не могу открыть аудио: %s\n", SDL_GetError());        exit(1);    }    SDL_PauseAudio(0);     ...     SDL_CloseAudio();}

Загрузка и воспроизведение звука

Для вашего удобства, SDL предоставляет единственную функцию для загрузки звука, SDL_LoadWAV(). После того, как вы загрузили звук, вы должны преобразовать его к звуковому формату выходного потока с помощью функции SDL_ConvertAudio(), и сделать его доступным для вашей функции микширования.

Совет:

Устройства SDL audio предназначены для низкоуровневого программного аудио микшера. Хорошую реализацию такого микшера, доступную по LGPL лицензии, можно найти в архиве SDL demos.

<


Пример:

 #define NUM_SOUNDS 2struct sample {    Uint8 *data;    Uint32 dpos;    Uint32 dlen;} sounds[NUM_SOUNDS]; void mixaudio(void *unused, Uint8 *stream, int len){    int i;    Uint32 amount;     for ( i=0; i<NUM_SOUNDS; ++i ) {        amount = (sounds[i].dlen-sounds[i].dpos);        if ( amount > len ) {            amount = len;        }        SDL_MixAudio(stream, &sounds[i].data[sounds[i].dpos], amount, SDL_MIX_MAXVOLUME);        sounds[i].dpos += amount;    }} void PlaySound(char *file){    int index;    SDL_AudioSpec wave;    Uint8 *data;    Uint32 dlen;    SDL_AudioCVT cvt;     /* Найти пустой ( или до конца воспроизведенный) звуковой слот */    for ( index=0; index<NUM_SOUNDS; ++index ) {        if ( sounds[index].dpos == sounds[index].dlen ) {            break;        }    }    if ( index == NUM_SOUNDS )        return;     /* Открыть аудио файл и конвертировать его в 16-bit stereo 22kHz */    if ( SDL_LoadWAV(file, &wave, &data, &dlen) == NULL ) {        fprintf(stderr, "Couldn't load %s: %s\n", file, SDL_GetError());        return;    }    SDL_BuildAudioCVT(&cvt, wave.format, wave.channels, wave.freq,                            AUDIO_S16,   2,             22050);    cvt.buf = malloc(dlen*cvt.len_mult);    memcpy(cvt.buf, data, dlen);    cvt.len = dlen;    SDL_ConvertAudio(&cvt);    SDL_FreeWAV(data);     /* Поместить данные в слот (воспроизведение начнется немедленно) */    if ( sounds[index].data ) {        free(sounds[index].data);    }    SDL_LockAudio();    sounds[index].data = cvt.buf;    sounds[index].dlen = cvt.len_cvt;    sounds[index].dpos = 0;    SDL_UnlockAudio();}
[Назад] Содержание [Дальше]