API  0.9.10
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 
24 @typedef HTMLAudioElement
25 
26 @protocol CPSoundDelegate <CPObject>
27 
28 @optional
29 - (void)sound:(CPSound)aSound didFinishPlaying:(BOOL)finishedLoading;
30 
31 @end
32 
33 
35 
40 
44 
45 
54 @implementation CPSound : CPObject
55 {
56  CPString _name;
57  id _delegate;
58 
59  BOOL _playRequestBeforeLoad;
60  HTMLAudioElement _audioTag;
61  int _loadStatus;
62  int _playBackStatus;
63  unsigned _implementedDelegateMethods;
64 }
65 
66 #pragma mark -
67 #pragma mark Initialization
68 
69 - (id)init
70 {
71  if (self = [super init])
72  {
73  _loadStatus = CPSoundLoadStateEmpty;
74 // _loops = NO;
75  _audioTag = document.createElement("audio");
76  _audioTag.preload = YES;
77  _playRequestBeforeLoad = NO;
78 
79  _audioTag.addEventListener("canplay", function()
80  {
81  [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
82  [self _soundDidload];
83  }, true);
84 
85  _audioTag.addEventListener("ended", function()
86  {
87  [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
88  [self _soundDidEnd];
89  }, true);
90 
91  _audioTag.addEventListener("error", function()
92  {
93  [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
94  [self _soundError];
95  }, true);
96  }
97 
98  return self;
99 }
100 
107 - (id)initWithContentsOfFile:(CPString)aFile byReference:(BOOL)byRef
108 {
109  if (self = [self init])
110  {
111  _loadStatus = CPSoundLoadStateLoading;
112  _audioTag.src = aFile;
113  }
114 
115  return self;
116 }
117 
124 - (id)initWithContentsOfURL:(CPURL)aURL byReference:(BOOL)byRef
125 {
126  return [self initWithContentsOfFile:[aURL absoluteString] byReference:NO];
127 }
128 
135 - (id)initWithData:(CPData)someData
136 {
137  if (self = [self init])
138  {
139  _loadStatus = CPSoundLoadStateLoading;
140  _audioTag.src = [someData rawString];
141  }
142 
143  return self;
144 }
145 
146 
147 #pragma mark -
148 #pragma mark Delegate methods
149 
154 - (void)setDelegate:(id)aDelegate
155 {
156  if (_delegate === aDelegate)
157  return;
158 
159  _delegate = aDelegate;
160  _implementedDelegateMethods = 0;
161 
162  if ([_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
163  _implementedDelegateMethods |= CPSoundDelegate_sound_didFinishPlaying_;
164 }
165 
166 #pragma mark -
167 #pragma mark Events listener
168 
171 - (void)_soundDidload
172 {
173  _loadStatus = CPSoundLoadStateCanBePlayed;
174 
175  if (_playRequestBeforeLoad)
176  {
177  _playRequestBeforeLoad = NO;
178  [self play];
179  }
180 }
181 
184 - (void)_soundDidEnd
185 {
186  if (![self loops])
187  [self stop];
188 }
189 
192 - (void)_soundError
193 {
194  _loadStatus = CPSoundLoadStateError;
195  CPLog.error("Cannot load sound. Maybe the format of your sound is not compatible with your browser.");
196 }
197 
198 
199 #pragma mark -
200 #pragma mark Media controls
201 
207 - (BOOL)play
208 {
209  if (_loadStatus === CPSoundLoadStateLoading)
210  {
211  _playRequestBeforeLoad = YES;
212  return YES;
213  }
214 
215  if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
216  || (_playBackStatus === CPSoundPlayBackStatePlay))
217  return NO;
218 
219  _audioTag.play();
220  _playBackStatus = CPSoundPlayBackStatePlay;
221 
222  return YES;
223 }
224 
230 - (BOOL)stop
231 {
232  if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
233  || (_playBackStatus === CPSoundPlayBackStateStop))
234  return NO;
235 
236  _audioTag.pause();
237  _audioTag.currentTime = 0.0;
238  _playBackStatus = CPSoundPlayBackStateStop;
239 
240  [self _sendDelegateSoundDidFinishPlaying:YES];
241 
242  return YES;
243 }
244 
250 - (BOOL)pause
251 {
252  if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
253  || (_playBackStatus === CPSoundPlayBackStatePause))
254  return NO;
255 
256  _audioTag.pause();
257  _playBackStatus = CPSoundPlayBackStatePause;
258 
259  return YES;
260 }
261 
267 - (BOOL)resume
268 {
269  if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
270  || (_playBackStatus !== CPSoundPlayBackStatePause))
271  return NO;
272 
273  _audioTag.play();
274  _playBackStatus = CPSoundPlayBackStatePlay;
275 
276  return YES;
277 }
278 
284 - (BOOL)loops
285 {
286  return _audioTag.loop;
287 }
288 
294 - (void)setLoops:(BOOL)shouldLoop
295 {
296  _audioTag.loop = shouldLoop;
297 }
298 
304 - (double)volume
305 {
306  return _audioTag.volume;
307 }
308 
314 - (void)setVolume:(double)aVolume
315 {
316  if (aVolume > 1.0)
317  aVolume = 1.0;
318  else if (aVolume < 0.0)
319  aVolume = 0.0;
320 
321  _audioTag.volume = aVolume;
322 }
323 
324 #pragma mark -
325 #pragma mark Accessors
326 
332 - (double)duration
333 {
334  return _audioTag.duration;
335 }
336 
342 - (BOOL)isPlaying
343 {
344  return (_playBackStatus === CPSoundPlayBackStatePlay);
345 }
346 
347 @end
348 
349 
351 
356 - (void)_sendDelegateSoundDidFinishPlaying:(BOOL)finishedPlaying
357 {
358  if (!(_implementedDelegateMethods & CPSoundDelegate_sound_didFinishPlaying_))
359  return;
360 
361  [_delegate sound:self didFinishPlaying:finishedPlaying];
362 }
363 
364 @end
365 
367 
372 {
373  return _name;
374 }
375 
379 - (void)setName:(CPString)aValue
380 {
381  _name = aValue;
382 }
383 
387 - (id)delegate
388 {
389  return _delegate;
390 }
391 
395 - (void)setDelegate:(id)aValue
396 {
397  _delegate = aValue;
398 }
399 
400 @end
id init()
Definition: CPSound.j:69
var CPSoundDelegate_sound_didFinishPlaying_
Definition: CPSound.j:34
The main run loop for the application.
Definition: CPRunLoop.h:2
CPString rawString()
Definition: CPData.j:121
id initWithContentsOfFile:byReference:(CPString aFile, [byReference] BOOL byRef)
Definition: CPSound.j:107
A Cappuccino wrapper for any data type.
Definition: CPData.h:2
CPSoundPlayBackStatePlay
Definition: CPSound.j:41
CPSoundLoadStateEmpty
Definition: CPSound.j:36
CPRunLoop currentRunLoop()
Definition: CPRunLoop.j:232
CPSoundLoadStateCanBePlayed
Definition: CPSound.j:38
Definition: CPSound.h:2
An immutable string (collection of characters).
Definition: CPString.h:2
CPString absoluteString()
Definition: CPURL.j:105
BOOL stop()
Definition: CPSound.j:230
BOOL play()
Definition: CPSound.j:207
CPSoundPlayBackStatePause
Definition: CPSound.j:43
CPSoundLoadStateLoading
Definition: CPSound.j:37
BOOL loops()
Definition: CPSound.j:284
CPDate limitDateForMode:(CPString aMode)
Definition: CPRunLoop.j:342
CPSoundPlayBackStateStop
Definition: CPSound.j:42
double duration()
Definition: CPSound.j:332
BOOL resume()
Definition: CPSound.j:267
CPSoundLoadStateError
Definition: CPSound.j:39
BOOL pause()
Definition: CPSound.j:250
Definition: CPURL.h:2
double volume()
Definition: CPSound.j:304
BOOL isPlaying()
Definition: CPSound.j:342