copy openal dlls
[blender.git] / intern / SoundSystem / openal / SND_OpenALDevice.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * SND_OpenALDevice derived from SND_IAudioDevice
29  */
30
31 #ifdef WIN32
32 #pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
33 #endif //WIN32
34
35 #include "SND_OpenALDevice.h"
36 #ifndef __APPLE__
37 #include "SND_SDLCDDevice.h"
38 #endif
39 #include "SoundDefines.h"
40
41 #include "SND_Utils.h"
42
43 #ifdef APPLE_FRAMEWORK_FIX
44 #include <al.h>
45 #include <alc.h>
46 #else
47 #include <AL/al.h>
48 #include <AL/alc.h>
49 #endif
50
51 #include <stdio.h>
52 #include <stdlib.h>
53 #if defined(WIN32)
54 #include <io.h>
55 #else
56 #include <unistd.h>
57 #endif
58 #include <fcntl.h>
59
60 #include <signal.h>
61
62 /*************************** ALUT replacement *****************************/
63
64 /* instead of relying on alut, we just implement our own
65  * WAV loading functions, hopefully more reliable */
66
67 #include <stdlib.h>
68
69 typedef struct                                  /* WAV File-header */
70 {
71   ALubyte  Id[4];
72   ALsizei  Size;
73   ALubyte  Type[4];
74 } WAVFileHdr_Struct;
75
76 typedef struct                                  /* WAV Fmt-header */
77 {
78   ALushort Format;                              
79   ALushort Channels;
80   ALuint   SamplesPerSec;
81   ALuint   BytesPerSec;
82   ALushort BlockAlign;
83   ALushort BitsPerSample;
84 } WAVFmtHdr_Struct;
85
86 typedef struct                                                                  /* WAV FmtEx-header */
87 {
88   ALushort Size;
89   ALushort SamplesPerBlock;
90 } WAVFmtExHdr_Struct;
91
92 typedef struct                                  /* WAV Smpl-header */
93 {
94   ALuint   Manufacturer;
95   ALuint   Product;
96   ALuint   SamplePeriod;                          
97   ALuint   Note;                                  
98   ALuint   FineTune;                              
99   ALuint   SMPTEFormat;
100   ALuint   SMPTEOffest;
101   ALuint   Loops;
102   ALuint   SamplerData;
103   struct
104   {
105     ALuint Identifier;
106     ALuint Type;
107     ALuint Start;
108     ALuint End;
109     ALuint Fraction;
110     ALuint Count;
111   }      Loop[1];
112 } WAVSmplHdr_Struct;
113
114 typedef struct                                  /* WAV Chunk-header */
115 {
116   ALubyte  Id[4];
117   ALuint   Size;
118 } WAVChunkHdr_Struct;
119
120 static void *SND_loadFileIntoMemory(const char *filename, int *len_r)
121 {
122         FILE *fp= fopen(filename, "rb");
123         void *data;
124
125         if (!fp) {
126                 *len_r= -1;
127                 return NULL;
128         }
129
130         fseek(fp, 0L, SEEK_END);
131         *len_r= ftell(fp);
132         fseek(fp, 0L, SEEK_SET);
133
134         data= malloc(*len_r);
135         if (!data) {
136                 *len_r= -1;
137                 return NULL;
138         }
139
140         if (fread(data, *len_r, 1, fp)!=1) {
141                 *len_r= -1;
142                 free(data);
143                 return NULL;
144         }
145
146         return data;
147 }
148
149 #define TEST_SWITCH_INT(a) if(big_endian) { \
150     char s_i, *p_i; \
151     p_i= (char *)&(a); \
152     s_i=p_i[0]; p_i[0]=p_i[3]; p_i[3]=s_i; \
153     s_i=p_i[1]; p_i[1]=p_i[2]; p_i[2]=s_i; }
154
155 #define TEST_SWITCH_SHORT(a) if(big_endian) { \
156     char s_i, *p_i; \
157     p_i= (char *)&(a); \
158     s_i=p_i[0]; p_i[0]=p_i[1]; p_i[1]=s_i; }
159
160 static int stream_read(void *out, ALbyte **stream, ALsizei size, ALsizei *memsize)
161 {
162         if(size <= *memsize) {
163                 memcpy(out, *stream, size);
164                 return 1;
165         }
166         else {
167                 memset(out, 0, size);
168                 return 0;
169         }
170 }
171
172 static int stream_skip(ALbyte **stream, ALsizei size, ALsizei *memsize)
173 {
174         if(size <= *memsize) {
175                 *stream += size;
176                 *memsize -= size;
177                 return 1;
178         }
179         else
180                 return 0;
181 }
182
183 ALvoid SND_alutLoadWAVMemory(ALbyte *memory,ALsizei memsize,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop)
184 {
185         WAVChunkHdr_Struct ChunkHdr;
186         WAVFmtExHdr_Struct FmtExHdr;
187         WAVFileHdr_Struct FileHdr;
188         WAVSmplHdr_Struct SmplHdr;
189         WAVFmtHdr_Struct FmtHdr;
190         ALbyte *Stream= memory;
191         int test_endian= 1;
192         int big_endian= !((char*)&test_endian)[0];
193         
194         *format=AL_FORMAT_MONO16;
195         *data=NULL;
196         *size=0;
197         *freq=22050;
198         *loop=AL_FALSE;
199
200         if(!Stream)
201                 return;
202  
203         stream_read(&FileHdr,&Stream,sizeof(WAVFileHdr_Struct),&memsize);
204         stream_skip(&Stream,sizeof(WAVFileHdr_Struct),&memsize);
205
206         TEST_SWITCH_INT(FileHdr.Size);
207         FileHdr.Size=((FileHdr.Size+1)&~1)-4;
208
209         while((FileHdr.Size!=0) && stream_read(&ChunkHdr,&Stream,sizeof(WAVChunkHdr_Struct),&memsize))
210         {
211                 TEST_SWITCH_INT(ChunkHdr.Size);
212                 stream_skip(&Stream,sizeof(WAVChunkHdr_Struct),&memsize);
213
214                 if (!memcmp(ChunkHdr.Id,"fmt ",4))
215                 {
216                         stream_read(&FmtHdr,&Stream,sizeof(WAVFmtHdr_Struct),&memsize);
217
218                         TEST_SWITCH_SHORT(FmtHdr.Format);
219                         TEST_SWITCH_SHORT(FmtHdr.Channels);
220                         TEST_SWITCH_INT(FmtHdr.SamplesPerSec);
221                         TEST_SWITCH_INT(FmtHdr.BytesPerSec);
222                         TEST_SWITCH_SHORT(FmtHdr.BlockAlign);
223                         TEST_SWITCH_SHORT(FmtHdr.BitsPerSample);
224
225                         if (FmtHdr.Format==0x0001)
226                         {
227                                 *format=(FmtHdr.Channels==1?
228                                                 (FmtHdr.BitsPerSample==8?AL_FORMAT_MONO8:AL_FORMAT_MONO16):
229                                                 (FmtHdr.BitsPerSample==8?AL_FORMAT_STEREO8:AL_FORMAT_STEREO16));
230                                 *freq=FmtHdr.SamplesPerSec;
231                         } 
232                         else
233                         {
234                                 stream_read(&FmtExHdr,&Stream,sizeof(WAVFmtExHdr_Struct),&memsize);
235                                 TEST_SWITCH_SHORT(FmtExHdr.Size);
236                                 TEST_SWITCH_SHORT(FmtExHdr.SamplesPerBlock);
237                         }
238                 }
239                 else if (!memcmp(ChunkHdr.Id,"data",4))
240                 {
241                         if (FmtHdr.Format==0x0001)
242                         {
243                                 if((ALsizei)ChunkHdr.Size <= memsize)
244                                 {
245                                         *size=ChunkHdr.Size;
246                                         *data=malloc(ChunkHdr.Size+31);
247
248                                         if (*data) {
249                                                 stream_read(*data,&Stream,ChunkHdr.Size,&memsize);
250                                                 memset(((char *)*data)+ChunkHdr.Size,0,31);
251
252                                                 if(FmtHdr.BitsPerSample == 16 && big_endian) {
253                                                         int a, len= *size/2;
254                                                         short *samples= (short*)*data;
255
256                                                         for(a=0; a<len; a++) {
257                                                                 TEST_SWITCH_SHORT(samples[a])
258                                                         }
259                                                 }
260                                         }
261                                 }
262                         }
263                         else if (FmtHdr.Format==0x0011)
264                         {
265                                 //IMA ADPCM
266                         }
267                         else if (FmtHdr.Format==0x0055)
268                         {
269                                 //MP3 WAVE
270                         }
271                 }
272                 else if (!memcmp(ChunkHdr.Id,"smpl",4))
273                 {
274                         stream_read(&SmplHdr,&Stream,sizeof(WAVSmplHdr_Struct),&memsize);
275
276                         TEST_SWITCH_INT(SmplHdr.Manufacturer);
277                         TEST_SWITCH_INT(SmplHdr.Product);
278                         TEST_SWITCH_INT(SmplHdr.SamplePeriod);
279                         TEST_SWITCH_INT(SmplHdr.Note);
280                         TEST_SWITCH_INT(SmplHdr.FineTune);
281                         TEST_SWITCH_INT(SmplHdr.SMPTEFormat);
282                         TEST_SWITCH_INT(SmplHdr.SMPTEOffest);
283                         TEST_SWITCH_INT(SmplHdr.Loops);
284                         TEST_SWITCH_INT(SmplHdr.SamplerData);
285
286                         *loop = (SmplHdr.Loops ? AL_TRUE : AL_FALSE);
287                 }
288
289                 if(!stream_skip(&Stream, ChunkHdr.Size + (ChunkHdr.Size&1), &memsize))
290                         break;
291
292                 FileHdr.Size-=(((ChunkHdr.Size+1)&~1)+8);
293         }
294 }
295
296 ALvoid SND_alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq)
297 {
298         if (data)
299                 free(data);
300 }
301
302 /************************ Device Implementation ****************************/
303
304 SND_OpenALDevice::SND_OpenALDevice()
305         : SND_AudioDevice(),
306           m_context(NULL),
307           m_device(NULL)
308 {
309     /* Removed the functionality for checking if noaudio was provided on */
310     /* the commandline. */
311         m_audio = true;
312         m_context = NULL;
313         m_buffersinitialized = false;
314         m_sourcesinitialized = false;
315
316         // let's check if we can get openal to initialize...
317         if (m_audio)
318         {
319                 m_audio = false;
320
321                 ALCdevice *dev = alcOpenDevice(NULL);
322                 if (dev) {
323                         m_context = alcCreateContext(dev, NULL);
324
325                         if (m_context) {
326 #ifdef AL_VERSION_1_1
327                         alcMakeContextCurrent((ALCcontext*)m_context);
328 #else
329                         alcMakeContextCurrent(m_context);
330 #endif
331                         m_audio = true;
332                                 m_device = dev;
333 #ifdef __linux__
334                                 /*
335                                 *   SIGHUP Hack:
336                                 *
337                                 *   On Linux, alcDestroyContext generates a SIGHUP (Hangup) when killing the OpenAL
338                                 *   mixer thread, which kills Blender.
339                                 *  
340                                 *   So we set the signal to ignore....
341                                 *
342                                 *   TODO: check if this applies to other platforms.
343                                 *
344                                 */
345                                 signal(SIGHUP, SIG_IGN);
346 #endif
347                         }
348                 }
349
350         }
351
352         // then try to generate some buffers
353         if (m_audio)
354         {
355                 // let openal generate its buffers
356                 alGenBuffers(NUM_BUFFERS, m_buffers);
357                 m_buffersinitialized = true;
358                 
359                 for (int i = 0; i < NUM_BUFFERS; i++)
360                 {
361                         if (!alIsBuffer(m_buffers[i]))
362                         {
363                                 //printf("\n\n  WARNING: OpenAL returned with an error. Continuing without audio.\n\n");
364                                 m_audio = false;
365                                 break;
366                         }
367                 }
368         }
369
370         // next: the sources
371         if (m_audio)
372         {
373 #ifdef __APPLE__
374                 ALenum alc_error = ALC_NO_ERROR;        // openal_2.12
375 #elif defined(_WIN32)
376                 // alcGetError has no arguments on windows
377                 ALenum alc_error = alcGetError();       // openal_2.14+
378 #else
379                 ALenum alc_error = alcGetError(NULL);   // openal_2.14+
380 #endif
381
382                 // let openal generate its sources
383                 if (alc_error == ALC_NO_ERROR)
384                 {
385                         int i;
386
387                         for (i=0;i<NUM_SOURCES;i++)
388                                 m_sources[i] = 0;
389                         alGenSources(NUM_SOURCES, m_sources);
390                         m_sourcesinitialized = true;
391                 }
392         }
393
394         // let's get us a wavecache
395         if (m_audio)
396         {
397                 m_wavecache = new SND_WaveCache();
398         }
399 #ifndef __APPLE__       
400         m_cdrom = new SND_SDLCDDevice();
401 #endif
402 }
403
404 void SND_OpenALDevice::UseCD(void) const
405 {
406         // we use SDL for CD, so we create the system
407         SND_CDObject::CreateSystem();
408
409 }
410
411 void SND_OpenALDevice::MakeCurrent() const
412 {
413 #ifdef WIN32
414         alcMakeContextCurrent(m_context);
415 #endif
416 }
417
418
419
420 SND_OpenALDevice::~SND_OpenALDevice()
421 {
422         MakeCurrent();
423         
424         if (m_sourcesinitialized)
425         {
426                 for (int i = 0; i < NUM_SOURCES; i++)
427                         alSourceStop(m_sources[i]);
428                 
429                 alDeleteSources(NUM_SOURCES, m_sources);
430                 m_sourcesinitialized = false;
431         }
432         
433         if (m_buffersinitialized)
434         {
435                 alDeleteBuffers(NUM_BUFFERS, m_buffers);
436                 m_buffersinitialized = false;
437         }
438         
439         if (m_context) {
440                 MakeCurrent();
441 #ifdef AL_VERSION_1_1
442                 alcDestroyContext((ALCcontext*)m_context);
443 #else
444                 alcDestroyContext(m_context);
445 #endif
446                 m_context = NULL;
447         }
448         
449 #ifdef __linux__
450         // restore the signal state above.
451         signal(SIGHUP, SIG_DFL);
452 #endif  
453         // let's see if we used the cd. if not, just leave it alone
454         SND_CDObject* pCD = SND_CDObject::Instance();
455         
456         if (pCD)
457         {
458                 this->StopCD();
459                 SND_CDObject::DisposeSystem();
460         }
461 #ifndef __APPLE__
462         if (m_cdrom)
463                 delete m_cdrom;
464 #endif
465         if (m_device)
466                 alcCloseDevice((ALCdevice*) m_device);
467 }
468
469
470 SND_WaveSlot* SND_OpenALDevice::LoadSample(const STR_String& name,
471                                                                                   void* memlocation,
472                                                                                   int size)
473 {
474         SND_WaveSlot* waveslot = NULL;
475         STR_String samplename = name;
476         
477         if (m_audio)
478         {
479                 /* create the waveslot */
480                 waveslot = m_wavecache->GetWaveSlot(samplename);
481
482                 /* do we support this sample? */
483                 if (SND_IsSampleValid(name, memlocation))
484                 {
485                         if (waveslot)
486                         {
487                                 bool freemem = false;
488                                 int buffer = waveslot->GetBuffer();
489                                 void* data = NULL;
490                                 char loop = 'a';
491                                 int sampleformat, bitrate, numberofchannels;
492                                 ALenum al_error = alGetError();
493                                 ALsizei samplerate, numberofsamples;  // openal_2.14+
494                                 
495                                 /* Give them some safe defaults just incase */
496                                 bitrate = numberofchannels = 0;
497
498                                 if (!(size && memlocation)) {
499                                         memlocation = SND_loadFileIntoMemory(samplename.Ptr(), &size);
500                                         freemem = true;
501                                 }
502
503                                 /* load the sample from memory? */
504                                 if (size && memlocation)
505                                 {
506                                         waveslot->SetFileSize(size);
507                                         
508                                         /* what was (our) buffer? */
509                                         int buffer = waveslot->GetBuffer();
510                                         
511                                         /* get some info out of the sample */
512                                         SND_GetSampleInfo((signed char*)memlocation, waveslot);
513                                         numberofchannels = SND_GetNumberOfChannels(memlocation);
514                                         bitrate = SND_GetBitRate(memlocation);
515                                         
516                                         /* load the sample into openal */
517                                         SND_alutLoadWAVMemory((ALbyte*)memlocation, size, &sampleformat, &data, &numberofsamples, &samplerate, &loop);
518                                         /* put it in the buffer */
519                                         alBufferData(m_buffers[buffer], sampleformat, data, numberofsamples, samplerate);
520                                 }
521                                 
522                                 if(freemem)
523                                                 free(memlocation);
524                                                                 
525                                 /* fill the waveslot with info */
526                                 al_error = alGetError();
527                                 if (al_error == AL_NO_ERROR && m_buffers[buffer])
528                                 {
529                                         waveslot->SetData(data);
530                                         waveslot->SetSampleFormat(sampleformat);
531                                         waveslot->SetNumberOfChannels(numberofchannels);
532                                         waveslot->SetSampleRate(samplerate);
533                                         waveslot->SetBitRate(bitrate);
534                                         waveslot->SetNumberOfSamples(numberofsamples);
535                                         
536                                         /* if the loading succeeded, mark the waveslot */
537                                         waveslot->SetLoaded(true);
538                                 }
539                                 else
540                                 {
541                                         /* or when it failed, free the waveslot */
542                                         m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer());
543                                         waveslot = NULL;
544                                 }
545                                 
546                                 /* and free the original stuff (copy was made in openal) */
547                                 SND_alutUnloadWAV(sampleformat, data, numberofsamples, samplerate);
548                         }
549                 }
550                 else
551                 {
552                         /* sample not supported, remove waveslot */
553                         m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer());
554                         waveslot = NULL;
555                 }
556         }
557         return waveslot;
558 }
559
560
561
562 // listener's and general stuff //////////////////////////////////////////////////////
563
564
565
566 /* sets the global dopplervelocity */
567 void SND_OpenALDevice::SetDopplerVelocity(MT_Scalar dopplervelocity) const
568 {
569         alDopplerVelocity ((float)dopplervelocity);
570 }
571
572
573
574 /* sets the global dopplerfactor */
575 void SND_OpenALDevice::SetDopplerFactor(MT_Scalar dopplerfactor) const
576 {
577         alDopplerFactor ((float)dopplerfactor);
578 }
579
580
581
582 /* sets the global rolloff factor */
583 void SND_OpenALDevice::SetListenerRollOffFactor(MT_Scalar rollofffactor) const
584 {
585         // not implemented in openal
586 }
587
588
589
590 void SND_OpenALDevice::NextFrame() const
591 {
592         // CD
593 #ifndef __APPLE__
594         m_cdrom->NextFrame();
595 #endif
596         // not needed by openal
597 }
598
599
600
601 // set the gain for the listener
602 void SND_OpenALDevice::SetListenerGain(float gain) const
603 {
604         alListenerf (AL_GAIN, gain);
605 }
606
607
608
609 void SND_OpenALDevice::InitListener()
610 {
611         // initialize the listener with these values that won't change
612         // (as long as we can have only one listener)
613         // now we can superimpose all listeners on each other (for they
614         // have the same settings)
615         float lispos[3] = {0,0,0};
616         float lisvel[3] = {0,0,0};
617 #ifdef WIN32
618         float lisori[6] = {0,1,0,0,0,1};
619 #else
620         float lisori[6] = {0,0,1,0,-1,0};
621 #endif
622
623         alListenerfv(AL_POSITION, lispos);
624         alListenerfv(AL_VELOCITY, lisvel);
625         alListenerfv(AL_ORIENTATION, lisori);
626 }
627
628
629
630 // source playstate stuff ////////////////////////////////////////////////////////////
631
632
633
634 /* sets the buffer */
635 void SND_OpenALDevice::SetObjectBuffer(int id, unsigned int buffer)
636 {
637         alSourcei (m_sources[id], AL_BUFFER, m_buffers[buffer]);
638 }
639
640
641
642 // check if the sound's still playing
643 int SND_OpenALDevice::GetPlayState(int id)
644 {
645     int alstate = 0;
646         int result = 0;
647
648 #ifdef __APPLE__
649         alGetSourcei(m_sources[id], AL_SOURCE_STATE, &alstate);
650 #else
651         alGetSourceiv(m_sources[id], AL_SOURCE_STATE, &alstate);
652 #endif
653         
654         switch(alstate)
655         {
656         case AL_INITIAL:
657                 {
658                         result = SND_INITIAL;
659                         break;
660                 }
661         case AL_PLAYING:
662                 {
663                         result = SND_PLAYING;
664                         break;
665                 }
666         case AL_PAUSED:
667                 {
668                         result = SND_PAUSED;
669                         break;
670                 }
671         case AL_STOPPED:
672                 {
673                         result = SND_STOPPED;
674                         break;
675                 }
676         default:
677                 result = SND_UNKNOWN;
678         }
679
680     return result;
681 }
682
683
684
685 // make the source play
686 void SND_OpenALDevice::PlayObject(int id)
687 {
688         alSourcePlay(m_sources[id]);
689 }
690
691
692
693 // make the source stop
694 void SND_OpenALDevice::StopObject(int id) const
695 {
696         float obpos[3] = {0,0,0};
697         float obvel[3] = {0,0,0};
698
699         alSourcefv(m_sources[id], AL_POSITION, obpos);
700         alSourcefv(m_sources[id], AL_VELOCITY, obvel);
701
702         alSourcef(m_sources[id], AL_GAIN, 1.0);
703         alSourcef(m_sources[id], AL_PITCH, 1.0);
704         alSourcei(m_sources[id], AL_LOOPING, AL_FALSE);
705         alSourceStop(m_sources[id]);
706 }
707
708
709
710 // stop all sources
711 void SND_OpenALDevice::StopAllObjects()
712 {
713         alSourceStopv(NUM_SOURCES, m_sources);
714 }
715
716
717
718 // pause the source
719 void SND_OpenALDevice::PauseObject(int id) const
720 {
721         alSourcePause(m_sources[id]);
722 }
723
724
725
726 // source properties stuff ////////////////////////////////////////////////////////////
727
728
729
730 // give openal the object's pitch
731 void SND_OpenALDevice::SetObjectPitch(int id, MT_Scalar pitch) const
732 {
733         alSourcef (m_sources[id], AL_PITCH, (float)pitch);
734 }
735
736
737
738 // give openal the object's gain
739 void SND_OpenALDevice::SetObjectGain(int id, MT_Scalar gain) const
740 {
741         alSourcef (m_sources[id], AL_GAIN, (float)gain);
742 }
743
744
745
746 // give openal the object's looping
747 void SND_OpenALDevice::SetObjectLoop(int id, unsigned int loopmode) const
748 {
749         if (loopmode == SND_LOOP_OFF)
750         {
751                 //printf("%d - ", id);
752                 alSourcei (m_sources[id], AL_LOOPING, AL_FALSE);
753         }
754         else
755                 alSourcei (m_sources[id], AL_LOOPING, AL_TRUE);
756 }
757
758 void SND_OpenALDevice::SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const
759 {
760
761
762 }
763
764
765 void SND_OpenALDevice::SetObjectMinGain(int id, MT_Scalar mingain) const
766 {
767         alSourcef (m_sources[id], AL_MIN_GAIN, (float)mingain);
768 }
769
770
771
772 void SND_OpenALDevice::SetObjectMaxGain(int id, MT_Scalar maxgain) const
773 {
774         alSourcef (m_sources[id], AL_MAX_GAIN, (float)maxgain);
775 }
776
777
778
779 void SND_OpenALDevice::SetObjectRollOffFactor(int id, MT_Scalar rollofffactor) const
780 {
781         alSourcef (m_sources[id], AL_ROLLOFF_FACTOR, (float)rollofffactor);
782 }
783
784
785
786 void SND_OpenALDevice::SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const
787 {
788         alSourcef (m_sources[id], AL_REFERENCE_DISTANCE, (float)referencedistance);
789 }
790
791
792
793 // give openal the object's position
794 void SND_OpenALDevice::ObjectIs2D(int id) const
795 {
796         float obpos[3] = {0,0,0};
797         float obvel[3] = {0,0,0};
798         
799         alSourcefv(m_sources[id], AL_POSITION, obpos);
800         alSourcefv(m_sources[id], AL_VELOCITY, obvel);
801 }
802
803
804
805 void SND_OpenALDevice::SetObjectTransform(int id,
806                                                                                   const MT_Vector3& position,
807                                                                                   const MT_Vector3& velocity,
808                                                                                   const MT_Matrix3x3& orientation,
809                                                                                   const MT_Vector3& lisposition,
810                                                                                   const MT_Scalar& rollofffactor) const 
811 {
812         float obpos[3];
813         float obvel[3];
814
815         obpos[0] = (float)position[0] * (float)rollofffactor;   //x (l/r)
816         obpos[1] = (float)position[1] * (float)rollofffactor;
817         obpos[2] = (float)position[2] * (float)rollofffactor;
818
819         alSourcefv(m_sources[id], AL_POSITION, obpos);
820
821         velocity.getValue(obvel);
822         alSourcefv(m_sources[id], AL_VELOCITY, obvel);
823 }
824
825 void SND_OpenALDevice::PlayCD(int track) const
826 {
827 #ifndef __APPLE__
828         m_cdrom->PlayCD(track);
829 #endif
830 }
831
832
833 void SND_OpenALDevice::PauseCD(bool pause) const
834 {
835 #ifndef __APPLE__
836         m_cdrom->PauseCD(pause);
837 #endif
838 }
839
840 void SND_OpenALDevice::StopCD() const
841 {
842 #ifndef __APPLE__
843         SND_CDObject* pCD = SND_CDObject::Instance();
844
845         if (pCD && pCD->GetUsed())
846         {
847                 m_cdrom->StopCD();
848         }
849 #endif
850 }
851
852 void SND_OpenALDevice::SetCDPlaymode(int playmode) const
853 {
854 #ifndef __APPLE__
855         m_cdrom->SetCDPlaymode(playmode);
856 #endif
857 }
858
859 void SND_OpenALDevice::SetCDGain(MT_Scalar gain) const
860 {
861 #ifndef __APPLE__
862         m_cdrom->SetCDGain(gain);
863 #endif
864 }