Что это такое?
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();} |