API  0.9.7
 All Classes Files Functions Variables Macros Groups Pages
CPSound.j
Go to the documentation of this file.
1 /*
2  * CPSound.j
3  * AppKit
4  *
5  * Created by Antoine Mercadal
6  * Copyright 2010, Antoine Mercadal
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
28 
32 
33 
42 @implementation CPSound : CPObject
43 {
44  CPString _name;
45  id _delegate;
46 
47  BOOL _playRequestBeforeLoad;
48  HTMLAudioElement _audioTag;
49  int _loadStatus;
50  int _playBackStatus;
51 }
52 
53 #pragma mark -
54 #pragma mark Initialization
55 
56 - (id)init
57 {
58  if (self = [super init])
59  {
60  _loadStatus = CPSoundLoadStateEmpty;
61 // _loops = NO;
62  _audioTag = document.createElement("audio");
63  _audioTag.preload = YES;
64  _playRequestBeforeLoad = NO;
65 
66  _audioTag.addEventListener("canplay", function()
67  {
68  [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
69  [self _soundDidload];
70  }, true);
71 
72  _audioTag.addEventListener("ended", function()
73  {
74  [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
75  [self _soundDidEnd];
76  }, true);
77 
78  _audioTag.addEventListener("error", function()
79  {
80  [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
81  [self _soundError];
82  }, true);
83  }
84 
85  return self;
86 }
87 
94 - (id)initWithContentsOfFile:(CPString)aFile byReference:(BOOL)byRef
95 {
96  if (self = [self init])
97  {
98  _loadStatus = CPSoundLoadStateLoading;
99  _audioTag.src = aFile;
100  }
101 
102  return self;
103 }
104 
111 - (id)initWithContentsOfURL:(CPURL)aURL byReference:(BOOL)byRef
112 {
113  return [self initWithContentsOfFile:[aURL absoluteString] byReference:NO];
114 }
115 
122 - (id)initWithData:(CPData)someData
123 {
124  if (self = [self init])
125  {
126  _loadStatus = CPSoundLoadStateLoading;
127  _audioTag.src = [someData rawString];
128  }
129 
130  return self;
131 }
132 
133 
134 #pragma mark -
135 #pragma mark Events listener
136 
139 - (void)_soundDidload
140 {
141  _loadStatus = CPSoundLoadStateCanBePlayed;
142 
143  if (_playRequestBeforeLoad)
144  {
145  _playRequestBeforeLoad = NO;
146  [self play];
147  }
148 }
149 
152 - (void)_soundDidEnd
153 {
154  if (![self loops])
155  [self stop];
156 }
157 
160 - (void)_soundError
161 {
162  _loadStatus = CPSoundLoadStateError;
163  CPLog.error("Cannot load sound. Maybe the format of your sound is not compatible with your browser.");
164 }
165 
166 
167 #pragma mark -
168 #pragma mark Media controls
169 
175 - (BOOL)play
176 {
177  if (_loadStatus === CPSoundLoadStateLoading)
178  {
179  _playRequestBeforeLoad = YES;
180  return YES;
181  }
182 
183  if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
184  || (_playBackStatus === CPSoundPlayBackStatePlay))
185  return NO;
186 
187  _audioTag.play();
188  _playBackStatus = CPSoundPlayBackStatePlay;
189 
190  return YES;
191 }
192 
198 - (BOOL)stop
199 {
200  if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
201  || (_playBackStatus === CPSoundPlayBackStateStop))
202  return NO;
203 
204  _audioTag.pause();
205  _audioTag.currentTime = 0.0;
206  _playBackStatus = CPSoundPlayBackStateStop;
207 
208  if (_delegate && [_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
209  [_delegate sound:self didFinishPlaying:YES];
210 
211  return YES;
212 }
213 
219 - (BOOL)pause
220 {
221  if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
222  || (_playBackStatus === CPSoundPlayBackStatePause))
223  return NO;
224 
225  _audioTag.pause();
226  _playBackStatus = CPSoundPlayBackStatePause;
227 
228  return YES;
229 }
230 
236 - (BOOL)resume
237 {
238  if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
239  || (_playBackStatus !== CPSoundPlayBackStatePause))
240  return NO;
241 
242  _audioTag.play();
243  _playBackStatus = CPSoundPlayBackStatePlay;
244 
245  return YES;
246 }
247 
253 - (BOOL)loops
254 {
255  return _audioTag.loop;
256 }
257 
263 - (void)setLoops:(BOOL)shouldLoop
264 {
265  _audioTag.loop = shouldLoop;
266 }
267 
273 - (double)volume
274 {
275  return _audioTag.volume;
276 }
277 
283 - (void)setVolume:(double)aVolume
284 {
285  if (aVolume > 1.0)
286  aVolume = 1.0;
287  else if (aVolume < 0.0)
288  aVolume = 0.0;
289 
290  _audioTag.volume = aVolume;
291 }
292 
293 #pragma mark -
294 #pragma mark Accessors
295 
301 - (double)duration
302 {
303  return _audioTag.duration;
304 }
305 
311 - (BOOL)isPlaying
312 {
313  return (_playBackStatus === CPSoundPlayBackStatePlay);
314 }
315 
316 @end
317 
319 
324 {
325  return _name;
326 }
327 
331 - (void)setName:(CPString)aValue
332 {
333  _name = aValue;
334 }
335 
339 - (id)delegate
340 {
341  return _delegate;
342 }
343 
347 - (void)setDelegate:(id)aValue
348 {
349  _delegate = aValue;
350 }
351 
352 @end