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