Запись звука с использованием API FMOD

Дата публикации:2005
Twitter Facebook Vkontakte

Вступление

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

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

Ниже будет рассмотрена практическая реализация записи звука при помощи специальной библиотеки FMOD (в данном случае использована версия 3.74), предназначенной для работы со звуком в различных его ипостасях. Достоинством FMOD является ее многофункциональность: в предыдущих статьях уже рассматривалась работа с 3D звуком и использование спецификации EAX для создания эффектов пространственной реверберации. В данной статье нас будет интересовать исключительно запись звука.

Для примеров использован расширенный Си( или обычный Си++), позволяющий объявлять переменные в любом месте программы.

Последовательность действий

Процесс записи звука состоит из следующих этапов:

  1. Инициализация библиотеки FMOD;
  2. Выделение памяти для создания "пустого" звукового образца;
  3. Непосредственная запись звуковых данных с устройства записи;
  4. Воспроизведение записанных данных;
  5. Сохранение данных на диск.

Стоит заметить, что под устройствами ввода ниже подразумеваются аппаратные устройства, имеющиеся на компьютере и представленные, например, в Windows XP в диалоге "Звуки и аудиоустройства" (Панель управления->Звуки и аудиоустройства->вкладка Аудио->Группа "Запись"->Используемое по умолчанию устройство).

Однако у каждого такого устройства могут быть различные источники (входы) для записи звука, например, микрофон, линейный вход, микшер (wav/mp3), компакт-диск и т.д. Выбор конкретного источника производится пользователем в диалоге "Громкость" (Меню "Пуск"->Все программы->Стандартные->Развлечения->Громкость). Еще этот диалог может быть доступен из системного трея.

Инициализация FMOD

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

int FSOUND_Record_SetDriver (
	int driver /* номер устройства */
	);

Функция в качестве параметра получает номер устройства в системе (значение 0 соответствует устройству по умолчанию), а возвращает TRUE если выбор устройства прошел без ошибок и FALSE в противном случае.

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

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

int num_dev = FSOUND_Record_GetNumDrivers ();
char buf [256]; // промежуточный буфер для конвертации ANSI в OEM
for (int i=0; i< num_dev; i++)
{ 
	CharToOem (FSOUND_Record_GetDriverName (i), buf);
	puts (buf);
}

Запись звука в память

Создание звукового образца, которое можно условно назвать "резервированием места, куда будут записаны введенные звуковые данные", осуществляется функцией FSOUND_Sample_Alloc ():

FSOUND_SAMPLE * FSOUND_Sample_Alloc (
int index, /* индекс звукового пула */
int length, /* размер в отсчетах (сэмплах) */
unsigned int mode, /* параметры звукового образца */
int deffreq, /* частота дискретизации в герцах */
int defvol, /* громкость (0 - 255) */
int defpan, /* соотношение каналов (правый - левый (0 - 255)*/
int defpri /* приоритет (0 - 255)*/
);

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

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

int FSOUND_Record_StartSample (
FSOUND_SAMPLE *samp, /* указатель на звуковой образец */
signed char loop /* режим циклической записи */
);

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

Остановить запись можно при помощи функции FSOUND_Record_Stop(). Эта функция не имеет параметров и возвращает TRUE, если запись была благополучно остановлена, и FALSE в случае ошибки.

Получить номер текущего отсчета (сэмпла) в буфере звукового образца можно при помощи функции FSOUND_Record_GetPosition (). Функция не имеет параметров и возвращает номер отсчета в буфере звукового образца, куда происходит запись звука. В случае неудачи функция возвращает значение -1 (минус один).

Типичная процедура записи, приводимая в примерах к библиотеке FMOD, выглядит следующим образом:

// инициализация FMOD
if (!FSOUND_Init (22050, 32, 0)) 
{
// обработка ошибки
...
}
// Параметры звукового образца: стерео, 16 бит, 22050 герц
// Длительность: не более 10 секунд
int rec_rate = 22050;	// 22050 герц
int = rec_len = rec_rate * 10;	// 10 секундный буфер
FSOUND_SAMPLE *samp1 = FSOUND_Sample_Alloc(FSOUND_UNMANAGED, rec_len, FSOUND_STEREO | FSOUND_16BITS , rec_rate, 255, 128, 255);
if (!samp1)
{
// обработка ошибки
...
};
// Начинаем запись
	if (!FSOUND_Record_StartSample(samp1, FALSE)) 
{
// обработка ошибки
...
}
//Крутимся в цикле, пока указатель текущей позиции
// записи не достигнет конца буфера
// или пока не будет нажата клавиша
	do {
Sleep(50);
	} while (FSOUND_Record_GetPosition() < rec_len && !kbhit());
// Останавливаем запись
FSOUND_Record_Stop();	

Прослушивание записанного звука

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

// Создаем звуковой канал и воспроизводим звук
int channel;
channel = FSOUND_PlaySound(FSOUND_FREE, samp1);

Сохранение записанных данных на диск

К сожалению, FMOD не содержит встроенных функций, поддерживающих запись на диск файлов в формате wav. Если вы желаете сохранить записанные звуковые данные в этом формате, то вам придется самостоятельно сформировать wav-заголовок файла и сохранить файл обычными средствами работы с файловой системой.

Однако, если записанные звуковые данные предполагается использовать только внутри вашего приложения или игры, то можно сохранить звуковые данные в "чистом" виде (raw) ,без заголовков.

Для доступа к буферу звукового образца используются функции FSOUND_Sample_Unlock () и FSOUND_Sample_Lock (). При помощи этих функций можно получить непосредственный доступ к звуковым отсчетам (сэмплам) и сохранить их на диске стандартными средствами для работы с файлами (функции fopen (), fwrite (), fclose ()). Вот пример такого решения:

// Открываем файл для записи
FILE *f = fopen ("recdata.dat", "wb");
// Получаем доступ к звуковым данным в буфере звукового образца
// Буфер имеет кольцевую структуру, поэтому задается двумя указателями.
void *ptr1, *ptr2;
unsigned int len1, len2;
int length = rec_len * 4; // в байтах, сэмпл = 4 байта (стерео, 16 бит)
FSOUND_Sample_Lock(samp1, 0, length, &ptr1, &ptr2, &len1, &len2);
fwrite(ptr1, len1, 1, f);
if (len2) fwrite(ptr2, len2, 1, f);
FSOUND_Sample_Unlock(samp1, ptr1, ptr2, len1, len2);
fclose(f);

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

// Загружаем файл в буфер звукового образца 
FSOUND_SAMPLE *samp2 = FSOUND_Sample_Load (FSOUND_FREE, "recdata.dat", FSOUND_LOADRAW|FSOUND_STEREO | FSOUND_16BITS, 0,0);
if (!samp2)
{
// Обработка ошибки
...
}
// Устанавливаем параметры звука: частота, громкость, стереобаланс, приоритет
FSOUND_Sample_SetDefaults (samp2, rec_rate, 255, 128, 255);
// Воспроизводим звук
int channel2 = FSOUND_PlaySound(FSOUND_FREE, samp2);

Пример

В архиве представлен пример консольного приложения, демонстрирующего возможности записи звука. Пример компилировался средствами C++BUILDER COMMAND LINE TOOLS 5.2. В архив включены файлы record.cpp и make.bat. Загрузить пример (~1.5 Кб).



Распространение материалов сайта означает, что распространитель принял условия лицензионного соглашения.
Идея и реализация: © Владимир Довыденков и Анатолий Камынин,  2004-2017