Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
OOSoundSourcePool.m
Go to the documentation of this file.
1/*
2
3OOSoundSourcePool.m
4
5
6Copyright (C) 2008-2013 Jens Ayton
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in all
16copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24SOFTWARE.
25
26*/
27
28#import "OOSoundSourcePool.h"
29#import "OOSound.h"
30#import "Universe.h"
31
32
33enum
34{
35 kNoSlot = UINT8_MAX
36};
37
38
40{
43 float priority;
45
46
47@interface OOSoundSourcePool (Private)
48
49- (uint8_t) selectSlotForPriority:(float)priority;
50
51@end
52
53
54@implementation OOSoundSourcePool
55
56+ (instancetype) poolWithCount:(uint8_t)count minRepeatTime:(OOTimeDelta)minRepeat
57{
58 return [[[self alloc] initWithCount:count minRepeatTime:minRepeat] autorelease];
59}
60
61
62- (id) initWithCount:(uint8_t)count minRepeatTime:(OOTimeDelta)minRepeat
63{
64 if ((self = [super init]))
65 {
66 // Sanity-check count
67 if (count == 0) count = 1;
68 if (count == kNoSlot) --count;
69 _count = count;
70 _reserved = kNoSlot;
71
72 if (minRepeat < 0.0) minRepeat = 0.0;
73 _minRepeat = minRepeat;
74
75 // Create source pool
76 _sources = calloc(sizeof(PoolElement), count);
77 if (_sources == NULL)
78 {
79 [self release];
80 self = nil;
81 }
82 }
83 return self;
84}
85
86
87- (void) dealloc
88{
89 uint8_t i;
90
91 for (i = 0; i != _count; i++)
92 {
93 [_sources[i].source release];
94 }
95 free(_sources);
96
97 [_lastKey release];
98
99 [super dealloc];
100}
101
102
103- (void) playSoundWithKey:(NSString *)key
104 priority:(float)priority
105 expiryTime:(OOTimeDelta)expiryTime
106 overlap:(BOOL)overlap
107 position:(Vector)position
108{
109 uint8_t slot;
110 OOTimeAbsolute now, absExpiryTime;
111 PoolElement *element = NULL;
112 OOSound *sound = NULL;
113
114 // Convert expiry time to absolute
115 now = [UNIVERSE getTime];
116 absExpiryTime = expiryTime + now;
117
118 // Avoid repeats if required
119 if (now < _nextRepeat && [key isEqualToString:_lastKey]) return;
120 if (!overlap && _reserved != kNoSlot && [_sources[_reserved].source isPlaying]) return;
121
122 // Look for a slot in the source list to use
123 slot = [self selectSlotForPriority:priority];
124 if (slot == kNoSlot) return;
125 element = &_sources[slot];
126
127 // Load sound
128 sound = [OOSound soundWithCustomSoundKey:key];
129 if (sound == nil) return;
130
131 // Stop playing sound or set up sound source as appropriate
132 if (element->source != nil) [element->source stop];
133 else
134 {
135 element->source = [[OOSoundSource alloc] init];
136 if (element->source == nil) return;
137 }
138 if (slot == _reserved) _reserved = kNoSlot; // _reserved has finished playing!
139 if (!overlap) _reserved = slot;
140
141 // Play and store metadata
142 [element->source setPosition:position];
143 [element->source playSound:sound];
144 element->expiryTime = absExpiryTime;
145 element->priority = priority;
146 if (_minRepeat > 0.0)
147 {
148 _nextRepeat = now + _minRepeat;
149 [_lastKey release];
150 _lastKey = [key copy];
151 }
152
153 // Set staring search location for next slot lookup
154 _latest = slot;
155}
156
157
158- (void) playSoundWithKey:(NSString *)key
159 priority:(float)priority
160 expiryTime:(OOTimeDelta)expiryTime
161{
162 [self playSoundWithKey:key
163 priority:priority
164 expiryTime:expiryTime
165 overlap:YES
166 position:kZeroVector];
167}
168
169
170- (void) playSoundWithKey:(NSString *)key
171 priority:(float)priority
172 position:(Vector)position
173{
174 [self playSoundWithKey:key
175 priority:priority
176 expiryTime:0.5 + randf() * 0.1
177 overlap:YES
178 position:position];
179}
180
181
182- (void) playSoundWithKey:(NSString *)key
183 priority:(float)priority
184{
185 [self playSoundWithKey:key
186 priority:priority
187 expiryTime:0.5 + randf() * 0.1];
188}
189
190
191- (void) playSoundWithKey:(NSString *)key
192{
193 [self playSoundWithKey:key priority:1.0];
194}
195
196
197- (void) playSoundWithKey:(NSString *)key position:(Vector)position
198{
199 [self playSoundWithKey:key priority:1.0 position:position];
200}
201
202
203- (void) playSoundWithKey:(NSString *)key overlap:(BOOL)overlap
204{
205 [self playSoundWithKey:key
206 priority:1.0
207 expiryTime:0.5
208 overlap:overlap
209 position:kZeroVector];
210}
211
212
213- (void) playSoundWithKey:(NSString *)key overlap:(BOOL)overlap position:(Vector)position
214{
215 [self playSoundWithKey:key
216 priority:1.0
217 expiryTime:0.5
218 overlap:overlap
219 position:position];
220}
221
222
223@end
224
225
226@implementation OOSoundSourcePool (Private)
227
228- (uint8_t) selectSlotForPriority:(float)priority
229{
230 uint8_t curr, count, expiredLower = kNoSlot, unexpiredLower = kNoSlot, expiredEqual = kNoSlot;
231 PoolElement *element = NULL;
232 OOTimeAbsolute now = [UNIVERSE getTime];
233
234#define NEXT(x) (((x) + 1) % _count)
235
236 curr = _latest;
237 count = _count;
238 do
239 {
240 curr = NEXT(curr);
241 element = &_sources[curr];
242
243 if (element->source == nil || ![element->source isPlaying]) return curr; // Best type of slot: empty
244 else if (element->priority < priority)
245 {
246 if (element->expiryTime <= now) expiredLower = curr; // Second-best type: expired lower-priority
247 else if (curr != _reserved) unexpiredLower = curr; // Third-best type: unexpired lower-priority
248 }
249 else if (element->priority == priority && element->expiryTime <= now)
250 {
251 expiredEqual = curr; // Fourth-best type: expired equal-priority.
252 }
253 } while (--count);
254
255 if (expiredLower != kNoSlot) return expiredLower;
256 if (unexpiredLower != kNoSlot) return unexpiredLower;
257 return expiredEqual; // Will be kNoSlot if none found
258}
259
260@end
unsigned count
return nil
#define NEXT(x)
struct OOSoundSourcePoolElement PoolElement
@ kNoSlot
double OOTimeDelta
Definition OOTypes.h:224
double OOTimeAbsolute
Definition OOTypes.h:223
id soundWithCustomSoundKey:(NSString *key)
Definition Universe.m:11029