Switch to using -I to find includes, rather than relative paths.
[gemrb.git] / gemrb / plugins / OpenALAudio / OpenALAudio.cpp
blobc05b7110656d488da1214c8724e2ee42b577f13f
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003-2004 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "OpenALAudio.h"
22 #include <cassert>
23 #include <cstdio>
25 bool checkALError(const char* msg, const char* status) {
26 int error = alGetError();
27 if (error != AL_NO_ERROR) {
28 printMessage("OpenAL", msg, WHITE );
29 printf (": %d ", error);
30 printStatus(status, YELLOW);
31 return true;
33 return false;
36 void showALCError(const char* msg, const char* status, ALCdevice *device) {
37 int error = alcGetError(device);
38 printMessage("OpenAL", msg, WHITE );
39 if (error != AL_NO_ERROR) {
40 printf (": %d ", error);
42 printStatus(status, YELLOW);
45 void AudioStream::ClearProcessedBuffers()
47 ALint processed = 0;
48 alGetSourcei( Source, AL_BUFFERS_PROCESSED, &processed );
50 checkALError("Failed to get processed buffers", "WARNING");
52 if (processed > 0) {
53 ALuint * b = new ALuint[processed];
54 alSourceUnqueueBuffers( Source, processed, b );
55 checkALError("Failed to unqueue buffers", "WARNING");
57 if (delete_buffers) {
58 alDeleteBuffers(processed, b);
59 checkALError("Failed to delete buffers", "WARNING");
62 delete[] b;
67 void AudioStream::ClearIfStopped()
69 if (free || locked) return;
71 if (!alIsSource(Source)) return;
73 ALint state;
74 alGetSourcei( Source, AL_SOURCE_STATE, &state );
75 if (!checkALError("Failed to check source state", "WARNING") &&
76 state == AL_STOPPED)
78 ClearProcessedBuffers();
79 alDeleteSources( 1, &Source );
80 checkALError("Failed to delete source", "WARNING");
81 Source = 0;
82 Buffer = 0;
83 free = true;
84 ambient = false;
85 locked = false;
86 delete_buffers = false;
90 void AudioStream::ForceClear()
92 if (!alIsSource(Source)) return;
94 alSourceStop(Source);
95 checkALError("Failed to stop source", "WARNING");
96 ClearProcessedBuffers();
97 ClearIfStopped();
100 OpenALAudioDriver::OpenALAudioDriver(void)
102 alutContext = NULL;
103 MusicPlaying = false;
104 music_memory = (unsigned char*) malloc(ACM_BUFFERSIZE);
105 MusicSource = 0;
106 memset(MusicBuffer, 0, MUSICBUFFERS*sizeof(ALuint));
107 musicMutex = SDL_CreateMutex();
108 MusicReader = 0;
109 ambim = NULL;
112 bool OpenALAudioDriver::Init(void)
114 ALCdevice *device;
115 ALCcontext *context;
117 device = alcOpenDevice (NULL);
118 if (device == NULL) {
119 showALCError("Failed to open device", "ERROR", device);
120 return false;
123 context = alcCreateContext (device, NULL);
124 if (context == NULL) {
125 showALCError("Failed to create context", "ERROR", device);
126 alcCloseDevice (device);
127 return false;
130 if (!alcMakeContextCurrent (context)) {
131 showALCError("Failed to select context", "ERROR", device);
132 alcDestroyContext (context);
133 alcCloseDevice (device);
134 return false;
136 alutContext = context;
138 //1 for speech
139 int sources = CountAvailableSources(MAX_STREAMS+1);
140 num_streams = sources - 1;
142 char buf[255];
143 sprintf(buf, "Allocated %d streams.%s", num_streams,
144 (num_streams < MAX_STREAMS ? " (Fewer than desired.)" : "" ) );
146 printMessage( "OpenAL", buf, WHITE );
148 stayAlive = true;
149 musicThread = SDL_CreateThread( MusicManager, this );
151 ambim = new AmbientMgrAL;
152 speech.free = true;
153 speech.ambient = false;
154 return true;
157 int OpenALAudioDriver::CountAvailableSources(int limit)
159 ALuint* src = new ALuint[limit+2];
160 int i;
161 for (i = 0; i < limit+2; ++i) {
162 alGenSources(1, &src[i]);
163 if (alGetError() != AL_NO_ERROR)
164 break;
166 if (i > 0)
167 alDeleteSources(i, src);
168 delete[] src;
170 // Leave two sources free for internal OpenAL usage
171 // (Might not be strictly necessary...)
172 i -= 2;
174 checkALError("Error while auto-detecting number of sources", "WARNING");
176 // Return number of succesfully allocated sources
177 return i;
180 OpenALAudioDriver::~OpenALAudioDriver(void)
182 if (!ambim) {
183 // initialisation must have failed
184 return;
187 for(int i =0; i<num_streams; i++) {
188 streams[i].ForceClear();
190 speech.ForceClear();
191 ResetMusics();
192 clearBufferCache(true);
194 ALCdevice *device;
196 alcMakeContextCurrent (NULL);
198 device = alcGetContextsDevice (alutContext);
199 alcDestroyContext (alutContext);
200 if (alcGetError (device) == ALC_NO_ERROR) {
201 alcCloseDevice (device);
203 alutContext = NULL;
204 SDL_mutexP(musicMutex);
205 SDL_KillThread(musicThread);
206 SDL_mutexV(musicMutex);
208 SDL_DestroyMutex(musicMutex);
209 musicMutex = NULL;
211 free(music_memory);
212 if(MusicReader)
213 core->FreeInterface(MusicReader);
215 delete ambim;
218 ALuint OpenALAudioDriver::loadSound(const char *ResRef, unsigned int &time_length)
220 ALuint Buffer = 0;
222 CacheEntry *e;
223 void* p;
225 if (!ResRef[0]) {
226 return 0;
228 if(buffercache.Lookup(ResRef, p))
230 e = (CacheEntry*) p;
231 time_length = e->Length;
232 return e->Buffer;
234 //no cache entry...
235 DataStream* stream = gamedata->GetResource(ResRef, IE_WAV_CLASS_ID);
236 if (!stream)
237 stream = gamedata->GetResource(ResRef, IE_OGG_CLASS_ID);
238 if (!stream)
239 return 0;
241 alGenBuffers(1, &Buffer);
242 if (checkALError("Unable to create sound buffer", "ERROR")) {
243 delete stream;
244 return 0;
247 SoundMgr* acm = (SoundMgr*) core->GetInterface(IE_WAV_CLASS_ID);
248 if (!acm->Open(stream)) {
249 core->FreeInterface(acm);
250 alDeleteBuffers( 1, &Buffer );
251 return 0;
253 int cnt = acm->get_length();
254 int riff_chans = acm->get_channels();
255 int samplerate = acm->get_samplerate();
256 //multiply always by 2 because it is in 16 bits
257 int rawsize = cnt * 2;
258 unsigned char * memory = (unsigned char*) malloc(rawsize);
259 //multiply always with 2 because it is in 16 bits
260 int cnt1 = acm->read_samples( ( short* ) memory, cnt ) * 2;
261 //Sound Length in milliseconds
262 time_length = ((cnt / riff_chans) * 1000) / samplerate;
263 //it is always reading the stuff into 16 bits
264 alBufferData( Buffer, GetFormatEnum( riff_chans, 16 ), memory, cnt1, samplerate );
265 core->FreeInterface( acm );
266 free(memory);
268 if (checkALError("Unable to fill buffer", "ERROR")) {
269 alDeleteBuffers( 1, &Buffer );
270 checkALError("Error deleting buffer", "WARNING");
271 return 0;
274 e = new CacheEntry;
275 e->Buffer = Buffer;
276 e->Length = ((cnt / riff_chans) * 1000) / samplerate;
278 buffercache.SetAt(ResRef, (void*)e);
279 //printf("LoadSound: added %s to cache: %d. Cache size now %d\n", ResRef, e->Buffer, buffercache.GetCount());
281 if (buffercache.GetCount() > BUFFER_CACHE_SIZE) {
282 evictBuffer();
284 return Buffer;
287 unsigned int OpenALAudioDriver::Play(const char* ResRef, int XPos, int YPos, unsigned int flags)
289 ALuint Buffer;
290 unsigned int time_length;
292 if(ResRef == NULL) {
293 if((flags & GEM_SND_SPEECH) && alIsSource(speech.Source)) {
294 //So we want him to be quiet...
295 alSourceStop( speech.Source );
296 checkALError("Unable to stop speech", "WARNING");
297 speech.ClearProcessedBuffers();
299 return 0;
302 Buffer = loadSound( ResRef, time_length );
303 if (Buffer == 0) {
304 return 0;
307 ALuint Source;
308 ALfloat SourcePos[] = {
309 (float) XPos, (float) YPos, 0.0f
311 ALfloat SourceVel[] = {
312 0.0f, 0.0f, 0.0f
315 ieDword volume = 100;
317 if (flags & GEM_SND_SPEECH) {
318 //speech has a single channel, if a new speech started
319 //we stop the previous one
320 if(!speech.free && alIsSource(speech.Source)) {
321 alSourceStop( speech.Source );
322 checkALError("Unable to stop speech", "WARNING");
323 speech.ClearProcessedBuffers();
325 if(!alIsSource(speech.Source)) {
326 alGenSources( 1, &speech.Source );
327 if (checkALError("Error creating source for speech", "ERROR")) {
328 return 0;
332 alSourcef( speech.Source, AL_PITCH, 1.0f );
333 alSourcefv( speech.Source, AL_VELOCITY, SourceVel );
334 alSourcei( speech.Source, AL_LOOPING, 0 );
335 alSourcef( speech.Source, AL_REFERENCE_DISTANCE, REFERENCE_DISTANCE );
336 checkALError("Unable to set speech parameters", "WARNING");
337 speech.free = false;
338 printf("speech.free: %d source:%d\n", speech.free,speech.Source);
340 core->GetDictionary()->Lookup( "Volume Voices", volume );
341 alSourcef( speech.Source, AL_GAIN, 0.01f * volume );
342 alSourcei( speech.Source, AL_SOURCE_RELATIVE, flags & GEM_SND_RELATIVE );
343 alSourcefv( speech.Source, AL_POSITION, SourcePos );
344 assert(!speech.delete_buffers);
345 alSourcei( speech.Source, AL_BUFFER, Buffer );
346 checkALError("Unable to set speech parameters", "WARNING");
347 speech.Buffer = Buffer;
348 alSourcePlay( speech.Source );
349 if (checkALError("Unable to play speech", "ERROR")) {
350 return 0;
352 return time_length;
355 int stream = -1;
356 for (int i = 0; i < num_streams; i++) {
357 streams[i].ClearIfStopped();
358 if (streams[i].free) {
359 stream = i;
360 break;
364 if (stream == -1) {
365 // Failed to assign new sound.
366 // The buffercache will handle deleting Buffer.
367 return 0;
370 // not speech
371 alGenSources( 1, &Source );
372 if (checkALError("Unable to create source", "ERROR")) {
373 return 0;
376 alSourcef( Source, AL_PITCH, 1.0f );
377 alSourcefv( Source, AL_VELOCITY, SourceVel );
378 alSourcei( Source, AL_LOOPING, 0 );
379 alSourcef( Source, AL_REFERENCE_DISTANCE, REFERENCE_DISTANCE );
380 core->GetDictionary()->Lookup( "Volume SFX", volume );
381 alSourcef( Source, AL_GAIN, 0.01f * volume );
382 alSourcei( Source, AL_SOURCE_RELATIVE, flags & GEM_SND_RELATIVE );
383 alSourcefv( Source, AL_POSITION, SourcePos );
384 assert(!streams[stream].delete_buffers);
385 alSourcei( Source, AL_BUFFER, Buffer );
387 if (checkALError("Unable to set sound parameters", "ERROR")) {
388 return 0;
391 streams[stream].Buffer = Buffer;
392 streams[stream].Source = Source;
393 streams[stream].free = false;
394 alSourcePlay( Source );
396 if (checkALError("Unable to play sound", "ERROR")) {
397 return 0;
400 return time_length;
403 bool OpenALAudioDriver::IsSpeaking()
405 speech.ClearIfStopped();
406 return !speech.free;
409 void OpenALAudioDriver::UpdateVolume(unsigned int flags)
411 ieDword volume;
413 if (flags & GEM_SND_VOL_MUSIC) {
414 SDL_mutexP( musicMutex );
415 core->GetDictionary()->Lookup("Volume Music", volume);
416 if (alIsSource(MusicSource))
417 alSourcef(MusicSource, AL_GAIN, volume * 0.01f);
418 SDL_mutexV(musicMutex);
421 if (flags & GEM_SND_VOL_AMBIENTS) {
422 core->GetDictionary()->Lookup("Volume Ambients", volume);
423 ((AmbientMgrAL*) ambim)->UpdateVolume(volume);
427 bool OpenALAudioDriver::CanPlay()
429 return true;
432 void OpenALAudioDriver::ResetMusics()
434 MusicPlaying = false;
435 SDL_mutexP( musicMutex );
436 if (alIsSource(MusicSource)) {
437 alSourceStop(MusicSource);
438 checkALError("Unable to stop music source", "WARNING");
439 alDeleteSources(1, &MusicSource );
440 checkALError("Unable to delete music source", "WARNING");
441 MusicSource = 0;
442 for (int i=0; i<MUSICBUFFERS; i++) {
443 if (alIsBuffer(MusicBuffer[i])) {
444 alDeleteBuffers(1, MusicBuffer+i);
445 checkALError("Unable to delete music buffer", "WARNING");
449 SDL_mutexV( musicMutex );
452 bool OpenALAudioDriver::Play()
454 if (!MusicReader) return false;
456 SDL_mutexP( musicMutex );
457 if (!MusicPlaying)
458 MusicPlaying = true;
459 SDL_mutexV( musicMutex );
461 return true;
464 bool OpenALAudioDriver::Stop()
466 SDL_mutexP( musicMutex );
467 if (!alIsSource( MusicSource )) {
468 SDL_mutexV( musicMutex );
469 return false;
471 alSourceStop( MusicSource );
472 checkALError("Unable to stop music source", "WARNING");
473 MusicPlaying = false;
474 alDeleteSources( 1, &MusicSource );
475 checkALError("Unable to delete music source", "WARNING");
476 MusicSource = 0;
477 SDL_mutexV( musicMutex );
478 return true;
481 int OpenALAudioDriver::StreamFile(const char* filename)
483 char path[_MAX_PATH];
485 strcpy( path, core->GamePath );
486 strcpy( path, filename );
487 FileStream* str = new FileStream();
488 if (!str->Open( path, true )) {
489 delete str;
490 printMessage("OpenAL", "",WHITE);
491 printf( "Cannot find %s", path );
492 printStatus("NOT FOUND", YELLOW );
493 return -1;
495 StackLock l(musicMutex, "musicMutex in CreateStream()");
497 // Free old MusicReader
498 core->FreeInterface(MusicReader);
499 MusicReader = NULL;
501 if (MusicBuffer[0] == 0) {
502 alGenBuffers( MUSICBUFFERS, MusicBuffer );
503 if (checkALError("Unable to create music buffers", "ERROR")) {
504 return -1;
508 MusicReader = (SoundMgr*) core->GetInterface( IE_WAV_CLASS_ID );
509 if (!MusicReader->Open(str, true)) {
510 delete str;
511 core->FreeInterface(MusicReader);
512 MusicReader = NULL;
513 MusicPlaying = false;
514 printMessage("OpenAL", "",WHITE);
515 printf( "Cannot open %s", path );
516 printStatus("ERROR", YELLOW );
519 if (MusicSource == 0) {
520 alGenSources( 1, &MusicSource );
521 if (checkALError("Unable to create music source", "ERROR")) {
522 return -1;
525 ALfloat SourcePos[] = {
526 0.0f, 0.0f, 0.0f
528 ALfloat SourceVel[] = {
529 0.0f, 0.0f, 0.0f
532 ieDword volume;
533 core->GetDictionary()->Lookup( "Volume Music", volume );
534 alSourcef( MusicSource, AL_PITCH, 1.0f );
535 alSourcef( MusicSource, AL_GAIN, 0.01f * volume );
536 alSourcei( MusicSource, AL_SOURCE_RELATIVE, 1 );
537 alSourcefv( MusicSource, AL_POSITION, SourcePos );
538 alSourcefv( MusicSource, AL_VELOCITY, SourceVel );
539 alSourcei( MusicSource, AL_LOOPING, 0 );
540 checkALError("Unable to set music parameters", "WARNING");
543 return 0;
546 void OpenALAudioDriver::UpdateListenerPos(int XPos, int YPos )
548 alListener3f( AL_POSITION, (float) XPos, (float) YPos, 0.0f );
551 void OpenALAudioDriver::GetListenerPos(int &XPos, int &YPos )
553 ALfloat listen[3];
554 alGetListenerfv( AL_POSITION, listen );
555 if (checkALError("Unable to get listener pos", "ERROR")) return;
556 XPos = (int) listen[0];
557 YPos = (int) listen[1];
560 bool OpenALAudioDriver::ReleaseStream(int stream, bool HardStop)
562 if (streams[stream].free || !streams[stream].locked)
563 return false;
564 streams[stream].locked = false;
565 if (!HardStop) {
566 // it's now unlocked, so it will automatically be reclaimed when needed
567 return true;
570 ALuint Source = streams[stream].Source;
571 alSourceStop(Source);
572 checkALError("Unable to stop source", "WARNING");
573 streams[stream].ClearIfStopped();
575 return true;
578 //This one is used for movies and ambients.
579 int OpenALAudioDriver::SetupNewStream( ieWord x, ieWord y, ieWord z,
580 ieWord gain, bool point, bool Ambient )
582 // Find a free (or finished) stream for this sound
583 int stream = -1;
584 for (int i = 0; i < num_streams; i++) {
585 streams[i].ClearIfStopped();
586 if (streams[i].free) {
587 stream = i;
588 break;
591 if (stream == -1) return -1;
593 ALuint source;
594 alGenSources(1, &source);
595 if (checkALError("Unable to create new source", "ERROR")) {
596 return -1;
599 ALfloat position[] = { (float) x, (float) y, (float) z };
600 alSourcef( source, AL_PITCH, 1.0f );
601 alSourcefv( source, AL_POSITION, position );
602 alSourcef( source, AL_GAIN, 0.01f * gain );
603 alSourcei( source, AL_REFERENCE_DISTANCE, REFERENCE_DISTANCE );
604 alSourcei( source, AL_ROLLOFF_FACTOR, point ? 1 : 0 );
605 alSourcei( source, AL_LOOPING, 0 );
606 checkALError("Unable to set stream parameters", "WARNING");
608 streams[stream].Buffer = 0;
609 streams[stream].Source = source;
610 streams[stream].free = false;
611 streams[stream].ambient = Ambient;
612 streams[stream].locked = true;
614 return stream;
617 int OpenALAudioDriver::QueueAmbient(int stream, const char* sound)
619 if (streams[stream].free || !streams[stream].ambient)
620 return -1;
622 ALuint source = streams[stream].Source;
624 // first dequeue any processed buffers
625 streams[stream].ClearProcessedBuffers();
627 if (sound == 0)
628 return 0;
630 unsigned int time_length;
631 ALuint Buffer = loadSound(sound, time_length);
632 if (0 == Buffer) {
633 return -1;
636 assert(!streams[stream].delete_buffers);
638 alSourceQueueBuffers(source, 1, &Buffer);
639 if (checkALError("Unable to queue ambient buffer","ERROR")) {
640 return -1;
643 // play
644 ALint state;
645 alGetSourcei( source, AL_SOURCE_STATE, &state );
646 if (!checkALError("Unable to query ambient source state", "ERROR") &&
647 state != AL_PLAYING)
648 { // play on playing source would rewind it
649 alSourcePlay( source );
650 if (checkALError("Unable to play ambient source", "ERROR"))
651 return -1;
654 return time_length;
657 void OpenALAudioDriver::SetAmbientStreamVolume(int stream, int volume)
659 if (streams[stream].free || !streams[stream].ambient)
660 return;
662 ALuint source = streams[stream].Source;
663 alSourcef( source, AL_GAIN, 0.01f * volume );
664 checkALError("Unable to set ambient volume", "WARNING");
667 bool OpenALAudioDriver::evictBuffer()
669 // Note: this function assumes the caller holds bufferMutex
671 // Room for optimization: this is O(n^2) in the number of buffers
672 // at the tail that are used. It can be O(n) if LRUCache supports it.
674 unsigned int n = 0;
675 void* p;
676 const char* k;
677 bool res;
679 while ((res = buffercache.getLRU(n, k, p)) == true) {
680 CacheEntry* e = (CacheEntry*)p;
681 alDeleteBuffers(1, &e->Buffer);
682 if (alGetError() == AL_NO_ERROR) {
683 // Buffer was unused. An error would have indicated
684 // the buffer was still attached to a source.
686 delete e;
687 buffercache.Remove(k);
689 //printf("Removed buffer %s from ACMImp cache\n", k);
690 break;
692 ++n;
695 return res;
698 void OpenALAudioDriver::clearBufferCache(bool force)
700 // Room for optimization: any method of iterating over the buffers
701 // would suffice. It doesn't have to be in LRU-order.
702 void* p;
703 const char* k;
704 int n = 0;
705 while (buffercache.getLRU(n, k, p)) {
706 CacheEntry* e = (CacheEntry*)p;
707 alDeleteBuffers(1, &e->Buffer);
708 if (force || alGetError() == AL_NO_ERROR) {
709 delete e;
710 buffercache.Remove(k);
711 } else
712 ++n;
716 ALenum OpenALAudioDriver::GetFormatEnum(int channels, int bits)
718 switch (channels) {
719 case 1:
720 if (bits == 8)
721 return AL_FORMAT_MONO8;
722 else
723 return AL_FORMAT_MONO16;
724 break;
726 case 2:
727 if (bits == 8)
728 return AL_FORMAT_STEREO8;
729 else
730 return AL_FORMAT_STEREO16;
731 break;
733 return AL_FORMAT_MONO8;
736 int OpenALAudioDriver::MusicManager(void* arg)
738 OpenALAudioDriver* driver = (OpenALAudioDriver*) arg;
739 ALuint buffersreturned = 0;
740 ALboolean bFinished = AL_FALSE;
741 while (driver->stayAlive) {
742 SDL_Delay(30);
743 StackLock l(driver->musicMutex, "musicMutex in PlayListManager()");
744 if (driver->MusicPlaying) {
745 ALint state;
746 alGetSourcei( driver->MusicSource, AL_SOURCE_STATE, &state );
747 if (checkALError("Unable to query music source state", "ERROR")) {
748 driver->MusicPlaying = false;
749 return -1;
751 switch (state) {
752 default:
753 printMessage("OpenAL", "WARNING: Unhandled Music state", WHITE );
754 printStatus("ERROR", YELLOW);
755 driver->MusicPlaying = false;
756 return -1;
757 case AL_INITIAL:
759 printMessage("OPENAL", "Music in INITIAL State. AutoStarting\n", WHITE );
760 for (int i = 0; i < MUSICBUFFERS; i++) {
761 driver->MusicReader->read_samples( ( short* ) driver->music_memory, ACM_BUFFERSIZE >> 1 );
762 alBufferData( driver->MusicBuffer[i], AL_FORMAT_STEREO16,
763 driver->music_memory, ACM_BUFFERSIZE,
764 driver->MusicReader->get_samplerate() );
766 alSourceQueueBuffers( driver->MusicSource, MUSICBUFFERS, driver->MusicBuffer );
767 if (alIsSource( driver->MusicSource )) {
768 alSourcePlay( driver->MusicSource );
769 checkALError("Error playing music source", "ERROR");
771 bFinished = AL_FALSE;
773 break;
774 case AL_STOPPED:
775 printMessage("OpenAL", "WARNING: Buffer Underrun. AutoRestarting Stream Playback\n", WHITE );
776 if (alIsSource( driver->MusicSource )) {
777 alSourcePlay( driver->MusicSource );
778 checkALError("Error playing music source", "ERROR");
780 break;
781 case AL_PLAYING:
782 break;
784 ALint processed;
785 alGetSourcei( driver->MusicSource, AL_BUFFERS_PROCESSED, &processed );
786 if (checkALError("Unable to query music source state", "ERROR")) {
787 driver->MusicPlaying = false;
788 return -1;
790 if (processed > 0) {
791 buffersreturned += processed;
792 while (processed) {
793 ALuint BufferID;
794 alSourceUnqueueBuffers( driver->MusicSource, 1, &BufferID );
795 if (checkALError("Unable to unqueue music buffers", "ERROR")) {
796 driver->MusicPlaying = false;
797 return -1;
799 if (bFinished == AL_FALSE) {
800 int size = ACM_BUFFERSIZE;
801 int cnt = driver->MusicReader->read_samples( ( short* ) driver->music_memory, ACM_BUFFERSIZE >> 1 );
802 size -= ( cnt * 2 );
803 if (size != 0)
804 bFinished = AL_TRUE;
805 if (bFinished) {
806 printMessage("OpenAL", "Playing Next Music\n", WHITE );
807 core->GetMusicMgr()->PlayNext();
808 if (driver->MusicPlaying) {
809 printMessage( "OpenAL", "Queuing New Music\n", WHITE );
810 driver->MusicReader->read_samples( ( short* ) ( driver->music_memory + ( cnt*2 ) ), size >> 1 );
811 bFinished = AL_FALSE;
812 } else {
813 printMessage( "OpenAL", "No Other Music to play\n", WHITE );
814 memset( driver->music_memory + ( cnt * 2 ), 0, size );
815 driver->MusicPlaying = false;
816 break;
819 alBufferData( BufferID, AL_FORMAT_STEREO16, driver->music_memory, ACM_BUFFERSIZE, driver->MusicReader->get_samplerate() );
820 if (checkALError("Unable to buffer music data", "ERROR")) {
821 driver->MusicPlaying = false;
822 return -1;
824 alSourceQueueBuffers( driver->MusicSource, 1, &BufferID );
825 if (checkALError("Unable to queue music buffers", "ERROR")) {
826 driver->MusicPlaying = false;
827 return -1;
829 processed--;
835 return 0;
838 //This one is used for movies, might be useful for others ?
839 void OpenALAudioDriver::QueueBuffer(int stream, unsigned short bits,
840 int channels, short* memory,
841 int size, int samplerate)
843 ALuint Buffer;
845 alGenBuffers(1, &Buffer);
846 if (checkALError("Unable to create buffer", "ERROR")) {
847 return;
850 alBufferData(Buffer, GetFormatEnum(channels, bits), memory, size, samplerate);
851 if (checkALError("Unable to buffer data", "ERROR")) {
852 return;
855 streams[stream].delete_buffers = true;
856 streams[stream].ClearProcessedBuffers();
858 alSourceQueueBuffers(streams[stream].Source, 1, &Buffer );
859 if (checkALError("Unable to queue buffer", "ERROR")) {
860 return;
863 ALenum state;
864 alGetSourcei(streams[stream].Source, AL_SOURCE_STATE, &state);
865 if (checkALError("Unable to query source state", "ERROR")) {
866 return;
869 if (state != AL_PLAYING ) {
870 alSourcePlay(streams[stream].Source);
871 checkALError("Unable to play source", "ERROR");
874 return;
877 #include "plugindef.h"
879 GEMRB_PLUGIN(0x27DD67E0, "OpenAL Audio Driver")
880 PLUGIN_CLASS(IE_AUDIO_CLASS_ID, OpenALAudioDriver)
881 END_PLUGIN()