![]() |
API 0.9.5
|
00001 /* 00002 * CPSound.j 00003 * AppKit 00004 * 00005 * Created by Antoine Mercadal 00006 * Copyright 2010, Antoine Mercadal 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 00024 CPSoundLoadStateEmpty = 0; 00025 CPSoundLoadStateLoading = 1; 00026 CPSoundLoadStateCanBePlayed = 2; 00027 CPSoundLoadStateError = 3; 00028 00029 CPSoundPlayBackStatePlay = 0; 00030 CPSoundPlayBackStateStop = 1; 00031 CPSoundPlayBackStatePause = 2; 00032 00033 00042 @implementation CPSound : CPObject 00043 { 00044 CPString _name; 00045 id _delegate; 00046 00047 BOOL _playRequestBeforeLoad; 00048 HTMLAudioElement _audioTag; 00049 int _loadStatus; 00050 int _playBackStatus; 00051 } 00052 00053 #pragma mark - 00054 #pragma mark Initialization 00055 00056 - (id)init 00057 { 00058 if (self = [super init]) 00059 { 00060 _loadStatus = CPSoundLoadStateEmpty; 00061 _loops = NO; 00062 _audioTag = document.createElement("audio"); 00063 _audioTag.preload = YES; 00064 _playRequestBeforeLoad = NO; 00065 00066 _audioTag.addEventListener("canplay", function() 00067 { 00068 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; 00069 [self _soundDidload]; 00070 }, true); 00071 00072 _audioTag.addEventListener("ended", function() 00073 { 00074 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; 00075 [self _soundDidEnd]; 00076 }, true); 00077 00078 _audioTag.addEventListener("error", function() 00079 { 00080 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; 00081 [self _soundError]; 00082 }, true); 00083 } 00084 00085 return self; 00086 } 00087 00094 - (id)initWithContentsOfFile:(CPString)aFile byReference:(BOOL)byRef 00095 { 00096 if (self = [self init]) 00097 { 00098 _loadStatus = CPSoundLoadStateLoading; 00099 _audioTag.src = aFile; 00100 } 00101 00102 return self; 00103 } 00104 00111 - (id)initWithContentsOfURL:(CPURL)aURL byReference:(BOOL)byRef 00112 { 00113 return [self initWithContentsOfFile:[aURL absoluteString] byReference:NO]; 00114 } 00115 00122 - (id)initWithData:(CPData)someData 00123 { 00124 if (self = [self init]) 00125 { 00126 _loadStatus = CPSoundLoadStateLoading; 00127 _audioTag.src = [someData rawString]; 00128 } 00129 00130 return self; 00131 } 00132 00133 00134 #pragma mark - 00135 #pragma mark Events listener 00136 00139 - (void)_soundDidload 00140 { 00141 _loadStatus = CPSoundLoadStateCanBePlayed; 00142 00143 if (_playRequestBeforeLoad) 00144 { 00145 _playRequestBeforeLoad = NO; 00146 [self play]; 00147 } 00148 } 00149 00152 - (void)_soundDidEnd 00153 { 00154 if (![self loops]) 00155 [self stop]; 00156 } 00157 00160 - (void)_soundError 00161 { 00162 _loadStatus = CPSoundLoadStateError; 00163 CPLog.error("Cannot load sound. Maybe the format of your sound is not compatible with your browser."); 00164 } 00165 00166 00167 #pragma mark - 00168 #pragma mark Media controls 00169 00175 - (BOOL)play 00176 { 00177 if (_loadStatus === CPSoundLoadStateLoading) 00178 { 00179 _playRequestBeforeLoad = YES; 00180 return YES; 00181 } 00182 00183 if ((_loadStatus !== CPSoundLoadStateCanBePlayed) 00184 || (_playBackStatus === CPSoundPlayBackStatePlay)) 00185 return NO; 00186 00187 _audioTag.play(); 00188 _playBackStatus = CPSoundPlayBackStatePlay; 00189 00190 return YES; 00191 } 00192 00198 - (BOOL)stop 00199 { 00200 if ((_loadStatus !== CPSoundLoadStateCanBePlayed) 00201 || (_playBackStatus === CPSoundPlayBackStateStop)) 00202 return NO; 00203 00204 _audioTag.pause(); 00205 _audioTag.currentTime = 0.0; 00206 _playBackStatus = CPSoundPlayBackStateStop; 00207 00208 if (_delegate && [_delegate respondsToSelector:@selector(sound:didFinishPlaying:)]) 00209 [_delegate sound:self didFinishPlaying:YES]; 00210 00211 return YES; 00212 } 00213 00219 - (BOOL)pause 00220 { 00221 if ((_loadStatus !== CPSoundLoadStateCanBePlayed) 00222 || (_playBackStatus === CPSoundPlayBackStatePause)) 00223 return NO; 00224 00225 _audioTag.pause(); 00226 _playBackStatus = CPSoundPlayBackStatePause; 00227 00228 return YES; 00229 } 00230 00236 - (BOOL)resume 00237 { 00238 if ((_loadStatus !== CPSoundLoadStateCanBePlayed) 00239 || (_playBackStatus !== CPSoundPlayBackStatePause)) 00240 return NO; 00241 00242 _audioTag.play(); 00243 _playBackStatus = CPSoundPlayBackStatePlay; 00244 00245 return YES; 00246 } 00247 00253 - (BOOL)loops 00254 { 00255 return _audioTag.loop; 00256 } 00257 00263 - (void)setLoops:(BOOL)shouldLoop 00264 { 00265 _audioTag.loop = shouldLoop; 00266 } 00267 00273 - (double)volume 00274 { 00275 return _audioTag.volume; 00276 } 00277 00283 - (void)setVolume:(double)aVolume 00284 { 00285 if (aVolume > 1.0) 00286 aVolume = 1.0; 00287 else if (aVolume < 0.0) 00288 aVolume = 0.0; 00289 00290 _audioTag.volume = aVolume; 00291 } 00292 00293 #pragma mark - 00294 #pragma mark Accessors 00295 00301 - (double)duration 00302 { 00303 return _audioTag.duration; 00304 } 00305 00311 - (BOOL)isPlaying 00312 { 00313 return (_playBackStatus === CPSoundPlayBackStatePlay); 00314 } 00315 00316 @end 00317 00318 @implementation CPSound (CPSynthesizedAccessors) 00319 00323 - (CPString)name 00324 { 00325 return _name; 00326 } 00327 00331 - (void)setName:(CPString)aValue 00332 { 00333 _name = aValue; 00334 } 00335 00339 - (id)delegate 00340 { 00341 return _delegate; 00342 } 00343 00347 - (void)setDelegate:(id)aValue 00348 { 00349 _delegate = aValue; 00350 } 00351 00352 @end