Line data Source code
1 0 : /*
2 :
3 : OOSoundSource.m
4 :
5 :
6 : Copyright (C) 2006-2013 Jens Ayton
7 :
8 : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : of this software and associated documentation files (the "Software"), to deal
10 : in the Software without restriction, including without limitation the rights
11 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : copies of the Software, and to permit persons to whom the Software is
13 : furnished to do so, subject to the following conditions:
14 :
15 : The above copyright notice and this permission notice shall be included in all
16 : copies or substantial portions of the Software.
17 :
18 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : SOFTWARE.
25 :
26 : */
27 :
28 : #import "OOSoundInternal.h"
29 : #import "OOLogging.h"
30 : #import "OOMaths.h"
31 :
32 0 : static NSMutableSet *sPlayingSoundSources;
33 :
34 :
35 : @implementation OOSoundSource
36 :
37 : + (instancetype) sourceWithSound:(OOSound *)inSound
38 : {
39 : return [[[self alloc] initWithSound:inSound] autorelease];
40 : }
41 :
42 :
43 0 : - (id) init
44 : {
45 : self = [super init];
46 : if (!self) return nil;
47 :
48 : _positional = NO;
49 : _position = kZeroVector;
50 : _gain = OO_DEFAULT_SOUNDSOURCE_GAIN;
51 : return self;
52 : }
53 :
54 :
55 : - (id) initWithSound:(OOSound *)inSound
56 : {
57 : self = [self init];
58 : if (!self) return nil;
59 :
60 : [self setSound:inSound];
61 :
62 : return self;
63 : }
64 :
65 :
66 0 : - (void) dealloc
67 : {
68 : [self stop];
69 : [_sound autorelease];
70 :
71 : [super dealloc];
72 : }
73 :
74 :
75 0 : - (NSString *) descriptionComponents
76 : {
77 : if ([self isPlaying])
78 : {
79 : return [NSString stringWithFormat:@"sound=%@, loop=%s, repeatCount=%u, playing on channel %@", _sound, [self loop] ? "YES" : "NO", [self repeatCount], _channel];
80 : }
81 : else
82 : {
83 : return [NSString stringWithFormat:@"sound=%@, loop=%s, repeatCount=%u, not playing", _sound, [self loop] ? "YES" : "NO", [self repeatCount]];
84 : }
85 : }
86 :
87 :
88 : - (OOSound *) sound
89 : {
90 : return _sound;
91 : }
92 :
93 :
94 : - (void) setSound:(OOSound *)sound
95 : {
96 : if (_sound != sound)
97 : {
98 : [self stop];
99 : [_sound autorelease];
100 : _sound = [sound retain];
101 : }
102 : }
103 :
104 :
105 : - (BOOL) loop
106 : {
107 : return _loop;
108 : }
109 :
110 :
111 : - (void) setLoop:(BOOL)loop
112 : {
113 : _loop = !!loop;
114 : }
115 :
116 :
117 : - (uint8_t) repeatCount
118 : {
119 : return _repeatCount ? _repeatCount : 1;
120 : }
121 :
122 :
123 : - (void) setRepeatCount:(uint8_t)count
124 : {
125 : _repeatCount = count;
126 : }
127 :
128 :
129 : - (BOOL) isPlaying
130 : {
131 : return _channel != nil;
132 : }
133 :
134 :
135 : - (void)play
136 : {
137 : if ([self sound] == nil) return;
138 :
139 : OOSoundAcquireLock();
140 :
141 : if (_channel) [self stop];
142 :
143 : _channel = [[OOSoundMixer sharedMixer] popChannel];
144 : if (nil != _channel)
145 : {
146 : _remainingCount = [self repeatCount];
147 : [_channel setDelegate:self];
148 : [_channel setPosition:_position];
149 : [_channel setGain:_gain];
150 : [_channel playSound:[self sound] looped:[self loop]];
151 : [self retain];
152 : }
153 :
154 : if (EXPECT_NOT(sPlayingSoundSources == nil))
155 : {
156 : sPlayingSoundSources = [[NSMutableSet alloc] init];
157 : }
158 : [sPlayingSoundSources addObject:self];
159 :
160 : OOSoundReleaseLock();
161 : }
162 :
163 :
164 : - (void) playOrRepeat
165 : {
166 : if (![self isPlaying]) [self play];
167 : else ++_remainingCount;
168 : }
169 :
170 :
171 : - (void)stop
172 : {
173 : OOSoundAcquireLock();
174 :
175 : if (nil != _channel)
176 : {
177 : [_channel setDelegate:[self class]];
178 : [_channel stop];
179 : _channel = nil;
180 :
181 : [sPlayingSoundSources removeObject:self];
182 : [self release];
183 : }
184 :
185 : OOSoundReleaseLock();
186 : }
187 :
188 :
189 : + (void) stopAll
190 : {
191 : /* We're not allowed to mutate sPlayingSoundSources during iteration. The
192 : normal solution would be to copy the set, but since we know it will
193 : end up empty we may as well use the original set and let a new one be
194 : set up lazily.
195 : */
196 : NSMutableSet *playing = sPlayingSoundSources;
197 : sPlayingSoundSources = nil;
198 :
199 : [playing makeObjectsPerformSelector:@selector(stop)];
200 : [playing release];
201 : }
202 :
203 :
204 : - (void) playSound:(OOSound *)sound
205 : {
206 : [self playSound:sound repeatCount:_repeatCount];
207 : }
208 :
209 :
210 : - (void) playSound:(OOSound *)sound repeatCount:(uint8_t)count
211 : {
212 : [self stop];
213 : [self setSound:sound];
214 : [self setRepeatCount:count];
215 : [self play];
216 : }
217 :
218 :
219 : - (void) playOrRepeatSound:(OOSound *)sound
220 : {
221 : if (_sound != sound) [self playSound:sound];
222 : else [self playOrRepeat];
223 : }
224 :
225 :
226 : - (void) setPositional:(BOOL)inPositional
227 : {
228 : if (inPositional)
229 : {
230 : _positional = YES;
231 : }
232 : else
233 : {
234 : /* OpenAL doesn't easily do non-positional sounds beyond the
235 : * stereo/mono distinction, but setting the position to the
236 : * zero vector is probably close enough */
237 : _positional = NO;
238 : [self setPosition:kZeroVector];
239 : }
240 : }
241 :
242 :
243 : - (BOOL) positional
244 : {
245 : return _positional;
246 : }
247 :
248 :
249 : - (void) setPosition:(Vector)inPosition
250 : {
251 : _position = inPosition;
252 : if (inPosition.x != 0.0 || inPosition.y != 0.0 || inPosition.z != 0.0)
253 : {
254 : _positional = YES;
255 : }
256 : if (_channel)
257 : {
258 : [_channel setPosition:_position];
259 : }
260 : }
261 :
262 :
263 : - (Vector) position
264 : {
265 : return _position;
266 : }
267 :
268 :
269 : - (void) setGain:(float)gain
270 : {
271 : _gain = gain;
272 : if (_channel)
273 : {
274 : [_channel setGain:_gain];
275 : }
276 : }
277 :
278 :
279 : - (float) gain
280 : {
281 : return _gain;
282 : }
283 :
284 :
285 : /* Following not yet implemented */
286 : - (void) setVelocity:(Vector)inVelocity
287 : {
288 :
289 : }
290 :
291 :
292 : - (void) setOrientation:(Vector)inOrientation
293 : {
294 :
295 : }
296 :
297 :
298 : - (void) setConeAngle:(float)inAngle
299 : {
300 :
301 : }
302 :
303 :
304 : - (void) setGainInsideCone:(float)inInside outsideCone:(float)inOutside
305 : {
306 :
307 : }
308 :
309 :
310 : - (void) positionRelativeTo:(OOSoundReferencePoint *)inPoint
311 : {
312 :
313 : }
314 :
315 :
316 : // OOSoundChannelDelegate
317 0 : - (void)channel:(OOSoundChannel *)channel didFinishPlayingSound:(OOSound *)sound
318 : {
319 : assert(_channel == channel);
320 :
321 : OOSoundAcquireLock();
322 :
323 : if (--_remainingCount)
324 : {
325 : [_channel playSound:[self sound] looped:NO];
326 : }
327 : else
328 : {
329 : [_channel setDelegate:nil];
330 : [[OOSoundMixer sharedMixer] pushChannel:_channel];
331 : _channel = nil;
332 : [self release];
333 : }
334 : OOSoundReleaseLock();
335 : }
336 :
337 :
338 : + (void)channel:(OOSoundChannel *)inChannel didFinishPlayingSound:(OOSound *)inSound
339 : {
340 : // This delegate is used for a stopped source
341 : [[OOSoundMixer sharedMixer] pushChannel:inChannel];
342 : }
343 :
344 : @end
|