Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
OOALSoundChannel.m
Go to the documentation of this file.
1/*
2
3OOALSoundChannel.m
4
5OOALSound - OpenAL sound implementation for Oolite.
6Copyright (C) 2006-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 "OOALSoundChannel.h"
29#import "OOALSound.h"
30#import "OOLogging.h"
31#import "OOMaths.h"
32
33@interface OOSoundChannel (Private)
34
35- (BOOL) enqueueBuffer:(OOSound *)sound;
36- (void) hasStopped;
37- (void) getNextSoundBuffer;
38
39@end
40
41
42@implementation OOSoundChannel
43
44- (id) init
45{
46 if ((self = [super init]))
47 {
48 ALuint error;
49 OOAL(alGenSources(1,&_source));
50 if ((error = alGetError()) != AL_NO_ERROR)
51 {
52 OOLog(kOOLogSoundInitError, @"%@", @"Could not create OpenAL source");
53 [self release];
54 self = nil;
55 }
56 else
57 {
58 // sources are all relative to listener, defaulting to zero vector
59 OOAL(alSourcei(_source, AL_SOURCE_RELATIVE, AL_TRUE));
60 OOAL(alSource3f(_source, AL_POSITION, 0.0f, 0.0f, 0.0f));
61 }
62 }
63 return self;
64}
65
66
67- (void) dealloc
68{
69 [self hasStopped]; // make sure buffers are dequeued and deleted
70 OOAL(alDeleteSources(1, &_source));
71 [super dealloc];
72}
73
74- (void) update
75{
76 // Check if we've reached the end of a sound.
77 if (_sound != nil)
78 {
79 ALint check;
80 OOAL(alGetSourcei(_source,AL_SOURCE_STATE,&check));
81 if (check == AL_STOPPED)
82 {
83 [self hasStopped];
84 }
85 else if ([_sound soundIncomplete]) // streaming and not finished loading
86 {
87 OOLog(@"sound.buffer", @"Incomplete, trying next for %@", [_sound name]);
88 [self getNextSoundBuffer];
89 }
90 else if (_loop)
91 {
92 OOLog(@"sound.buffer", @"Looping, trying restart for %@", [_sound name]);
93 // sound is complete, but needs to be looped, so start it again
94 [_sound rewind];
95 [self getNextSoundBuffer];
96 }
97 }
98}
99
100
101- (void) getNextSoundBuffer
102{
103 if (!_bigSound)
104 {
105 // we've only loaded one buffer so far
106 _bigSound = YES;
107 _lastBuffer = _buffer;
108 [self enqueueBuffer:_sound];
109 }
110 else
111 {
112 // _lastBuffer has something in it, so only queue up
113 // another one if we've finished with that
114 ALint processed = 0;
115 OOAL(alGetSourcei(_source, AL_BUFFERS_PROCESSED, &processed));
116 if (processed > 0) // slot free
117 {
118 // dequeue and delete lastBuffer
119 ALuint buffer;
120 OOAL(alSourceUnqueueBuffers(_source, 1, &buffer));
121 assert(buffer == _lastBuffer);
122 OOAL(alDeleteBuffers(1,&_lastBuffer));
123 // shuffle along, and grab the next bit
124 _lastBuffer = _buffer;
125 [self enqueueBuffer:_sound];
126 }
127 }
128}
129
130
131- (void) setDelegate:(id)delegate
132{
133 _delegate = delegate;
134}
135
136
137- (OOSoundChannel *) next
138{
139 return _next;
140}
141
142
143- (void) setNext:(OOSoundChannel *)next
144{
145 _next = next;
146}
147
148
149- (void) setPosition:(Vector) vector
150{
151 OOAL(alSource3f(_source, AL_POSITION, vector.x, vector.y, vector.z));
152}
153
154
155- (void) setGain:(float) gain
156{
157 OOAL(alSourcef(_source, AL_GAIN, gain));
158}
159
160
161- (BOOL) playSound:(OOSound *)sound looped:(BOOL)loop
162{
163 if (sound == nil) return NO;
164
165 if (_sound != nil) [self stop];
166
167 _loop = loop;
168 _bigSound = NO;
169 [sound rewind];
170 if ([self enqueueBuffer:sound])
171 {
172 _sound = [sound retain];
173 return YES;
174 }
175 else
176 {
177 return NO;
178 }
179}
180
181
182- (void) stop
183{
184 if (_sound != nil)
185 {
186 OOAL(alSourceStop(_source));
187 OOAL(alSourcei(_source, AL_BUFFER, AL_NONE));
188 [self hasStopped];
189 }
190}
191
192
193- (void) hasStopped
194{
195 ALint queued;
196 OOAL(alGetSourcei(_source, AL_BUFFERS_QUEUED, &queued));
197
198 while (queued--)
199 {
200 ALuint buffer;
201 OOAL(alSourceUnqueueBuffers(_source, 1, &buffer));
202 }
203
204 OOAL(alDeleteBuffers(1,&_buffer));
205 if (_bigSound)
206 {
207 // then we have two buffers to cleanup
208 OOAL(alDeleteBuffers(1,&_lastBuffer));
209 }
210 _bigSound = NO;
211
212
213 OOSound *sound = _sound;
214 _sound = nil;
215
216 if (nil != _delegate && [_delegate respondsToSelector:@selector(channel:didFinishPlayingSound:)])
217 {
218 [_delegate channel:self didFinishPlayingSound:sound];
219 }
220 [sound release];
221}
222
223
224- (BOOL) enqueueBuffer:(OOSound *)sound
225{
226 // get sound data
227 _buffer = [sound soundBuffer];
228 // bind sound data to buffer
229 OOAL(alSourceQueueBuffers(_source, 1, &_buffer));
230 ALuint error;
231 if ((error = alGetError()) != AL_NO_ERROR)
232 {
233 OOLog(@"ov.debug", @"Error %u queueing buffers (_source: %u (%p), _buffer: %u (%p))",
234 error, _source, &_source, _buffer, &_buffer);
235 return NO;
236 }
237 ALint playing = 0;
238 OOAL(alGetSourcei(_source,AL_SOURCE_STATE,&playing));
239 if (playing != AL_PLAYING)
240 {
241 OOAL(alSourcePlay(_source));
242 if ((error = alGetError()) != AL_NO_ERROR)
243 {
244 OOLog(@"ov.debug",@"Error %d playing source",error);
245 return NO;
246 }
247 }
248 return YES;
249}
250
251
252
253- (OOSound *)sound
254{
255 return _sound;
256}
257
258@end
#define OOLog(class, format,...)
Definition OOLogging.h:88
static NSString *const kOOLogSoundInitError
#define OOAL(cmd)
Definition OOOpenAL.h:40
return nil
void rewind()
Definition OOALSound.m:175
ALuint soundBuffer()
Definition OOALSound.m:162