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

device_oal.cpp

Go to the documentation of this file.
00001 #include "device_oal.h"
00002 #include "threads.h"
00003 
00004 
00005 static const int BUFFER_COUNT = 4;
00006 static const int BUFFER_MILLISECONDS = 250;
00007 
00008 
00009 namespace audiere {
00010 
00011   OALAudioDevice*
00012   OALAudioDevice::create(const ParameterList& parameters) {
00013     // open an output device
00014     ALCdevice* device = alcOpenDevice(0);
00015     if (!device) {
00016       return 0;
00017     }
00018 
00019     // create a rendering context
00020     ALCcontext* context = alcCreateContext(device, 0);
00021     if (!context) {
00022       alcCloseDevice(device);
00023       return false;
00024     }
00025 
00026     alcMakeContextCurrent(context);
00027 
00028     // define the listener state
00029     ALfloat position[]    = { 0.0, 0.0, 0.0 };
00030     ALfloat velocity[]    = { 0.0, 0.0, 0.0 };
00031     ALfloat orientation[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 };
00032 
00033     // set the listener state
00034     bool success = false;
00035     alListenerfv(AL_POSITION, position);
00036     if (alGetError() == AL_NO_ERROR) {
00037       alListenerfv(AL_VELOCITY, velocity);
00038       if (alGetError() == AL_NO_ERROR) {
00039         alListenerfv(AL_ORIENTATION, orientation);
00040         if (alGetError() == AL_NO_ERROR) {
00041 
00042           // set the distance model
00043           alDistanceModel(AL_NONE);
00044           success = (alGetError() == AL_NO_ERROR);
00045 
00046         }
00047       }
00048     }
00049 
00050     // if we failed, go home
00051     if (!success) {
00052       alcMakeContextCurrent(0);
00053       alcDestroyContext(context);
00054       alcCloseDevice(device);
00055       return 0;
00056     }
00057 
00058     return new OALAudioDevice(device, context);
00059   }
00060 
00061 
00062   OALAudioDevice::OALAudioDevice(ALCdevice* device, ALCcontext* context) {
00063     m_device  = device;
00064     m_context = context;
00065   }
00066 
00067 
00068   OALAudioDevice::~OALAudioDevice() {
00069     if (m_context) {
00070       alcMakeContextCurrent(0);
00071       alcDestroyContext(m_context);
00072       m_context = 0;
00073     }
00074 
00075     if (m_device) {
00076       alcCloseDevice(m_device);
00077       m_device = 0;
00078     }
00079   }
00080 
00081 
00082   void
00083   OALAudioDevice::update() {
00084     // enumerate all open streams
00085     StreamList::iterator i = m_open_streams.begin();
00086     while (i != m_open_streams.end()) {
00087       OALOutputStream* s = *i++;
00088       s->update();
00089     }
00090   }
00091 
00092 
00093   OutputStream*
00094   OALAudioDevice::openStream(SampleSource* source) {
00095     if (!source) {
00096       return 0;
00097     }
00098 
00099     int channel_count, sample_rate;
00100     SampleFormat sample_format;
00101     source->getFormat(channel_count, sample_rate, sample_format);
00102 
00103     // calculate OpenAL format
00104     ALenum format;
00105     if (channel_count == 1 && sample_format == SF_U8) {
00106       format = AL_FORMAT_MONO8;
00107     } else if (channel_count == 1 && sample_format == SF_S16) {
00108       format = AL_FORMAT_MONO16;
00109     } else if (channel_count == 2 && sample_format == SF_U8) {
00110       format = AL_FORMAT_STEREO8;
00111     } else if (channel_count == 2 && sample_format == SF_S16) {
00112       format = AL_FORMAT_STEREO16;
00113     } else {
00114       return 0;
00115     }
00116 
00117     // generate buffers
00118     ALuint* buffers = new ALuint[BUFFER_COUNT];
00119     alGenBuffers(BUFFER_COUNT, buffers);
00120     if (alGetError() != AL_NO_ERROR) {
00121       delete[] buffers;
00122       return NULL;
00123     }
00124 
00125     // generate sources
00126     // we have one source for each channel
00127     ALuint al_source;
00128     alGenSources(1, &al_source);
00129     if (alGetError() != AL_NO_ERROR) {
00130       alDeleteBuffers(BUFFER_COUNT, buffers);
00131       delete[] buffers;
00132       return NULL;
00133     }
00134 
00135     OALOutputStream* stream = new OALOutputStream(
00136       this,
00137       source,
00138       al_source,
00139       buffers,
00140       format,
00141       sample_rate);
00142     m_open_streams.push_back(stream);
00143     return stream;
00144   }
00145 
00146 
00147   OutputStream*
00148   OALAudioDevice::openBuffer(
00149     void* samples, int frame_count,
00150     int channel_count, int sample_rate, SampleFormat sample_format)
00151   {
00153     return 0;
00154   }
00155 
00156 
00157   void
00158   OALAudioDevice::removeStream(OALOutputStream* stream) {
00159     m_open_streams.remove(stream);
00160   }
00161 
00162 
00163   OALOutputStream::OALOutputStream(
00164     OALAudioDevice* device,
00165     SampleSource* source,
00166     ALuint al_source,
00167     ALuint* buffers,
00168     ALenum format,
00169     int sample_rate)
00170   {
00171     m_device = device;
00172 
00173     m_source = source;
00174 
00175     m_sample_rate = sample_rate;
00176     m_format = format;
00177     switch (format) {
00178       case AL_FORMAT_MONO8:    m_sample_size = 1; break;
00179       case AL_FORMAT_MONO16:   m_sample_size = 2; break;
00180       case AL_FORMAT_STEREO8:  m_sample_size = 2; break;
00181       case AL_FORMAT_STEREO16: m_sample_size = 4; break;
00182     }
00183 
00184     m_last_sample = new ALubyte[m_sample_size];
00185     memset(m_last_sample, 0, m_sample_size);
00186 
00187     m_ALsource = al_source;
00188     m_buffers  = buffers;
00189 
00190     m_is_playing = false;
00191     m_volume     = 1;
00192 
00193     // calculate the desired length (in samples) of each buffer
00194     m_buffer_length = BUFFER_MILLISECONDS * m_sample_rate / 1000;
00195 
00196     fillBuffers();
00197 
00198     // queue up the source's buffers
00199     alSourceQueueBuffers(m_ALsource, BUFFER_COUNT, m_buffers);
00200   }
00201 
00202 
00203   OALOutputStream::~OALOutputStream() {
00204     m_device->removeStream(this);
00205 
00206     alDeleteSources(1, &m_ALsource);
00207     alDeleteBuffers(BUFFER_COUNT, m_buffers);
00208     delete[] m_buffers;
00209     delete[] m_last_sample;
00210   }
00211 
00212 
00213   void
00214   OALOutputStream::update() {
00215     // are there any buffers that have been processed?
00216     ALint processed_buffers;
00217 #ifdef _WIN32 // XXX more OpenAL hacks
00218     alGetSourcei(m_ALsource, AL_BUFFERS_PROCESSED, &processed_buffers);
00219 #else
00220     alGetSourceiv(m_ALsource, AL_BUFFERS_PROCESSED, &processed_buffers);
00221 #endif
00222 
00223     // don't do any allocations if we don't need to
00224     if (processed_buffers == 0) {
00225       return;
00226     }
00227 
00228     int read_size_samples = m_buffer_length;
00229     int read_size_bytes = read_size_samples * m_sample_size;
00230     ALubyte* sample_buffer = new ALubyte[read_size_bytes];
00231 
00232     int buffer_length_bytes = read_size_bytes;
00233     while (processed_buffers--) {
00234 
00235       if (read(sample_buffer, read_size_samples) == 0) {
00236         stop();
00237         break;
00238       }
00239 
00240       // unqueue/refill/queue
00241       ALuint buffer;
00242       alSourceUnqueueBuffers(m_ALsource, 1, &buffer);
00243 
00244       alBufferData(
00245         buffer,
00246         m_format,
00247         sample_buffer,
00248         buffer_length_bytes,
00249         m_sample_rate);
00250 
00251       alSourceQueueBuffers(m_ALsource, 1, &buffer);
00252     }
00253 
00254     delete[] sample_buffer;
00255 
00256     AI_Sleep(50);
00257   }
00258 
00259 
00260   int
00261   OALOutputStream::read(void* samples, int sample_count) {
00262     // try to read from the stream
00263     int samples_read = m_source->read(sample_count, samples);
00264 
00265     // read the last sample
00266     if (samples_read > 0) {
00267       memcpy(
00268         m_last_sample,
00269         (ALubyte*)samples + (samples_read - 1) * m_sample_size,
00270         m_sample_size);
00271     }
00272 
00273     // fill the rest with silence
00274     ALubyte* out = (ALubyte*)samples + m_sample_size * samples_read;
00275     int c = sample_count - samples_read;
00276     while (c--) {
00277       memcpy(out, m_last_sample, m_sample_size);
00278       out += m_sample_size;
00279     }
00280 
00281     return samples_read;
00282   }
00283 
00284 
00285   void
00286   OALOutputStream::fillBuffers() {
00287     int samples_to_read = m_buffer_length * BUFFER_COUNT;
00288     int allocate = samples_to_read * m_sample_size;
00289     ALubyte* sample_buffer = new ALubyte[allocate];
00290     read(sample_buffer, samples_to_read);
00291    
00292     for (int i = 0; i < BUFFER_COUNT; i++) {      
00293       alBufferData(
00294         m_buffers[i],
00295         m_format,
00296         sample_buffer + i * m_buffer_length * m_sample_size,
00297         m_buffer_length * m_sample_size,
00298         m_sample_rate);
00299     }
00300 
00301     delete[] sample_buffer;
00302   }
00303 
00304 
00305   void
00306   OALOutputStream::play() {
00307     alSourcePlay(m_ALsource);
00308     m_is_playing = true;
00309   }
00310 
00311 
00312   void
00313   OALOutputStream::stop() {
00314     alSourcePause(m_ALsource);
00315     m_is_playing = false;
00316   }
00317 
00318 
00319   bool
00320   OALOutputStream::isPlaying() {
00321     return m_is_playing;
00322   }
00323 
00324 
00325   void
00326   OALOutputStream::reset() {
00327     bool is_playing = isPlaying();
00328     if (is_playing) {
00329       stop();
00330     }
00331 
00332     // reset stream
00333 
00334     if (is_playing) {
00335       play();
00336     }
00337   }
00338 
00339 
00340   void
00341   OALOutputStream::setRepeat(bool repeat) {
00343   }
00344 
00345 
00346   bool
00347   OALOutputStream::getRepeat() {
00349     return false;
00350   }
00351 
00352 
00353   void
00354   OALOutputStream::setVolume(float volume) {
00355     m_volume = volume;
00356     alSourcef(m_ALsource, AL_GAIN, volume);
00357   }
00358 
00359 
00360   float
00361   OALOutputStream::getVolume() {
00362     return m_volume;
00363   }
00364 
00365 
00366   void
00367   OALOutputStream::setPan(float pan) {
00369   }
00370 
00371 
00372   float
00373   OALOutputStream::getPan() {
00375     return 0.0f;
00376   }
00377 
00378 
00379   void
00380   OALOutputStream::setPitchShift(float shift) {
00382   }
00383 
00384 
00385   float
00386   OALOutputStream::getPitchShift() {
00388     return 0;
00389   }
00390 
00391 
00392   bool
00393   OALOutputStream::isSeekable() {
00395     return false;
00396   }
00397 
00398 
00399   int
00400   OALOutputStream::getLength() {
00402     return 0;
00403   }
00404 
00405 
00406   void
00407   OALOutputStream::setPosition(int /*position*/) {
00409   }
00410 
00411 
00412   int
00413   OALOutputStream::getPosition() {
00415     return 0;
00416   }
00417 
00418 }

Generated on Sat Oct 12 01:43:02 2002 for audiere by doxygen1.2.17