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