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
OpenALStreamingSound.cpp
Go to the documentation of this file.
1 //
2 // C++ Implementation: Audio::OpenALSimpleSound
3 //
4 
5 #include "OpenALStreamingSound.h"
6 #include "OpenALHelpers.h"
7 #include "config.h"
8 
9 #include "../../CodecRegistry.h"
10 #include "../../Stream.h"
11 #include "al.h"
12 
13 #ifdef max
14 #undef max
15 #endif
16 
17 #include <utility>
18 #include <list>
19 #include <string>
20 
21 using namespace Audio::__impl::OpenAL;
22 
23 // Handy macro
24 #define NUM_BUFFERS (sizeof(bufferHandles) / sizeof(bufferHandles[0]))
25 
26 
27 namespace Audio {
28 
30  unsigned int _bufferSamples)
31  throw() :
32  SimpleSound(name, type, true),
33  bufferSamples(_bufferSamples)
34  {
35  for (size_t i=0; i < NUM_BUFFERS; ++i)
36  bufferHandles[i] = AL_NULL_BUFFER;
37  }
38 
40  {
41  }
42 
44  throw(Exception)
45  {
46  // just in case
47  unloadImpl();
48 
49  try {
50 
51  flags.loading = 1;
52 
53  // load the stream
54  try {
55  loadStream();
57  // Weird...
58  getStream()->seek(0);
59  }
60  SharedPtr<Stream> stream = getStream();
61 
62  // setup formatted buffer
63  // if the format does not match an OpenAL built-in format, we must convert it.
64  targetFormat = stream->getFormat();
65  targetFormat.signedSamples = (targetFormat.bitsPerSample > 8);
66  targetFormat.nativeOrder = 1;
67  if (targetFormat.bitsPerSample > 8)
68  targetFormat.bitsPerSample = 16;
69  else
70  targetFormat.bitsPerSample = 8;
71 
72  // Set capacity to a quarter second or 16k samples, whatever's bigger
73  // TODO: make it configurable. But first, implement a central configuration repository.
74  bufferSamples = std::max( 16384U, targetFormat.sampleFrequency/4 );
75 
76  // Prepare a buffer, so we avoid repeated allocation/deallocation
77  buffer.reserve(bufferSamples, targetFormat);
78 
79  // Prepare AL buffers
80  clearAlError();
81  alGenBuffers(NUM_BUFFERS, bufferHandles);
82  checkAlError();
83 
84  // Initialize the buffer queue
85  flushBuffers();
86 
87  onLoaded(true);
88  } catch(Exception e) {
89  onLoaded(false);
90  throw e;
91  }
92  }
93 
95  throw()
96  {
97  // Mark as detached, so that readAndFlip() knows to initialize the source
98  // and streaming indices
99  readBufferIndex = 0;
100 
101  // Mark the playBufferIndex as uninitialized, by setting it to NUM_BUFFERS
102  // readAndFlip will initialize it later.
103  playBufferIndex = NUM_BUFFERS;
104  }
105 
107  throw()
108  {
109  if (isStreamLoaded())
110  closeStream();
111  if (bufferHandles[0] != AL_NULL_BUFFER)
112  alDeleteBuffers(sizeof(bufferHandles)/sizeof(bufferHandles[0]), bufferHandles);
113  }
114 
116  throw(Exception)
117  {
118  if (!isLoaded())
120 
121  // Check for a full queue
122  if (playBufferIndex == readBufferIndex)
123  return AL_NULL_BUFFER;
124 
125  bufferStarts[readBufferIndex] = getStream()->getPosition();
126 
127  readBuffer(buffer);
128 
129  // Break if there's no more data
130  if (buffer.getUsedBytes() == 0)
131  throw EndOfStreamException();
132 
133  ALBufferHandle bufferHandle = bufferHandles[readBufferIndex];
134 
135  clearAlError();
136  alBufferData(bufferHandle,
137  asALFormat(targetFormat),
138  buffer.getBuffer(), buffer.getUsedBytes(),
139  targetFormat.sampleFrequency);
140  checkAlError();
141 
142  if (playBufferIndex == NUM_BUFFERS)
143  playBufferIndex = readBufferIndex;
144 
145  readBufferIndex = (readBufferIndex + 1) % NUM_BUFFERS;
146  return bufferHandle;
147  }
148 
150  throw(Exception)
151  {
152  if (playBufferIndex < NUM_BUFFERS && buffer == bufferHandles[playBufferIndex]) {
153  playBufferIndex = (playBufferIndex + 1) % NUM_BUFFERS;
154  }
155  }
156 
157  void OpenALStreamingSound::seek(double position)
158  throw(Exception)
159  {
160  if (!isLoaded())
162 
163  getStream()->seek(position);
164  }
165 
167  throw()
168  {
169  return bufferStarts[playBufferIndex];
170  }
171 
172 };