Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/SoundSystem/openal/SND_OpenALDevice.cpp')
-rw-r--r--intern/SoundSystem/openal/SND_OpenALDevice.cpp661
1 files changed, 661 insertions, 0 deletions
diff --git a/intern/SoundSystem/openal/SND_OpenALDevice.cpp b/intern/SoundSystem/openal/SND_OpenALDevice.cpp
new file mode 100644
index 00000000000..a5cbf8d3300
--- /dev/null
+++ b/intern/SoundSystem/openal/SND_OpenALDevice.cpp
@@ -0,0 +1,661 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * SND_OpenALDevice derived from SND_IAudioDevice
+ */
+
+#ifdef WIN32
+#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
+#endif //WIN32
+
+#include "SND_OpenALDevice.h"
+#include "SoundDefines.h"
+#include "SYS_System.h"
+
+#include "SND_Utils.h"
+
+#include <AL/al.h>
+#include <AL/alc.h>
+#include <AL/alut.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#if defined(WIN32)
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+/* untill openal gets unified we need this hack for non-windows systems */
+#ifndef WIN32
+
+#include <malloc.h>
+
+ALvoid alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop);
+ALvoid alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq);
+
+typedef struct /* WAV File-header */
+{
+ ALubyte Id[4];
+ ALsizei Size;
+ ALubyte Type[4];
+} WAVFileHdr_Struct;
+
+typedef struct /* WAV Fmt-header */
+{
+ ALushort Format;
+ ALushort Channels;
+ ALuint SamplesPerSec;
+ ALuint BytesPerSec;
+ ALushort BlockAlign;
+ ALushort BitsPerSample;
+} WAVFmtHdr_Struct;
+
+typedef struct /* WAV FmtEx-header */
+{
+ ALushort Size;
+ ALushort SamplesPerBlock;
+} WAVFmtExHdr_Struct;
+
+typedef struct /* WAV Smpl-header */
+{
+ ALuint Manufacturer;
+ ALuint Product;
+ ALuint SamplePeriod;
+ ALuint Note;
+ ALuint FineTune;
+ ALuint SMPTEFormat;
+ ALuint SMPTEOffest;
+ ALuint Loops;
+ ALuint SamplerData;
+ struct
+ {
+ ALuint Identifier;
+ ALuint Type;
+ ALuint Start;
+ ALuint End;
+ ALuint Fraction;
+ ALuint Count;
+ } Loop[1];
+} WAVSmplHdr_Struct;
+
+typedef struct /* WAV Chunk-header */
+{
+ ALubyte Id[4];
+ ALuint Size;
+} WAVChunkHdr_Struct;
+
+ALvoid alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop)
+{
+ WAVChunkHdr_Struct ChunkHdr;
+ WAVFmtExHdr_Struct FmtExHdr;
+ WAVFileHdr_Struct FileHdr;
+ WAVSmplHdr_Struct SmplHdr;
+ WAVFmtHdr_Struct FmtHdr;
+ ALbyte *Stream;
+
+ *format=AL_FORMAT_MONO16;
+ *data=NULL;
+ *size=0;
+ *freq=22050;
+ *loop=AL_FALSE;
+ if (memory)
+ {
+ Stream=memory;
+ if (Stream)
+ {
+ memcpy(&FileHdr,Stream,sizeof(WAVFileHdr_Struct));
+ Stream+=sizeof(WAVFileHdr_Struct);
+ FileHdr.Size=((FileHdr.Size+1)&~1)-4;
+ while ((FileHdr.Size!=0)&&(memcpy(&ChunkHdr,Stream,sizeof(WAVChunkHdr_Struct))))
+ {
+ Stream+=sizeof(WAVChunkHdr_Struct);
+ if (!memcmp(ChunkHdr.Id,"fmt ",4))
+ {
+ memcpy(&FmtHdr,Stream,sizeof(WAVFmtHdr_Struct));
+ if (FmtHdr.Format==0x0001)
+ {
+ *format=(FmtHdr.Channels==1?
+ (FmtHdr.BitsPerSample==8?AL_FORMAT_MONO8:AL_FORMAT_MONO16):
+ (FmtHdr.BitsPerSample==8?AL_FORMAT_STEREO8:AL_FORMAT_STEREO16));
+ *freq=FmtHdr.SamplesPerSec;
+ Stream+=ChunkHdr.Size;
+ }
+ else
+ {
+ memcpy(&FmtExHdr,Stream,sizeof(WAVFmtExHdr_Struct));
+ Stream+=ChunkHdr.Size;
+ }
+ }
+ else if (!memcmp(ChunkHdr.Id,"data",4))
+ {
+ if (FmtHdr.Format==0x0001)
+ {
+ *size=ChunkHdr.Size;
+ *data=malloc(ChunkHdr.Size+31);
+ if (*data) memcpy(*data,Stream,ChunkHdr.Size);
+ memset(((char *)*data)+ChunkHdr.Size,0,31);
+ Stream+=ChunkHdr.Size;
+ }
+ else if (FmtHdr.Format==0x0011)
+ {
+ //IMA ADPCM
+ }
+ else if (FmtHdr.Format==0x0055)
+ {
+ //MP3 WAVE
+ }
+ }
+ else if (!memcmp(ChunkHdr.Id,"smpl",4))
+ {
+ memcpy(&SmplHdr,Stream,sizeof(WAVSmplHdr_Struct));
+ *loop = (SmplHdr.Loops ? AL_TRUE : AL_FALSE);
+ Stream+=ChunkHdr.Size;
+ }
+ else Stream+=ChunkHdr.Size;
+ Stream+=ChunkHdr.Size&1;
+ FileHdr.Size-=(((ChunkHdr.Size+1)&~1)+8);
+ }
+ }
+ }
+}
+
+ALvoid alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq)
+{
+ if (data)
+ free(data);
+}
+
+#endif /* WIN32 */
+
+
+
+SND_OpenALDevice::SND_OpenALDevice()
+{
+ // check if audio is wanted
+ SYS_SystemHandle syshandle = SYS_GetSystem();
+ int audio = SYS_GetCommandLineInt(syshandle,"noaudio",0);
+
+ if (audio != 0)
+ m_audio = false;
+ else
+ m_audio = true;
+
+ m_buffersinitialized = false;
+ m_sourcesinitialized = false;
+
+ // let's check if we can get openal to initialize...
+ if (m_audio)
+ {
+#ifdef OUDE_OPENAL
+ m_audio = true; // openal_2.12
+ alutInit(NULL, NULL); // openal_2.12
+#else
+ m_audio = false;
+
+ ALCdevice *dev = alcOpenDevice(NULL);
+ if (dev) {
+ m_context = alcCreateContext(dev, NULL);
+
+ if (m_context) {
+ alcMakeContextCurrent(m_context);
+ m_audio = true;
+ }
+ }
+
+#endif
+ }
+
+ // then try to generate some buffers
+ if (m_audio)
+ {
+ // let openal generate its buffers
+ alGenBuffers(NUM_BUFFERS, m_buffers);
+ m_buffersinitialized = true;
+
+ for (int i = 0; i < NUM_BUFFERS; i++)
+ {
+ if (!alIsBuffer(m_buffers[i]))
+ {
+ //printf("\n\n WARNING: OpenAL returned with an error. Continuing without audio.\n\n");
+ m_audio = false;
+ break;
+ }
+ }
+ }
+
+ // next: the sources
+ if (m_audio)
+ {
+#ifdef OUDE_OPENAL
+ ALenum alc_error = ALC_NO_ERROR; // openal_2.12
+#else
+ ALenum alc_error = alcGetError(); // openal_2.14+
+#endif
+
+ // let openal generate its sources
+ if (alc_error == ALC_NO_ERROR)
+ {
+ alGenSources(NUM_SOURCES, m_sources);
+ m_sourcesinitialized = true;
+ }
+ }
+
+ // let's get us a wavecache
+ if (m_audio)
+ {
+ m_wavecache = new SND_WaveCache();
+ }
+}
+
+
+
+void SND_OpenALDevice::MakeCurrent() const
+{
+#ifdef WIN32
+ alcMakeContextCurrent(m_context);
+#endif
+}
+
+
+
+SND_OpenALDevice::~SND_OpenALDevice()
+{
+ if (m_context) {
+ alcMakeContextCurrent(m_context);
+
+ if (m_buffersinitialized)
+ alDeleteBuffers(NUM_BUFFERS, m_buffers);
+
+ if (m_sourcesinitialized)
+ alDeleteSources(NUM_SOURCES, m_sources);
+ }
+}
+
+
+
+SND_WaveSlot* SND_OpenALDevice::LoadSample(const STR_String& name,
+ void* memlocation,
+ int size)
+{
+ SND_WaveSlot* waveslot = NULL;
+ STR_String samplename = name;
+
+ if (m_audio)
+ {
+ /* create the waveslot */
+ waveslot = m_wavecache->GetWaveSlot(samplename);
+
+ /* do we support this sample? */
+ if (SND_IsSampleValid(name, memlocation))
+ {
+ if (waveslot)
+ {
+ int buffer = waveslot->GetBuffer();
+ void* data = NULL;
+ char loop = 'a';
+ int sampleformat, bitrate, numberofchannels;
+ ALenum al_error = alGetError();
+
+#ifdef OUDE_OPENAL
+ unsigned int samplerate, numberofsamples; // openal_2.12
+#else
+ int samplerate, numberofsamples, frequency; // openal_2.14+
+#endif
+
+ /* load the sample from memory? */
+ if (size && memlocation)
+ {
+ waveslot->SetFileSize(size);
+
+ /* what was (our) buffer? */
+ int buffer = waveslot->GetBuffer();
+
+ /* get some info out of the sample */
+ SND_GetSampleInfo((signed char*)memlocation, waveslot);
+ numberofchannels = SND_GetNumberOfChannels(memlocation);
+ bitrate = SND_GetBitRate(memlocation);
+
+ /* load the sample into openal */
+#ifdef OUDE_OPENAL
+ alutLoadWAVMemory((char*)memlocation, &sampleformat, &data, &numberofsamples, &samplerate); // openal_2.12
+#else
+ alutLoadWAVMemory((signed char*)memlocation, &sampleformat, &data, &numberofsamples, &samplerate, &loop);// openal_2.14+
+#endif
+ /* put it in the buffer */
+ alBufferData(m_buffers[buffer], sampleformat, data, numberofsamples, samplerate);
+ }
+ /* or from file? */
+ else
+ {
+#ifdef WIN32
+ alutLoadWAVFile((signed char*)samplename.Ptr(), &sampleformat, &data, &numberofsamples, &samplerate, &loop);
+#else
+ alutLoadWAV((char*)samplename.Ptr(), &data,
+ &sampleformat, &numberofsamples,
+ &samplerate, &frequency);
+#endif
+ /* put it in the buffer */
+ alBufferData(m_buffers[buffer], sampleformat, data, numberofsamples, samplerate);
+ }
+
+ /* fill the waveslot with info */
+ al_error = alGetError();
+ if (al_error == AL_NO_ERROR && m_buffers[buffer])
+ {
+ waveslot->SetData(data);
+ waveslot->SetSampleFormat(sampleformat);
+ waveslot->SetNumberOfChannels(numberofchannels);
+ waveslot->SetSampleRate(samplerate);
+ waveslot->SetBitRate(bitrate);
+ waveslot->SetNumberOfSamples(numberofsamples);
+
+ /* if the loading succeeded, mark the waveslot */
+ waveslot->SetLoaded(true);
+ }
+ else
+ {
+ /* or when it failed, free the waveslot */
+ m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer());
+ waveslot = NULL;
+ }
+
+ /* and free the original stuff (copy was made in openal) */
+ alutUnloadWAV(sampleformat, data, numberofsamples, samplerate);
+ }
+ }
+ else
+ {
+ /* sample not supported, remove waveslot */
+ m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer());
+ waveslot = NULL;
+ }
+ }
+ return waveslot;
+}
+
+
+
+// listener's and general stuff //////////////////////////////////////////////////////
+
+
+
+/* sets the global dopplervelocity */
+void SND_OpenALDevice::SetDopplerVelocity(MT_Scalar dopplervelocity) const
+{
+ alDopplerVelocity ((float)dopplervelocity);
+}
+
+
+
+/* sets the global dopplerfactor */
+void SND_OpenALDevice::SetDopplerFactor(MT_Scalar dopplerfactor) const
+{
+ alDopplerFactor ((float)dopplerfactor);
+}
+
+
+
+/* sets the global rolloff factor */
+void SND_OpenALDevice::SetListenerRollOffFactor(MT_Scalar rollofffactor) const
+{
+ // not implemented in openal
+}
+
+
+
+void SND_OpenALDevice::NextFrame() const
+{
+ // not needed by openal
+}
+
+
+
+// set the gain for the listener
+void SND_OpenALDevice::SetListenerGain(float gain) const
+{
+ alListenerf (AL_GAIN, gain);
+}
+
+
+
+void SND_OpenALDevice::InitListener()
+{
+ // initialize the listener with these values that won't change
+ // (as long as we can have only one listener)
+ // now we can superimpose all listeners on each other (for they
+ // have the same settings)
+ float lispos[3] = {0,0,0};
+ float lisvel[3] = {0,0,0};
+#ifdef WIN32
+ float lisori[6] = {0,1,0,0,0,1};
+#else
+ float lisori[6] = {0,0,1,0,-1,0};
+#endif
+
+ alListenerfv(AL_POSITION, lispos);
+ alListenerfv(AL_VELOCITY, lisvel);
+ alListenerfv(AL_ORIENTATION, lisori);
+}
+
+
+
+// source playstate stuff ////////////////////////////////////////////////////////////
+
+
+
+/* sets the buffer */
+void SND_OpenALDevice::SetObjectBuffer(int id, unsigned int buffer)
+{
+ alSourcei (m_sources[id], AL_BUFFER, m_buffers[buffer]);
+}
+
+
+
+// check if the sound's still playing
+int SND_OpenALDevice::GetPlayState(int id)
+{
+ int alstate = 0;
+ int result = 0;
+
+ alGetSourceiv(m_sources[id], AL_SOURCE_STATE, &alstate);
+
+ switch(alstate)
+ {
+ case AL_INITIAL:
+ {
+ result = SND_INITIAL;
+ break;
+ }
+ case AL_PLAYING:
+ {
+ result = SND_PLAYING;
+ break;
+ }
+ case AL_PAUSED:
+ {
+ result = SND_PAUSED;
+ break;
+ }
+ case AL_STOPPED:
+ {
+ result = SND_STOPPED;
+ break;
+ }
+ default:
+ result = SND_UNKNOWN;
+ }
+
+ return result;
+}
+
+
+
+// make the source play
+void SND_OpenALDevice::PlayObject(int id)
+{
+ alSourcePlay(m_sources[id]);
+}
+
+
+
+// make the source stop
+void SND_OpenALDevice::StopObject(int id) const
+{
+ float obpos[3] = {0,0,0};
+ float obvel[3] = {0,0,0};
+
+ alSourcefv(m_sources[id], AL_POSITION, obpos);
+
+#ifdef WIN32
+ alSourcefv(m_sources[id], AL_VELOCITY, obvel);
+#endif
+
+ alSourcef(m_sources[id], AL_GAIN, 1.0);
+ alSourcef(m_sources[id], AL_PITCH, 1.0);
+ alSourcei(m_sources[id], AL_LOOPING, AL_FALSE);
+ alSourceStop(m_sources[id]);
+}
+
+
+
+// stop all sources
+void SND_OpenALDevice::StopAllObjects()
+{
+ alSourceStopv(NUM_SOURCES, m_sources);
+}
+
+
+
+// pause the source
+void SND_OpenALDevice::PauseObject(int id) const
+{
+ alSourcePause(m_sources[id]);
+}
+
+
+
+// source properties stuff ////////////////////////////////////////////////////////////
+
+
+
+// give openal the object's pitch
+void SND_OpenALDevice::SetObjectPitch(int id, MT_Scalar pitch) const
+{
+ alSourcef (m_sources[id], AL_PITCH, (float)pitch);
+}
+
+
+
+// give openal the object's gain
+void SND_OpenALDevice::SetObjectGain(int id, MT_Scalar gain) const
+{
+ alSourcef (m_sources[id], AL_GAIN, (float)gain);
+}
+
+
+
+// give openal the object's looping
+void SND_OpenALDevice::SetObjectLoop(int id, unsigned int loopmode) const
+{
+ if (loopmode == SND_LOOP_OFF)
+ {
+ //printf("%d - ", id);
+ alSourcei (m_sources[id], AL_LOOPING, AL_FALSE);
+ }
+ else
+ alSourcei (m_sources[id], AL_LOOPING, AL_TRUE);
+}
+
+
+
+void SND_OpenALDevice::SetObjectMinGain(int id, MT_Scalar mingain) const
+{
+ alSourcef (m_sources[id], AL_MIN_GAIN, (float)mingain);
+}
+
+
+
+void SND_OpenALDevice::SetObjectMaxGain(int id, MT_Scalar maxgain) const
+{
+ alSourcef (m_sources[id], AL_MAX_GAIN, (float)maxgain);
+}
+
+
+
+void SND_OpenALDevice::SetObjectRollOffFactor(int id, MT_Scalar rollofffactor) const
+{
+ alSourcef (m_sources[id], AL_ROLLOFF_FACTOR, (float)rollofffactor);
+}
+
+
+
+void SND_OpenALDevice::SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const
+{
+ alSourcef (m_sources[id], AL_REFERENCE_DISTANCE, (float)referencedistance);
+}
+
+
+
+// give openal the object's position
+void SND_OpenALDevice::ObjectIs2D(int id) const
+{
+ float obpos[3] = {0,0,0};
+ float obvel[3] = {0,0,0};
+
+ alSourcefv(m_sources[id], AL_POSITION, obpos);
+ alSourcefv(m_sources[id], AL_VELOCITY, obvel);
+}
+
+
+
+void SND_OpenALDevice::SetObjectTransform(int id,
+ const MT_Vector3& position,
+ const MT_Vector3& velocity,
+ const MT_Matrix3x3& orientation,
+ const MT_Vector3& lisposition,
+ const MT_Scalar& rollofffactor) const
+{
+ float obpos[3];
+ float obvel[3];
+
+ obpos[0] = (float)position[0] * (float)rollofffactor; //x (l/r)
+ obpos[1] = (float)position[1] * (float)rollofffactor;
+ obpos[2] = (float)position[2] * (float)rollofffactor;
+
+ alSourcefv(m_sources[id], AL_POSITION, obpos);
+
+#ifdef WIN32
+ velocity.getValue(obvel);
+ alSourcefv(m_sources[id], AL_VELOCITY, obvel);
+#endif
+
+}