00001 #ifdef WITH_OPENAL
00002
00003 #include <limits.h>
00004 #include "output_al.hpp"
00005 #include "threads.hpp"
00006
00007
00008 static const int BUFFER_COUNT = 4;
00009 static const int BUFFER_MILLISECONDS = 250;
00010
00011
00013
00014 ALOutputContext::ALOutputContext()
00015 {
00016 m_Device = 0;
00017 m_Context = 0;
00018 }
00019
00021
00022 ALOutputContext::~ALOutputContext()
00023 {
00024 if (m_Context) {
00025 alcMakeContextCurrent(0);
00026 alcDestroyContext(m_Context);
00027 m_Context = 0;
00028 }
00029
00030 if (m_Device) {
00031 alcCloseDevice(m_Device);
00032 m_Device = 0;
00033 }
00034 }
00035
00037
00038 bool
00039 ALOutputContext::Initialize(const char* parameters)
00040 {
00041
00042 if (m_Device) {
00043 return false;
00044 }
00045
00046
00047 m_Device = alcOpenDevice(0);
00048 if (!m_Device) {
00049 return false;
00050 }
00051
00052
00053 m_Context = alcCreateContext(m_Device, 0);
00054 if (!m_Context) {
00055 alcCloseDevice(m_Device);
00056 m_Device = 0;
00057 return false;
00058 }
00059
00060 alcMakeContextCurrent(m_Context);
00061
00062
00063 ALfloat position[] = { 0.0, 0.0, 0.0 };
00064 ALfloat velocity[] = { 0.0, 0.0, 0.0 };
00065 ALfloat orientation[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 };
00066
00067
00068 bool success = false;
00069 alListenerfv(AL_POSITION, position);
00070 if (alGetError() == AL_NO_ERROR) {
00071 alListenerfv(AL_VELOCITY, velocity);
00072 if (alGetError() == AL_NO_ERROR) {
00073 alListenerfv(AL_ORIENTATION, orientation);
00074 if (alGetError() == AL_NO_ERROR) {
00075
00076
00077 alDistanceModel(AL_NONE);
00078 success = (alGetError() == AL_NO_ERROR);
00079
00080 }
00081 }
00082 }
00083
00084
00085 if (!success) {
00086 alcMakeContextCurrent(0);
00087 alcDestroyContext(m_Context);
00088 m_Context = 0;
00089 alcCloseDevice(m_Device);
00090 m_Device = 0;
00091 return false;
00092 }
00093
00094 return (m_Device != 0);
00095 }
00096
00098
00099 void
00100 ALOutputContext::Update()
00101 {
00102
00103 StreamList::iterator i = m_OpenStreams.begin();
00104 while (i != m_OpenStreams.end()) {
00105 ALOutputStream* s = *i++;
00106 s->Update();
00107 }
00108 }
00109
00111
00112 IOutputStream*
00113 ALOutputContext::OpenStream(ISampleSource* source)
00114 {
00115 int channel_count;
00116 int sample_rate;
00117 int bits_per_sample;
00118 source->GetFormat(channel_count, sample_rate, bits_per_sample);
00119
00120
00121 ALenum format;
00122 if (channel_count == 1 && bits_per_sample == 8) {
00123 format = AL_FORMAT_MONO8;
00124 } else if (channel_count == 1 && bits_per_sample == 16) {
00125 format = AL_FORMAT_MONO16;
00126 } else if (channel_count == 2 && bits_per_sample == 8) {
00127 format = AL_FORMAT_STEREO8;
00128 } else if (channel_count == 2 && bits_per_sample == 16) {
00129 format = AL_FORMAT_STEREO16;
00130 } else {
00131 return 0;
00132 }
00133
00134
00135 ALuint* buffers = new ALuint[BUFFER_COUNT];
00136 alGenBuffers(BUFFER_COUNT, buffers);
00137 if (alGetError() != AL_NO_ERROR) {
00138 delete[] buffers;
00139 return NULL;
00140 }
00141
00142
00143
00144 ALuint al_source;
00145 alGenSources(1, &al_source);
00146 if (alGetError() != AL_NO_ERROR) {
00147 alDeleteBuffers(BUFFER_COUNT, buffers);
00148 delete[] buffers;
00149 return NULL;
00150 }
00151
00152 ALOutputStream* stream = new ALOutputStream(
00153 this,
00154 source,
00155 al_source,
00156 buffers,
00157 format,
00158 sample_rate);
00159 m_OpenStreams.push_back(stream);
00160 return stream;
00161 }
00162
00164
00165 ALOutputStream::ALOutputStream(
00166 ALOutputContext* context,
00167 ISampleSource* source,
00168 ALuint al_source,
00169 ALuint* buffers,
00170 ALenum format,
00171 int sample_rate)
00172 {
00173
00174 m_Context = context;
00175 m_Source = source;
00176
00177 m_SampleRate = sample_rate;
00178 m_Format = format;
00179 switch (format) {
00180 case AL_FORMAT_MONO8: m_SampleSize = 1; break;
00181 case AL_FORMAT_MONO16: m_SampleSize = 2; break;
00182 case AL_FORMAT_STEREO8: m_SampleSize = 2; break;
00183 case AL_FORMAT_STEREO16: m_SampleSize = 4; break;
00184 }
00185
00186 m_LastSample = new ALubyte[m_SampleSize];
00187 memset(m_LastSample, 0, m_SampleSize);
00188
00189 m_ALSource = al_source;
00190 m_Buffers = buffers;
00191
00192 m_IsPlaying = false;
00193 m_Volume = ADR_VOLUME_MAX;
00194
00195
00196 m_BufferLength = BUFFER_MILLISECONDS * m_SampleRate / 1000;
00197
00198 FillBuffers();
00199
00200
00201 alSourceQueueBuffers(m_ALSource, BUFFER_COUNT, m_Buffers);
00202 }
00203
00205
00206 ALOutputStream::~ALOutputStream()
00207 {
00208
00209 ALOutputContext::StreamList::iterator i = m_Context->m_OpenStreams.begin();
00210 while (i != m_Context->m_OpenStreams.end()) {
00211 if (*i == this) {
00212 m_Context->m_OpenStreams.erase(i);
00213 break;
00214 }
00215 ++i;
00216 }
00217
00218 alDeleteSources(1, &m_ALSource);
00219 alDeleteBuffers(BUFFER_COUNT, m_Buffers);
00220 delete[] m_Buffers;
00221 delete[] m_LastSample;
00222 }
00223
00225
00226 void
00227 ALOutputStream::Update()
00228 {
00229
00230 ALint processed_buffers;
00231 #ifdef _WIN32 // XXX more OpenAL hacks
00232 alGetSourcei(m_ALSource, AL_BUFFERS_PROCESSED, &processed_buffers);
00233 #else
00234 alGetSourceiv(m_ALSource, AL_BUFFERS_PROCESSED, &processed_buffers);
00235 #endif
00236
00237
00238 if (processed_buffers == 0) {
00239 return;
00240 }
00241
00242 int read_size_samples = m_BufferLength;
00243 int read_size_bytes = read_size_samples * m_SampleSize;
00244 ALubyte* sample_buffer = new ALubyte[read_size_bytes];
00245
00246 int buffer_length_bytes = read_size_bytes;
00247 while (processed_buffers--) {
00248
00249 if (Read(sample_buffer, read_size_samples) == 0) {
00250 Stop();
00251 break;
00252 }
00253
00254
00255 ALuint buffer;
00256 alSourceUnqueueBuffers(m_ALSource, 1, &buffer);
00257
00258 alBufferData(
00259 buffer,
00260 m_Format,
00261 sample_buffer,
00262 buffer_length_bytes,
00263 m_SampleRate);
00264
00265 alSourceQueueBuffers(m_ALSource, 1, &buffer);
00266 }
00267
00268 delete[] sample_buffer;
00269
00270 AI_Sleep(50);
00271 }
00272
00274
00275 int
00276 ALOutputStream::Read(void* samples, int sample_count)
00277 {
00278
00279 int samples_read = m_Source->Read(sample_count, samples);
00280
00281
00282 if (samples_read > 0) {
00283 memcpy(
00284 m_LastSample,
00285 (ALubyte*)samples + (samples_read - 1) * m_SampleSize,
00286 m_SampleSize
00287 );
00288 }
00289
00290
00291 ALubyte* out = (ALubyte*)samples + m_SampleSize * samples_read;
00292 int c = sample_count - samples_read;
00293 while (c--) {
00294 memcpy(out, m_LastSample, m_SampleSize);
00295 out += m_SampleSize;
00296 }
00297
00298 return samples_read;
00299 }
00300
00302
00303 void
00304 ALOutputStream::FillBuffers()
00305 {
00306 int samples_to_read = m_BufferLength * BUFFER_COUNT;
00307 int allocate = samples_to_read * m_SampleSize;
00308 ALubyte* sample_buffer = new ALubyte[allocate];
00309 Read(sample_buffer, samples_to_read);
00310
00311
00312 ALubyte* samples = sample_buffer;
00313 ALuint* buffer = m_Buffers;
00314
00315 for (int i = 0; i < BUFFER_COUNT; i++) {
00316
00317 alBufferData(
00318 *buffer,
00319 m_Format,
00320 samples,
00321 m_BufferLength * m_SampleSize,
00322 m_SampleRate);
00323
00324 samples += m_BufferLength * m_SampleSize;
00325 buffer++;
00326 }
00327
00328 delete[] sample_buffer;
00329 }
00330
00332
00333 void
00334 ALOutputStream::Play()
00335 {
00336 alSourcePlay(m_ALSource);
00337 m_IsPlaying = true;
00338 }
00339
00341
00342 void
00343 ALOutputStream::Stop()
00344 {
00345 alSourcePause(m_ALSource);
00346 m_IsPlaying = false;
00347 }
00348
00350
00351 void
00352 ALOutputStream::Reset()
00353 {
00354 bool is_playing = IsPlaying();
00355 if (is_playing) {
00356 Stop();
00357 }
00358
00359
00360
00361 if (is_playing) {
00362 Play();
00363 }
00364 }
00365
00367
00368 bool
00369 ALOutputStream::IsPlaying()
00370 {
00371 return m_IsPlaying;
00372 }
00373
00375
00376 void
00377 ALOutputStream::SetVolume(int volume)
00378 {
00379 m_Volume = volume;
00380
00381 float v = (float)m_Volume / ADR_VOLUME_MAX;
00382 alSourcef(m_ALSource, AL_GAIN, v);
00383 }
00384
00386
00387 int
00388 ALOutputStream::GetVolume()
00389 {
00390 return m_Volume;
00391 }
00392
00394
00395 #endif // WITH_OPENAL