|
Июн
09
|
В продолжение темы, рассмотренной в частях 1 и 2, мы будем и дальше работать с созданным ранее проектом, но на этот раз освоим воспроизведение базовых звуков. Для загрузки и озвучки воспользуемся одним из примеров Apple, который можно найти в Apple Developer Network под именем BubbleLevel (к сожалению, прямой ссылки нет, поскольку нужно входить под собственным логином).
Шаг 1
Итак, нам предстоит добавить к проекту аудиофайлы. iPhone дружит с форматом CAF. Использовать его не обязательно, но если решите, о создании и преобразовании CAF-файлов можно прочесть здесь (на английском языке) http://permadi.com/blog/?p=927. В нашем примере я будут работать с одним CAF-файлом и с одним MP3.
Импортируйте оба файла в группу “Resources” точно так же, как это делали это с изображениями (удерживая нажатой клавишу <Ctrl>, щелкните на пиктограмме “Resources” и выберите “Add Existing Files“).

Шаг 2
Добавьте файлы “SoundEffect.m” и “SoundEffect.h” из примера BubbleLevel (если его нет, скачайте zip-архив в конце статьи). Удерживая нажатой клавишу <Ctrl>, щелкните на группе “Classes” и выберите “Add Existing Files“.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | /* File: SoundEffect.h Abstract: SoundEffect is a class that loads and plays sound files. Version: 1.6 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Copyright (C) 2008 Apple Inc. All Rights Reserved. */ #import #import @interface SoundEffect : NSObject { SystemSoundID _soundID; } + (id)soundEffectWithContentsOfFile:(NSString *)aPath; - (id)initWithContentsOfFile:(NSString *)path; - (void)play; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | /* File: SoundEffect.m Abstract: SoundEffect is a class that loads and plays sound files. Version: 1.6 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Copyright (C) 2008 Apple Inc. All Rights Reserved. */ #import "SoundEffect.h" @implementation SoundEffect // Creates a sound effect object from the specified sound file + (id)soundEffectWithContentsOfFile:(NSString *)aPath { if (aPath) { return [[[SoundEffect alloc] initWithContentsOfFile:aPath] autorelease]; } return nil; } // Initializes a sound effect object with the contents of the specified sound file - (id)initWithContentsOfFile:(NSString *)path { self = [super init]; 62. // Gets the file located at the specified path. if (self != nil) { NSURL *aFileURL = [NSURL fileURLWithPath:path isDirectory:NO]; // If the file exists, calls Core Audio to create a system sound ID. if (aFileURL != nil) { SystemSoundID aSoundID; OSStatus error = AudioServicesCreateSystemSoundID((CFURLRef)aFileURL, &aSoundID); if (error == kAudioServicesNoError) { // success _soundID = aSoundID; } else { NSLog(@"Error %d loading sound at path: %@", error, path); [self release], self = nil; } } else { NSLog(@"NSURL is nil for path: %@", path); [self release], self = nil; } } return self; } // Releases resouces when no longer needed. -(void)dealloc { AudioServicesDisposeSystemSoundID(_soundID); [super dealloc]; } // Plays the sound associated with a sound effect object. -(void)play { // Calls Core Audio to play the sound for the specified sound ID. AudioServicesPlaySystemSound(_soundID); } @end |
Теперь группа “Classes” должна выглядеть так, как показано ниже.

Если попытаться выполнить компиляцию, появится следующее сообщение об ошибке:
“_AudioServicesPlaySystemSound”, referenced from:
-[SoundEffect play] in SoundEffect.o
“_AudioServicesDisposeSystemSoundID”, referenced from:
-[SoundEffect dealloc] in SoundEffect.o
“_AudioServicesCreateSystemSoundID”, referenced from:
-[SoundEffect initWithContentsOfFile:] in SoundEffect.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Шаг 3
Ошибка означает, что компоновщик не смог найти часть используемых приложением функций. Поскольку ничего нового за исключением класса “SoundEffect” не добавлялось, значит, дело в звуке. Определить нужный фреймворк в некоторых случаях затруднительно, поэтому предлагаю на выбор два варианта:
а) проанализируйте пример BubbleLevel и найдите нужные фреймворки либо
б) попробуйте копнуть глубже, открыв окно Xcode Developer Documentation и выполнив поиск недостающих функций (нижнее подчеркивание в имени функции не требуется — его добавляет компилятор). В результате поиска “AudioServicesCreateSystemSoundID“, обнаруживаем, что ему необходим фреймворк “AudioToolbox“.

