* merge r22237 (from soundsystem branch) to have b25 still compile against new openal...
[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 #else
376                 ALenum alc_error = alcGetError(NULL);   // openal_2.14+
377 #endif
378
379                 // let openal generate its sources
380                 if (alc_error == ALC_NO_ERROR)
381                 {
382                         int i;
383
384                         for (i=0;i<NUM_SOURCES;i++)
385                                 m_sources[i] = 0;
386                         alGenSources(NUM_SOURCES, m_sources);
387                         m_sourcesinitialized = true;
388                 }
389         }
390
391         // let's get us a wavecache
392         if (m_audio)
393         {
394                 m_wavecache = new SND_WaveCache();
395         }
396 #ifndef __APPLE__       
397         m_cdrom = new SND_SDLCDDevice();
398 #endif
399 }
400
401 void SND_OpenALDevice::UseCD(void) const
402 {
403         // we use SDL for CD, so we create the system
404         SND_CDObject::CreateSystem();
405
406 }
407
408 void SND_OpenALDevice::MakeCurrent() const
409 {
410 }
411
412
413
414 SND_OpenALDevice::~SND_OpenALDevice()
415 {
416         MakeCurrent();
417         
418         if (m_sourcesinitialized)
419         {
420                 for (int i = 0; i < NUM_SOURCES; i++)
421                         alSourceStop(m_sources[i]);
422                 
423                 alDeleteSources(NUM_SOURCES, m_sources);
424                 m_sourcesinitialized = false;
425         }
426         
427         if (m_buffersinitialized)
428         {
429                 alDeleteBuffers(NUM_BUFFERS, m_buffers);
430                 m_buffersinitialized = false;
431         }
432         
433         if (m_context) {
434                 MakeCurrent();
435 #ifdef AL_VERSION_1_1
436                 alcDestroyContext((ALCcontext*)m_context);
437 #else
438                 alcDestroyContext(m_context);
439 #endif
440                 m_context = NULL;
441         }
442         
443 #ifdef __linux__
444         // restore the signal state above.
445         signal(SIGHUP, SIG_DFL);
446 #endif  
447         // let's see if we used the cd. if not, just leave it alone
448         SND_CDObject* pCD = SND_CDObject::Instance();
449         
450         if (pCD)
451         {
452                 this->StopCD();
453                 SND_CDObject::DisposeSystem();
454         }
455 #ifndef __APPLE__
456         if (m_cdrom)
457                 delete m_cdrom;
458 #endif
459         if (m_device)
460                 alcCloseDevice((ALCdevice*) m_device);
461 }
462
463
464 SND_WaveSlot* SND_OpenALDevice::LoadSample(const STR_String& name,
465                                                                                   void* memlocation,
466                                                                                   int size)
467 {
468         SND_WaveSlot* waveslot = NULL;
469         STR_String samplename = name;
470         
471         if (m_audio)
472         {
473                 /* create the waveslot */
474                 waveslot = m_wavecache->GetWaveSlot(samplename);
475
476                 /* do we support this sample? */
477                 if (SND_IsSampleValid(name, memlocation))
478                 {
479                         if (waveslot)
480                         {
481                                 bool freemem = false;
482                                 int buffer = waveslot->GetBuffer();
483                                 void* data = NULL;
484                                 char loop = 'a';
485                                 int sampleformat, bitrate, numberofchannels;
486                                 ALenum al_error = alGetError();
487                                 ALsizei samplerate, numberofsamples;  // openal_2.14+
488                                 
489                                 /* Give them some safe defaults just incase */
490                                 bitrate = numberofchannels = 0;
491
492                                 if (!(size && memlocation)) {
493                                         memlocation = SND_loadFileIntoMemory(samplename.Ptr(), &size);
494                                         freemem = true;
495                                 }
496
497                                 /* load the sample from memory? */
498                                 if (size && memlocation)
499                                 {
500                                         waveslot->SetFileSize(size);
501                                         
502                                         /* what was (our) buffer? */
503                                         int buffer = waveslot->GetBuffer();
504                                         
505                                         /* get some info out of the sample */
506                                         SND_GetSampleInfo((signed char*)memlocation, waveslot);
507                                         numberofchannels = SND_GetNumberOfChannels(memlocation);
508                                         bitrate = SND_GetBitRate(memlocation);
509                                         
510                                         /* load the sample into openal */
511                                         SND_alutLoadWAVMemory((ALbyte*)memlocation, size, &sampleformat, &data, &numberofsamples, &samplerate, &loop);
512                                         /* put it in the buffer */
513                                         alBufferData(m_buffers[buffer], sampleformat, data, numberofsamples, samplerate);
514                                 }
515                                 
516                                 if(freemem)
517                                                 free(memlocation);
518                                                                 
519                                 /* fill the waveslot with info */
520                                 al_error = alGetError();
521                                 if (al_error == AL_NO_ERROR && m_buffers[buffer])
522                                 {
523                                         waveslot->SetData(data);
524                                         waveslot->SetSampleFormat(sampleformat);
525                                         waveslot->SetNumberOfChannels(numberofchannels);
526                                         waveslot->SetSampleRate(samplerate);
527                                         waveslot->SetBitRate(bitrate);
528                                         waveslot->SetNumberOfSamples(numberofsamples);
529                                         
530                                         /* if the loading succeeded, mark the waveslot */
531                                         waveslot->SetLoaded(true);
532                                 }
533                                 else
534                                 {
535                                         /* or when it failed, free the waveslot */
536                                         m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer());
537                                         waveslot = NULL;
538                                 }
539                                 
540                                 /* and free the original stuff (copy was made in openal) */
541                                 SND_alutUnloadWAV(sampleformat, data, numberofsamples, samplerate);
542                         }
543                 }
544                 else
545                 {
546                         /* sample not supported, remove waveslot */
547                         m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer());
548                         waveslot = NULL;
549                 }
550         }
551         return waveslot;
552 }
553
554
555
556 // listener's and general stuff //////////////////////////////////////////////////////
557
558
559
560 /* sets the global dopplervelocity */
561 void SND_OpenALDevice::SetDopplerVelocity(MT_Scalar dopplervelocity) const
562 {
563         alDopplerVelocity ((float)dopplervelocity);
564 }
565
566
567
568 /* sets the global dopplerfactor */
569 void SND_OpenALDevice::SetDopplerFactor(MT_Scalar dopplerfactor) const
570 {
571         alDopplerFactor ((float)dopplerfactor);
572 }
573
574
575
576 /* sets the global rolloff factor */
577 void SND_OpenALDevice::SetListenerRollOffFactor(MT_Scalar rollofffactor) const
578 {
579         // not implemented in openal
580 }
581
582
583
584 void SND_OpenALDevice::NextFrame() const
585 {
586         // CD
587 #ifndef __APPLE__
588         m_cdrom->NextFrame();
589 #endif
590         // not needed by openal
591 }
592
593
594
595 // set the gain for the listener
596 void SND_OpenALDevice::SetListenerGain(float gain) const
597 {
598         alListenerf (AL_GAIN, gain);
599 }
600
601
602
603 void SND_OpenALDevice::InitListener()
604 {
605         // initialize the listener with these values that won't change
606         // (as long as we can have only one listener)
607         // now we can superimpose all listeners on each other (for they
608         // have the same settings)
609         float lispos[3] = {0,0,0};
610         float lisvel[3] = {0,0,0};
611         float lisori[6] = {0,0,1,0,-1,0};
612
613         alListenerfv(AL_POSITION, lispos);
614         alListenerfv(AL_VELOCITY, lisvel);
615         alListenerfv(AL_ORIENTATION, lisori);
616 }
617
618
619
620 // source playstate stuff ////////////////////////////////////////////////////////////
621
622
623
624 /* sets the buffer */
625 void SND_OpenALDevice::SetObjectBuffer(int id, unsigned int buffer)
626 {
627         alSourcei (m_sources[id], AL_BUFFER, m_buffers[buffer]);
628 }
629
630
631
632 // check if the sound's still playing
633 int SND_OpenALDevice::GetPlayState(int id)
634 {
635     int alstate = 0;
636         int result = 0;
637
638 #ifdef __APPLE__
639         alGetSourcei(m_sources[id], AL_SOURCE_STATE, &alstate);
640 #else
641         alGetSourceiv(m_sources[id], AL_SOURCE_STATE, &alstate);
642 #endif
643         
644         switch(alstate)
645         {
646         case AL_INITIAL:
647                 {
648                         result = SND_INITIAL;
649                         break;
650                 }
651         case AL_PLAYING:
652                 {
653                         result = SND_PLAYING;
654                         break;
655                 }
656         case AL_PAUSED:
657                 {
658                         result = SND_PAUSED;
659                         break;
660                 }
661         case AL_STOPPED:
662                 {
663                         result = SND_STOPPED;
664                         break;
665                 }
666         default:
667                 result = SND_UNKNOWN;
668         }
669
670     return result;
671 }
672
673
674
675 // make the source play
676 void SND_OpenALDevice::PlayObject(int id)
677 {
678         alSourcePlay(m_sources[id]);
679 }
680
681
682
683 // make the source stop
684 void SND_OpenALDevice::StopObject(int id) const
685 {
686         float obpos[3] = {0,0,0};
687         float obvel[3] = {0,0,0};
688
689         alSourcefv(m_sources[id], AL_POSITION, obpos);
690         alSourcefv(m_sources[id], AL_VELOCITY, obvel);
691
692         alSourcef(m_sources[id], AL_GAIN, 1.0);
693         alSourcef(m_sources[id], AL_PITCH, 1.0);
694         alSourcei(m_sources[id], AL_LOOPING, AL_FALSE);
695         alSourceStop(m_sources[id]);
696 }
697
698
699
700 // stop all sources
701 void SND_OpenALDevice::StopAllObjects()
702 {
703         alSourceStopv(NUM_SOURCES, m_sources);
704 }
705
706
707
708 // pause the source
709 void SND_OpenALDevice::PauseObject(int id) const
710 {
711         alSourcePause(m_sources[id]);
712 }
713
714
715
716 // source properties stuff ////////////////////////////////////////////////////////////
717
718
719
720 // give openal the object's pitch
721 void SND_OpenALDevice::SetObjectPitch(int id, MT_Scalar pitch) const
722 {
723         alSourcef (m_sources[id], AL_PITCH, (float)pitch);
724 }
725
726
727
728 // give openal the object's gain
729 void SND_OpenALDevice::SetObjectGain(int id, MT_Scalar gain) const
730 {
731         alSourcef (m_sources[id], AL_GAIN, (float)gain);
732 }
733
734
735
736 // give openal the object's looping
737 void SND_OpenALDevice::SetObjectLoop(int id, unsigned int loopmode) const
738 {
739         if (loopmode == SND_LOOP_OFF)
740         {
741                 //printf("%d - ", id);
742                 alSourcei (m_sources[id], AL_LOOPING, AL_FALSE);
743         }
744         else
745                 alSourcei (m_sources[id], AL_LOOPING, AL_TRUE);
746 }
747
748 void SND_OpenALDevice::SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const
749 {
750
751
752 }
753
754
755 void SND_OpenALDevice::SetObjectMinGain(int id, MT_Scalar mingain) const
756 {
757         alSourcef (m_sources[id], AL_MIN_GAIN, (float)mingain);
758 }
759
760
761
762 void SND_OpenALDevice::SetObjectMaxGain(int id, MT_Scalar maxgain) const
763 {
764         alSourcef (m_sources[id], AL_MAX_GAIN, (float)maxgain);
765 }
766
767
768
769 void SND_OpenALDevice::SetObjectRollOffFactor(int id, MT_Scalar rollofffactor) const
770 {
771         alSourcef (m_sources[id], AL_ROLLOFF_FACTOR, (float)rollofffactor);
772 }
773
774
775
776 void SND_OpenALDevice::SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const
777 {
778         alSourcef (m_sources[id], AL_REFERENCE_DISTANCE, (float)referencedistance);
779 }
780
781
782
783 // give openal the object's position
784 void SND_OpenALDevice::ObjectIs2D(int id) const
785 {
786         float obpos[3] = {0,0,0};
787         float obvel[3] = {0,0,0};
788         
789         alSourcefv(m_sources[id], AL_POSITION, obpos);
790         alSourcefv(m_sources[id], AL_VELOCITY, obvel);
791 }
792
793
794
795 void SND_OpenALDevice::SetObjectTransform(int id,
796                                                                                   const MT_Vector3& position,
797                                                                                   const MT_Vector3& velocity,
798                                                                                   const MT_Matrix3x3& orientation,
799                                                                                   const MT_Vector3& lisposition,
800                                                                                   const MT_Scalar& rollofffactor) const 
801 {
802         float obpos[3];
803         float obvel[3];
804
805         obpos[0] = (float)position[0] * (float)rollofffactor;   //x (l/r)
806         obpos[1] = (float)position[1] * (float)rollofffactor;
807         obpos[2] = (float)position[2] * (float)rollofffactor;
808
809         alSourcefv(m_sources[id], AL_POSITION, obpos);
810
811         velocity.getValue(obvel);
812         alSourcefv(m_sources[id], AL_VELOCITY, obvel);
813 }
814
815 void SND_OpenALDevice::PlayCD(int track) const
816 {
817 #ifndef __APPLE__
818         m_cdrom->PlayCD(track);
819 #endif
820 }
821
822
823 void SND_OpenALDevice::PauseCD(bool pause) const
824 {
825 #ifndef __APPLE__
826         m_cdrom->PauseCD(pause);
827 #endif
828 }
829
830 void SND_OpenALDevice::StopCD() const
831 {
832 #ifndef __APPLE__
833         SND_CDObject* pCD = SND_CDObject::Instance();
834
835         if (pCD && pCD->GetUsed())
836         {
837                 m_cdrom->StopCD();
838         }
839 #endif
840 }
841
842 void SND_OpenALDevice::SetCDPlaymode(int playmode) const
843 {
844 #ifndef __APPLE__
845         m_cdrom->SetCDPlaymode(playmode);
846 #endif
847 }
848
849 void SND_OpenALDevice::SetCDGain(MT_Scalar gain) const
850 {
851 #ifndef __APPLE__
852         m_cdrom->SetCDGain(gain);
853 #endif
854 }