Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OpenALRenderableStreamingSource.cpp
Go to the documentation of this file.
1 //
2 // C++ Implementation: Audio::OpenALRenderableListener
3 //
5 #include "OpenALStreamingSound.h"
6 #include "OpenALHelpers.h"
7 #include "config.h"
8 
9 #include "al.h"
10 
11 #include "../../Source.h"
12 #include "../../Listener.h"
13 
14 #include "vs_math.h"
15 
16 namespace Audio {
17 
18  static inline void alSource3f(ALuint source, ALenum param, const Vector3 &v)
19  {
20  ::alSource3f(source, param, ALfloat(v.x), ALfloat(v.y), ALfloat(v.z));
21  }
22 
23  static inline void alSource3f(ALuint source, ALenum param, const LVector3 &v)
24  {
25  ::alSource3f(source, param, ALfloat(v.x), ALfloat(v.y), ALfloat(v.z));
26  }
27 
29  : RenderableSource(source)
30  , alSource(0)
31  , atEos(false)
32  , shouldPlay(false)
33  , buffering(false)
34  {
35  alGenSources(1,&alSource);
36  }
37 
39  {
40  alDeleteSources(1,&alSource);
41  }
42 
44  throw(Exception)
45  {
46  if (!isPlayingImpl()) {
47  SharedPtr<Sound> sound = getSource()->getSound();
48 
49  assert(sound->isStreaming() && "OpenALRenderableStreamingSource can only handle streaming sounds");
50 
51  if (!sound->isLoaded())
52  sound->load();
53  else if (!buffering)
54  dynamic_cast<OpenALStreamingSound*>(sound.get())->flushBuffers();
55 
56  // Seek the stream to the specified position
57  atEos = false;
58  shouldPlay = true;
59  dynamic_cast<OpenALStreamingSound*>(sound.get())->seek(start);
60 
61  // Make sure we have some starting buffers queued
62  queueALBuffers();
63 
64  // Tell the AL to start playing
65  clearAlError();
66  ALuint als = getALSource();
67  alSourcePlay(als);
68  checkAlError();
69  }
70  }
71 
73  throw(Exception)
74  {
75  shouldPlay = false;
76  buffering = false;
77  alSourceStop(alSource);
78  }
79 
81  throw(Exception)
82  {
83  ALint state = 0;
84  alGetSourcei(getALSource(), AL_SOURCE_STATE, &state);
85  return (state == AL_PLAYING);
86  }
87 
89  throw(Exception)
90  {
91  ALfloat offs = -1.f;
92  alGetSourcef(getALSource(), AL_SEC_OFFSET, &offs);
93 
94  if (offs < 0.f)
95  throw NotImplementedException("getPlayingTimeImpl");
96 
97  Timestamp base = dynamic_cast<OpenALStreamingSound*>(getSource()->getSound().get())
98  ->getTimeBase();
99 
100  return Timestamp(offs) + base;
101  }
102 
104  throw(Exception)
105  {
106  // Seek the stream to the specified position
107  atEos = false;
108  dynamic_cast<OpenALStreamingSound*>(getSource()->getSound().get())
109  ->seek(time);
110  }
111 
112  void OpenALRenderableStreamingSource::updateImpl(int flags, const Listener& sceneListener)
113  throw(Exception)
114  {
115  Source *source = getSource();
116  ALSourceHandle als = getALSource();
117 
118  // Restart playing in case of a buffer underrun,
119  // else just fill buffers
120  if (shouldBePlaying() && !isPlayingImpl()) {
121  // startPlayingImpl(source->getWouldbePlayingTime());
122  // NOTE: Cannot use startPlaying because it stresses the buggy seek method
123  // Must fix that
124 
125  SharedPtr<Sound> sound = source->getSound();
126 
127  if (!sound->isLoaded())
128  sound->load();
129  else if (!buffering)
130  dynamic_cast<OpenALStreamingSound*>(sound.get())->flushBuffers();
131 
132  // Make sure we have some starting buffers queued
133  queueALBuffers();
134 
135  // Tell the AL to start playing
136  clearAlError();
137  ALuint als = getALSource();
138  alSourcePlay(als);
139  checkAlError();
140  } else {
141  queueALBuffers();
142  }
143 
144  // Update various attributes if required
145  clearAlError();
146 
147  if (flags & UPDATE_ATTRIBUTES) {
148  // Distance attenuation
149  if (source->isAttenuated()) {
150  alSourcef(als, AL_REFERENCE_DISTANCE, source->getRadius());
151  alSourcef(als, AL_ROLLOFF_FACTOR, 1.f / source->getRadius());
152  } else {
153  alSourcef(als, AL_ROLLOFF_FACTOR, 0.f);
154  }
155  // Cone
156  {
157  Range<Scalar> angleRange = source->getAngleRange();
158  alSourcef(als, AL_CONE_INNER_ANGLE, float(angleRange.min) * M_1_PI * 360.f);
159  alSourcef(als, AL_CONE_OUTER_ANGLE, float(angleRange.max) * M_1_PI * 360.f);
160  alSourcef(als, AL_CONE_OUTER_GAIN , 0.f);
161  }
162  // Relativity
163  alSourcei(als, AL_SOURCE_RELATIVE, source->isRelative() ? AL_TRUE : AL_FALSE);
164  // Looping
165  alSourcei(als, AL_LOOPING, source->isLooping() ? AL_TRUE : AL_FALSE);
166  }
167  if (flags & UPDATE_GAIN) {
168  // Gain
169  alSourcef(als, AL_GAIN, source->getGain());
170  }
171  if (flags & UPDATE_LOCATION) {
172  if (source->isRelative()) {
173  alSource3f(als, AL_POSITION, source->getPosition());
174  alSource3f(als, AL_VELOCITY, source->getVelocity());
175  alSource3f(als, AL_DIRECTION, source->getDirection());
176  } else {
177  alSource3f(als, AL_POSITION,
178  source->getPosition() - sceneListener.getPosition() );
179  alSource3f(als, AL_VELOCITY,
180  sceneListener.toLocalDirection(
181  source->getVelocity() - sceneListener.getVelocity()
182  ) );
183  alSource3f(als, AL_DIRECTION,
184  sceneListener.toLocalDirection(
185  source->getDirection()
186  ) );
187  }
188  }
189 
190  checkAlError();
191  }
192 
194  throw(Exception)
195  {
196  SharedPtr<Sound> sound = getSource()->getSound();
197 
198  if (!sound->isLoaded())
199  sound->load();
200 
201  assert(sound->isStreaming() && "OpenALRenderableStreamingSource can only handle streaming sounds");
202 
203  buffering = true;
204 
205  OpenALStreamingSound *streamingSound = dynamic_cast<OpenALStreamingSound*>(sound.get());
206  Source *source = getSource();
207  ALSourceHandle als = getALSource();
208  ALint buffersProcessed = 0;
209 
210  // Unqueue any buffers the AL is done with,
211  // returning them to the streaming sound
212  alGetSourcei(als, AL_BUFFERS_PROCESSED, &buffersProcessed);
213 
214  while (buffersProcessed > 0) {
215  ALBufferHandle buffers[2];
216  ALsizei nbuffers = (buffersProcessed > 2) ? 2 : (ALsizei)buffersProcessed;
217  alSourceUnqueueBuffers(als, nbuffers, buffers);
218 
219  for (ALsizei i=0; i<nbuffers; ++i)
220  streamingSound->unqueueBuffer(buffers[i]);
221 
222  buffersProcessed -= nbuffers;
223  }
224 
225  // Get buffers from the streaming sound and queue them
226  // until the streaming sound says Basta!
228  do {
229  try {
230  buffer = streamingSound->readAndFlip();
231  } catch(EndOfStreamException e) {
232  fprintf(stderr, "EOS!\n");
233  if (source->isLooping()) {
234  streamingSound->seek(0);
235  buffer = streamingSound->readAndFlip();
236  } else {
237  atEos = true;
238  buffer = AL_NULL_BUFFER;
239  }
240  }
241  if (buffer != AL_NULL_BUFFER)
242  alSourceQueueBuffers(als, 1, &buffer);
243  } while (buffer != AL_NULL_BUFFER);
244  }
245 
246 };