Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

output_al.cpp

Go to the documentation of this file.
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   // are we already initialized?
00042   if (m_Device) {
00043     return false;
00044   }
00045 
00046   // open an output device
00047   m_Device = alcOpenDevice(0);
00048   if (!m_Device) {
00049     return false;
00050   }
00051 
00052   // create a rendering context
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   // define the listener state
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   // set the listener state
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         // set the distance model
00077         alDistanceModel(AL_NONE);
00078         success = (alGetError() == AL_NO_ERROR);
00079 
00080       }
00081     }
00082   }
00083 
00084   // if we failed, go home
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   // enumerate all open streams
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   // calculate OpenAL format
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   // generate buffers
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   // generate sources
00143   // we have one source for each channel
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   // fill the members
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   // calculate the desired length (in samples) of each buffer
00196   m_BufferLength = BUFFER_MILLISECONDS * m_SampleRate / 1000;
00197 
00198   FillBuffers();
00199 
00200   // queue up the source's buffers
00201   alSourceQueueBuffers(m_ALSource, BUFFER_COUNT, m_Buffers);
00202 }
00203 
00205 
00206 ALOutputStream::~ALOutputStream()
00207 {
00208   // remove ourself from the list
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   // are there any buffers that have been processed?
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   // don't do any allocations if we don't need to
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     // unqueue/refill/queue
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   // try to read from the stream
00279   int samples_read = m_Source->Read(sample_count, samples);
00280 
00281   // read the last sample
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   // fill the rest with silence
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   // stick the data into the buffers
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   // reset stream
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

Generated at Mon Jun 10 02:55:12 2002 for audiere by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001