Есть еще один вариант: откройте проблемный файл (”SoundEffect.o” — компилированный obj файл класса “SoundEffect“) — и в “SoundEffect.h” увидите оператор импорта “: import“.
Предлагаю включить данный фреймворк в проект. Разверните меню группы “Target“, выберите “Link Binary With Libraries” и выполните “Add ->Existing Frameworks“.

В появившемся диалоговом окне щелкните на нижней пиктограмме
и добавьте выделенный “AudioToolbox.framework“.

Выполните компиляцию заново — ошибка должна исчезнуть.
Шаг 3
Время браться за код.
Взглянув на “SoundEffect.h“, оценим доступные методы. Работать будем с “initWithContentsOfFile” поскольку… Да просто это единственный доступный вариант. На самом деле все очень легко: создается объект “SoundEffect” и вызывается функция “play“. Так, например, приведенный ниже код предназначен для проигрывания “audio.mp3“.
1 2 3 | SoundEffect* soundEffect=[[SoundEffect alloc]; initWithContentsOfFile:[mainBundle pathForResource:@"audio" ofType:@"mp3"]]]; soundEffect.play(); |
Что такое “mainBundle“? По определению Apple, под термином “main bundle” понимается пакет файлов приложения, т.е. его упаковщик приложения — папка с именем приложения и расширением .app. Для получения адресной ссылки на нее достаточно вызвать “[NSBundle mainBundle]” (об этом чуть ниже).
Отредактируйте “Ball.h” и добавьте переменную для хранения объекта “SoundEffect“.
1 2 3 4 5 6 7 8 9 10 11 12 13 | #import @class SoundEffect; @interface Ball : UIImageView { int mXSpeed; int mYSpeed; float mAngle; SoundEffect* mSoundEffect; } - (void)move; - (void)setSpeedX:(int)xSpeed Y:(int)ySpeed; - (void)setSoundEffect:(SoundEffect*)soundEffect; @end |
К файлу “Ball.m” добавьте “#import” и функцию “setSoundEffect“.
1 2 3 4 5 6 7 | #import "SoundEffect.h" ... - (void)setSoundEffect:(SoundEffect*)soundEffect { mSoundEffect=soundEffect; } |
Отредактируйте функцию “move” в файле “Ball.m” так, чтобы при ударе мяча о края экрана воспроизводился “SoundEffect“.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | - (void)move { self.center=CGPointMake(self.center.x + mXSpeed, self.center.y + mYSpeed); if (!CGRectContainsRect(self.superview.frame, self.frame)) { Boolean bHit=false; if (self.frame.origin.x { bHit=true; mXSpeed=abs(mXSpeed); } if (self.frame.origin.x>self.superview.frame.size.width-self.frame.size.width) { bHit=true; mXSpeed=-abs(mXSpeed); } if (self.frame.origin.y<0)//self.superview.frame.origin.y) { bHit=true; mYSpeed=abs(mYSpeed); } if (self.frame.origin.y>self.superview.frame.size.height-self.frame.size.height) { bHit=true; mYSpeed=-abs(mYSpeed); } if (bHit) { [mSoundEffect play]; } } self.transform=CGAffineTransformMakeRotation (mAngle); mAngle+=0.1; } |
Файл “BallViewController.m” измените для загрузки и привязки звукового файла к объектам-мячам.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | - (void)viewDidLoad { [super viewDidLoad]; NSBundle *pMainBundle = [NSBundle mainBundle]; mBallArray = [[NSMutableArray alloc] init]; UIImage* image1=[UIImage imageNamed:@"ball1.png"]; UIImage* image2=[UIImage imageNamed:@"ball2.png"]; SoundEffect* sound1=[[SoundEffect alloc] initWithContentsOfFile:[pMainBundle pathForResource:@"ding1" ofType:@"caf"]]; SoundEffect* sound2=[[SoundEffect alloc] initWithContentsOfFile:[pMainBundle pathForResource:@"ding2" ofType:@"mp3"]]; int i; for (i = 0; i < 10; i++) { UIImage* image; SoundEffect* sound; if ((i%2)==0) { image=image1; sound=sound1; } else { image=image2; sound=sound2; } Ball* ball=[[Ball alloc] initWithImage:image]; [mBallArray addObject:ball]; [self.view addSubview:ball]; int speed=random() % 10; [ball setSpeedX:speed Y:speed]; [ball setSoundEffect:sound]; ball.center=self.view.center; } [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:@selector(moveBall) userInfo:nil repeats:YES]; } |
Выделив память для двух объектов “SoundEffect” — ding1.caf и ding2.mp3, я переключался между ними, связывая первый с мячами с четным индексом, второй, соответственно, — с нечетными мячами.
Данная строка получает main bundle для “initWithContentsOfFile:“.
1 | NSBundle *pMainBundle = [NSBundle mainBundle]; |
Должен предупредить о некоторых сложностях, ограничивающих возможности “AudioTolbox“, хотя для основной массы игр их вполне достаточно.
- “AudioServicesPlaySystemSound” воспроизводит аудиофайлы, не превышающие по длительности 30 с.
- Попытка запустить тот же файл до окончания его воспроизведения чревата последующими ошибками (например, очередной вызов аудиофайла не даст ничего кроме тишины).
Решить вторую проблему поможет незначительное редактирование кода, чтобы во время воспроизведения звуковой файл не запускался повторно.
Откорректируйте файл “SoundEffect.h” и добавьте переменную, сигнализирующую о процессе воспроизведения звука. При проигрывании аудиофайла флаг устанавливается на “true“.
1 2 3 4 | @interface SoundEffect : NSObject { SystemSoundID _soundID; Boolean isPlaying; } |
Дополнительно к этому модифицируем функцию в файле “SoundEffect.m“, чтобы она проверяла воспроизведение аудио и в нужный момент устанавливала флаг. Кроме того, инициируем “AudioServicesAddSystemSoundCompletion” для “вызова” функции “AudioPlaybackComplete” по окончании аудиофайла. При этом метод будет передавать себя как дополнительные данные функции “AudioPlaybackComplete“, сообщая, воспроизведение какого именно объекта “SoundEffect” завершено.
1 2 3 4 5 6 7 8 9 | -(void)play { if (!isPlaying) { // Вызывает Core Audio для воспроизведения звука, соответствующего указанному ID. AudioServicesPlaySystemSound(_soundID); AudioServicesAddSystemSoundCompletion(_soundID, NULL, NULL, AudioPlaybackComplete, self); isPlaying=true; } } |
Не расслабляйтесь: еще предстоит создать статичную функцию (метод класса), а также поработать с указателями (->), но это не отнимет много времени:
1 2 3 4 5 6 7 8 9 | static void AudioPlaybackComplete(SystemSoundID ssID, void *clientData) { SoundEffect* pSoundEffect=clientData; if (pSoundEffect->_soundID==ssID) { pSoundEffect->isPlaying=false; } } |
Код возвращает для переменной “isPlaying” значение “false“, сообщая объекту “SoundEffect” о возможности снова воспроизвести звук. Поскольку функция статична, к ней же будут обращаться все экземпляры класса “SoundEffect“. Следовательно, нужно передать заново вызывающий функцию объект “SoundEffect“. Это выполнит второй параметр *clientData.
Код проекта будет опубликован позже.



Июнь 9th, 2009 at 11:07
спс за топ !!! щас будем пробовать !!!
Июнь 9th, 2009 at 12:57
)) Вперед!!! ))
Июнь 10th, 2009 at 10:40
доброго вам времени суток!..
извиняюсь что не по теме,но скажите а как работать c камерой и как заливать написанные приложения непосредственно на iPhone.
Заранее спасибо…
Июнь 10th, 2009 at 12:10
не могу достать файли SoundEffect !! кто можжет помоч !!!???
Июнь 10th, 2009 at 12:23
Привет. Я сам не программист поэтому помочь не могу. Надеюсь скоро знающие люди подтянуться на сайт и помогут всем
Июнь 10th, 2009 at 13:29
нужна помощ !! как мне обращатся к жесткому диску ну что бы с его музыку прослушивать !!??? кто-то может примеррчик какой нибудь кинет !!1 и как производить аудио файли больше 30 с ?????
Июнь 10th, 2009 at 22:13
Смотрите самый последний урок, все этветы там есть
Июль 27th, 2009 at 04:44
Для заливки приложения на IPhone (для отладки); необходимо зарегистрироваться в программе разработчиков на сайте Apple (процедура, кстати, не из простых. Поэтому как это сделать точно не помню, но на сайте информация есть). Далее ID твоего IPhone нужно будет внести в список и всё, можно будет заливать на него приложение.
Октябрь 21st, 2009 at 13:55
Такое ощущение, что автор (не переводчик) статьи даже не понимает, почему пишется именно так:
#import
Октябрь 21st, 2009 at 13:56
Кхм, странно, сайт неадекватно реагирует на на фигурные скобки…
#import _AudioToolbox/AudioServices.h_
(заменил фигурные скобки на “_”)
Октябрь 21st, 2009 at 13:58
Да, пока не знаю как бороться с этими авто-подменами движка.