Уроки iPhone SDK: Создаем счетчик программными средствами (UIActivityIndicator) Star Defense
Июн 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“).

addaudiointoproject

Шаг 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, &amp;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” должна выглядеть так, как показано ниже.

addedsoundeffectclass

Если попытаться выполнить компиляцию, появится следующее сообщение об ошибке:

 “_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“.

xcodedocwindow

Есть еще один вариант: откройте проблемный файл (”SoundEffect.o” — компилированный obj файл класса “SoundEffect“) — и в “SoundEffect.h” увидите оператор импорта “: import“.

Предлагаю включить данный фреймворк в проект. Разверните меню группы “Target“, выберите “Link Binary With Libraries” и выполните “Add ->Existing Frameworks“.

balladdexistinglibrary

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

audiotoolboxadd

Выполните компиляцию заново — ошибка должна исчезнуть.

Шаг 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&gt;self.superview.frame.size.width-self.frame.size.width)
{
bHit=true;
mXSpeed=-abs(mXSpeed);

}

if (self.frame.origin.y&lt;0)//self.superview.frame.origin.y)
{
bHit=true;
mYSpeed=abs(mYSpeed);
}
if (self.frame.origin.y&gt;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 &lt; 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“, хотя для основной массы игр их вполне достаточно.

  1. AudioServicesPlaySystemSound” воспроизводит аудиофайлы, не превышающие по длительности 30 с.
  2.  Попытка запустить тот же файл до окончания его воспроизведения чревата последующими ошибками (например, очередной вызов аудиофайла не даст ничего кроме тишины).

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

Откорректируйте файл “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-&gt;_soundID==ssID)
{
pSoundEffect-&gt;isPlaying=false;
}

}

Код возвращает для переменной “isPlaying” значение “false“, сообщая объекту “SoundEffect” о возможности снова воспроизвести звук. Поскольку функция статична, к ней же будут обращаться все экземпляры класса “SoundEffect“. Следовательно, нужно передать заново вызывающий функцию объект “SoundEffect“. Это выполнит второй параметр *clientData.

Код проекта будет опубликован позже.

Текст оригинальной статьи на английском языке [здесь]

Уважаемые читатели, данный материал был переведен и подготовлен к публикации проектом LookApp.ru, при публикации на другом сайте ссылка на LookApp.ru обязательна.

1 звезда2 звезд3 звезд4 звезд5 звезд (Оцените приложение)
Загрузка ... Загрузка ...


11 Responses to “Уроки iPhone SDK: (Часть 3) Перемещение и вращение изображения. Базовые звуки.”

  1. 1. ARtt Says:

    спс за топ !!! щас будем пробовать !!!

  2. 2. Artem Says:

    )) Вперед!!! ))

  3. 3. KaDIF Says:

    доброго вам времени суток!..
    извиняюсь что не по теме,но скажите а как работать c камерой и как заливать написанные приложения непосредственно на iPhone.
    Заранее спасибо…

  4. 4. ARtt Says:

    не могу достать файли SoundEffect !! кто можжет помоч !!!???

  5. 5. Artem Says:

    Привет. Я сам не программист поэтому помочь не могу. Надеюсь скоро знающие люди подтянуться на сайт и помогут всем :)

  6. 6. ARtt Says:

    нужна помощ !! как мне обращатся к жесткому диску ну что бы с его музыку прослушивать !!??? кто-то может примеррчик какой нибудь кинет !!1 и как производить аудио файли больше 30 с ?????

  7. 7. Artem Says:

    Смотрите самый последний урок, все этветы там есть

  8. 8. Andrew Says:

    Для заливки приложения на IPhone (для отладки); необходимо зарегистрироваться в программе разработчиков на сайте Apple (процедура, кстати, не из простых. Поэтому как это сделать точно не помню, но на сайте информация есть). Далее ID твоего IPhone нужно будет внести в список и всё, можно будет заливать на него приложение.

  9. 9. Mr. DarK AngeL Says:

    Такое ощущение, что автор (не переводчик) статьи даже не понимает, почему пишется именно так:
    #import

  10. 10. Mr. DarK AngeL Says:

    Кхм, странно, сайт неадекватно реагирует на на фигурные скобки…
    #import _AudioToolbox/AudioServices.h_
    (заменил фигурные скобки на “_”)

  11. 11. Artem Says:

    Да, пока не знаю как бороться с этими авто-подменами движка.

Оставьте комментарий