Звук в iOS

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

Звук в iOS. Фото.

К сожалению, звук – одно из слабых мест iOS с точки зрения разработчика. В официальной документации (https://developer.apple.com/library/ios/#referencelibrary/GettingStarted/AudioVideoStartingPoint_iOS/_index.html) можно найти детальное описание только одного метода воспроизведения – с помощью класса AVAudioPlayer, а так же поверхностные упоминания Audio Queue и OpenAL. Немного углубившись в документацию, можно найти еще один способ – использование системных звуков. Но однозначно определиться с тем, что же нужно в каждом конкретном случае, из документации не получится.

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

SystemSound

Подходит для коротких эффектов фиксированной громкости, в частности – клики, «бипы», звонки. Легко инициализируется, легко используется и очень слабо нагружет CPU. Из недостатков можно отметить поддержку ограниченного набора форматов (только .wav и .cif), фиксированную громкость и возможность воспроизведения только одного звука за раз.

Для того что бы инициализировать и воспроизвести файл click.wav, достаточно:

SystemSoundID clickSound;
AudioServicesCreateSystemSoundID(
CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("click"), CFSTR("wav"), NULL),
&clickSound);
AudioServicesPlaySystemSound(clickSound);

И, конечно же, не надо забывать удалять ненужные звуки:

AudioServicesDisposeSystemSoundID(clickSound);

SystemSound находится во фреймфорке AudioToolbox.

AVAudioPlayer

Универсальный метод: поддерживает все форматы, которые поддерживает iOS, воспроизводит неограниченное количество файлов одновременно, позволяет регулировать громкость, но… очень сильно нагружает CPU и достаточно медленно загружает файлы. Впрочем, последний отмеченный недостаток достаточно условный, потому что к воспроизведению звуковых файлов плеер можно подготовить заранее, во время загрузки приложения.

// Инициализируем плеер файлом castaned.wav
NSString* path = [[NSBundle mainBundle] pathForResource:@"castaned" ofType:@"wav"];
AVAudioPlayer* player = [[AVAudioPlayer alloc]
initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
// Устанавливаем необходимую громкость и подготавливаемся
// к воспроизведению.
[player setVolume:1.0f];
[player prepareToPlay];
// Воспроизводим подготовленный файл.
[player play];

AVAudioPlayer находится во фреймворке AVFoundation. Полную документация доступна на https://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAudioPlayerClassReference/Reference/Reference.html.

OpenAL

Обрисовать OpenAL одним словом элементарно – это OpenGL в мире аудио. В принципе, это понятно из названия. На developer.apple.com по OpenAL – всего один пример (MyOpenALSupport). Из неофициальной документации следовало бы отметить сайт gehacktes.net, но он уже перестал существовать. К счастью, не так давно я успел скачать с него небольшой враппер вокруг OpenAL и немного оптимизировать его – теперь он включен в демо к этой статье и на GitHub (https://github.com/ashvetsov/MyOpenAL), где каждый желающий его может «склонировать» и использовать.

Как и SystemSound, OpenAL поддерживает ограниченный набор форматов, однако этот недостаток компенсируется его производительностью и функциональностью.

// Инициализируем OpenAL и загружаем файл castaned.wav
MyOpenAL* myOpenAL = myOpenAL = [[MyOpenAL alloc] init];
NSUInteger sound = [myOpenAL loadSoundFromFile:@"castaned" ext:@"wav" withLoop:false];
// Воспроизводим файл с заданной громкостью.
[myOpenAL playSoundWithId:soundOne atVolume:1.0f];

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

Вместо заключения

Все мы частенько восхищаемся тем, как сделаны приложения под iOS. Среди них попадаются реальные шедевры. Однако, если заглянуть за кулисы разработки под эту платформу (да по сути любой разработки), мы обнаруживаем: любую идею можно воплотить в жизнь минимум двумя разными способами. В случае со звуком – есть аж три способа, так что разгуляться есть где. Осталось призвать на помощь опыт: либо свой, который, как известно, «сын ошибок трудных», либо чужой — переняв его у того, кто уже испробовал разные возможности, т.е. таких как я +) А поможет в этом маленькое приложение, собранное на коленке.

Скачать готовый проект можно по ссылке.