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
OpenALSimpleSound.cpp
Go to the documentation of this file.
1 //
2 // C++ Implementation: Audio::OpenALSimpleSound
3 //
4 
5 #include "OpenALSimpleSound.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 namespace Audio {
24 
26  throw() :
27  SimpleSound(name, type, false),
28  bufferHandle(AL_NULL_BUFFER)
29  {
30  }
31 
33  {
34  }
35 
36  void OpenALSimpleSound::loadImpl(bool wait)
37  throw(Exception)
38  {
39  // just in case
40  unloadImpl();
41 
42  try {
43 
44  flags.loading = 1;
45 
46  // load the stream
47  try {
48  loadStream();
50  // Weird...
51  getStream()->seek(0);
52  }
53  SharedPtr<Stream> stream = getStream();
54 
55  // setup formatted buffer
56  // if the format does not match an OpenAL built-in format, we must convert it.
57  Format targetFormat = stream->getFormat();
58  targetFormat.signedSamples = (targetFormat.bitsPerSample > 8);
59  targetFormat.nativeOrder = 1;
60  if (targetFormat.bitsPerSample > 8)
61  targetFormat.bitsPerSample = 16;
62  else
63  targetFormat.bitsPerSample = 8;
64 
65  // Set capacity to half a second or 16k samples, whatever's bigger
66  size_t bufferCapacity =
67  std::max( 16384U, targetFormat.sampleFrequency/2 );
68 
69  // Prepare a list of buffers, we'll stack them here and later append them
70  std::list<SoundBuffer> buffers;
71 
72  try {
73  while (true) {
74  // Prepare a new buffer
75  buffers.push_back(SoundBuffer());
76  SoundBuffer &buffer = buffers.back();
77  buffer.reserve(bufferCapacity, targetFormat);
78 
79  // Fill it in
80  readBuffer(buffer);
81 
82  // Make sure we're not wasting memory
83  buffer.optimize();
84 
85  // Break if there's no more data
86  if (buffer.getUsedBytes() == 0) {
87  buffers.pop_back();
88  break;
89  }
90  }
91  closeStream();
92  } catch(EndOfStreamException e) {
93  closeStream();
94  } catch(Exception e) {
95  closeStream();
96  throw e;
97  }
98 
99  // Free the stream, asap
100  stream.reset();
101 
102  // Collapse the chunks into a single buffer
104 
105  if (buffers.size() > 1) {
106  // Create a compound buffer with all buffers concatenated
107  {
108  unsigned int finalBytes = 0;
109  for (std::list<SoundBuffer>::const_iterator it = buffers.begin(); it != buffers.end(); ++it)
110  finalBytes += it->getUsedBytes();
111  buffer.reserve(finalBytes);
112  }
113 
114  {
115  char* buf = (char*)buffer.getBuffer();
116  for (std::list<SoundBuffer>::const_iterator it = buffers.begin(); it != buffers.end(); ++it) {
117  memcpy(buf, it->getBuffer(), it->getUsedBytes());
118  buf += it->getUsedBytes();
119  buffer.setUsedBytes( buffer.getUsedBytes() + it->getUsedBytes() );
120  }
121  }
122  } else if (buffers.size() > 0) {
123  buffer.swap(buffers.back());
124  } else {
125  throw CorruptStreamException(true);
126  }
127 
128  // Free the buffers, asap
129  // The AL will copy to their own buffers, freeing now kind of makes certain
130  // the AL will have enough memory to do so
131  // (kind of since if memory is allocated off the DSP card, it could still fail)
132  buffers.clear();
133 
134  // Send the data to the AL
135  clearAlError();
136 
137  alGenBuffers(1,&bufferHandle);
138  checkAlError();
139 
140  alBufferData(bufferHandle,
141  asALFormat(targetFormat),
142  buffer.getBuffer(), buffer.getUsedBytes(),
143  targetFormat.sampleFrequency);
144  checkAlError();
145 
146  onLoaded(true);
147  } catch(Exception e) {
148  onLoaded(false);
149  throw e;
150  }
151  }
152 
154  throw()
155  {
156  if (bufferHandle == AL_NULL_BUFFER)
157  return;
158 
159  alDeleteBuffers(1, &bufferHandle);
160  bufferHandle = AL_NULL_BUFFER;
161  }
162 
163 };