LCOV - code coverage report
Current view: top level - src - sound_openal.cpp (source / functions) Hit Total Coverage
Test: report Lines: 232 291 79.7 %
Date: 2015-07-11 18:23:49 Functions: 28 31 90.3 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : OpenAL support based on work by:
       5             : Copyright (C) 2011 Sebastian 'Bahamada' Rühl
       6             : Copyright (C) 2011 Cyriaque 'Cisoun' Skrapits <cysoun@gmail.com>
       7             : Copyright (C) 2011 Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
       8             : 
       9             : This program is free software; you can redistribute it and/or modify
      10             : it under the terms of the GNU Lesser General Public License as published by
      11             : the Free Software Foundation; either version 2.1 of the License, or
      12             : (at your option) any later version.
      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 Lesser General Public License for more details.
      18             : 
      19             : You should have received a copy of the GNU Lesser General Public License along
      20             : with this program; ifnot, write to the Free Software Foundation, Inc.,
      21             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      22             : */
      23             : 
      24             : #include "sound_openal.h"
      25             : 
      26             : #if defined(_WIN32)
      27             :         #include <al.h>
      28             :         #include <alc.h>
      29             :         //#include <alext.h>
      30             : #elif defined(__APPLE__)
      31             :         #include <OpenAL/al.h>
      32             :         #include <OpenAL/alc.h>
      33             :         //#include <OpenAL/alext.h>
      34             : #else
      35             :         #include <AL/al.h>
      36             :         #include <AL/alc.h>
      37             :         #include <AL/alext.h>
      38             : #endif
      39             : #include <vorbis/vorbisfile.h>
      40             : #include <assert.h>
      41             : #include "log.h"
      42             : #include "filesys.h"
      43             : #include "util/numeric.h" // myrand()
      44             : #include "porting.h"
      45             : #include <map>
      46             : #include <vector>
      47             : #include <fstream>
      48             : 
      49             : #define BUFFER_SIZE 30000
      50             : 
      51           0 : static const char *alcErrorString(ALCenum err)
      52             : {
      53           0 :         switch (err) {
      54             :         case ALC_NO_ERROR:
      55           0 :                 return "no error";
      56             :         case ALC_INVALID_DEVICE:
      57           0 :                 return "invalid device";
      58             :         case ALC_INVALID_CONTEXT:
      59           0 :                 return "invalid context";
      60             :         case ALC_INVALID_ENUM:
      61           0 :                 return "invalid enum";
      62             :         case ALC_INVALID_VALUE:
      63           0 :                 return "invalid value";
      64             :         case ALC_OUT_OF_MEMORY:
      65           0 :                 return "out of memory";
      66             :         default:
      67           0 :                 return "<unknown OpenAL error>";
      68             :         }
      69             : }
      70             : 
      71           0 : static const char *alErrorString(ALenum err)
      72             : {
      73           0 :         switch (err) {
      74             :         case AL_NO_ERROR:
      75           0 :                 return "no error";
      76             :         case AL_INVALID_NAME:
      77           0 :                 return "invalid name";
      78             :         case AL_INVALID_ENUM:
      79           0 :                 return "invalid enum";
      80             :         case AL_INVALID_VALUE:
      81           0 :                 return "invalid value";
      82             :         case AL_INVALID_OPERATION:
      83           0 :                 return "invalid operation";
      84             :         case AL_OUT_OF_MEMORY:
      85           0 :                 return "out of memory";
      86             :         default:
      87           0 :                 return "<unknown OpenAL error>";
      88             :         }
      89             : }
      90             : 
      91        1288 : static ALenum warn_if_error(ALenum err, const char *desc)
      92             : {
      93        1288 :         if(err == AL_NO_ERROR)
      94        1288 :                 return err;
      95           0 :         errorstream<<"WARNING: "<<desc<<": "<<alErrorString(err)<<std::endl;
      96           0 :         return err;
      97             : }
      98             : 
      99        2332 : void f3_set(ALfloat *f3, v3f v)
     100             : {
     101        2332 :         f3[0] = v.X;
     102        2332 :         f3[1] = v.Y;
     103        2332 :         f3[2] = v.Z;
     104        2332 : }
     105             : 
     106         300 : struct SoundBuffer
     107             : {
     108             :         ALenum format;
     109             :         ALsizei freq;
     110             :         ALuint buffer_id;
     111             :         std::vector<char> buffer;
     112             : };
     113             : 
     114         172 : SoundBuffer* loadOggFile(const std::string &filepath)
     115             : {
     116         172 :         int endian = 0; // 0 for Little-Endian, 1 for Big-Endian
     117             :         int bitStream;
     118             :         long bytes;
     119             :         char array[BUFFER_SIZE]; // Local fixed size array
     120             :         vorbis_info *pInfo;
     121             :         OggVorbis_File oggFile;
     122             :         
     123             :         // Do a dumb-ass static string copy for old versions of ov_fopen
     124             :         // because they expect a non-const char*
     125             :         char nonconst[10000];
     126         172 :         snprintf(nonconst, 10000, "%s", filepath.c_str());
     127             :         // Try opening the given file
     128             :         //if(ov_fopen(filepath.c_str(), &oggFile) != 0)
     129         172 :         if(ov_fopen(nonconst, &oggFile) != 0)
     130             :         {
     131          22 :                 infostream<<"Audio: Error opening "<<filepath<<" for decoding"<<std::endl;
     132          22 :                 return NULL;
     133             :         }
     134             : 
     135         150 :         SoundBuffer *snd = new SoundBuffer;
     136             : 
     137             :         // Get some information about the OGG file
     138         150 :         pInfo = ov_info(&oggFile, -1);
     139             : 
     140             :         // Check the number of channels... always use 16-bit samples
     141         150 :         if(pInfo->channels == 1)
     142         112 :                 snd->format = AL_FORMAT_MONO16;
     143             :         else
     144          38 :                 snd->format = AL_FORMAT_STEREO16;
     145             : 
     146             :         // The frequency of the sampling rate
     147         150 :         snd->freq = pInfo->rate;
     148             : 
     149             :         // Keep reading until all is read
     150       16905 :         do
     151             :         {
     152             :                 // Read up to a buffer's worth of decoded sound data
     153       17055 :                 bytes = ov_read(&oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream);
     154             : 
     155       17055 :                 if(bytes < 0)
     156             :                 {
     157           0 :                         ov_clear(&oggFile);
     158           0 :                         infostream<<"Audio: Error decoding "<<filepath<<std::endl;
     159           0 :                         return NULL;
     160             :                 }
     161             : 
     162             :                 // Append to end of buffer
     163       17055 :                 snd->buffer.insert(snd->buffer.end(), array, array + bytes);
     164       17055 :         } while (bytes > 0);
     165             : 
     166         150 :         alGenBuffers(1, &snd->buffer_id);
     167         450 :         alBufferData(snd->buffer_id, snd->format,
     168         300 :                         &(snd->buffer[0]), snd->buffer.size(),
     169         150 :                         snd->freq);
     170             : 
     171         150 :         ALenum error = alGetError();
     172             : 
     173         150 :         if(error != AL_NO_ERROR){
     174           0 :                 infostream<<"Audio: OpenAL error: "<<alErrorString(error)
     175           0 :                                 <<"preparing sound buffer"<<std::endl;
     176             :         }
     177             : 
     178         150 :         infostream<<"Audio file "<<filepath<<" loaded"<<std::endl;
     179             : 
     180             :         // Clean up!
     181         150 :         ov_clear(&oggFile);
     182             : 
     183         150 :         return snd;
     184             : }
     185             : 
     186             : struct PlayingSound
     187             : {
     188             :         ALuint source_id;
     189             :         bool loop;
     190             : };
     191             : 
     192             : class OpenALSoundManager: public ISoundManager
     193             : {
     194             : private:
     195             :         OnDemandSoundFetcher *m_fetcher;
     196             :         ALCdevice *m_device;
     197             :         ALCcontext *m_context;
     198             :         bool m_can_vorbis;
     199             :         int m_next_id;
     200             :         std::map<std::string, std::vector<SoundBuffer*> > m_buffers;
     201             :         std::map<int, PlayingSound*> m_sounds_playing;
     202             :         v3f m_listener_pos;
     203             : public:
     204             :         bool m_is_initialized;
     205           2 :         OpenALSoundManager(OnDemandSoundFetcher *fetcher):
     206             :                 m_fetcher(fetcher),
     207             :                 m_device(NULL),
     208             :                 m_context(NULL),
     209             :                 m_can_vorbis(false),
     210             :                 m_next_id(1),
     211           2 :                 m_is_initialized(false)
     212             :         {
     213           2 :                 ALCenum error = ALC_NO_ERROR;
     214             :                 
     215           2 :                 infostream<<"Audio: Initializing..."<<std::endl;
     216             : 
     217           2 :                 m_device = alcOpenDevice(NULL);
     218           2 :                 if(!m_device){
     219           0 :                         infostream<<"Audio: No audio device available, audio system "
     220           0 :                                 <<"not initialized"<<std::endl;
     221           0 :                         return;
     222             :                 }
     223             : 
     224           2 :                 if(alcIsExtensionPresent(m_device, "EXT_vorbis")){
     225           0 :                         infostream<<"Audio: Vorbis extension present"<<std::endl;
     226           0 :                         m_can_vorbis = true;
     227             :                 } else{
     228           2 :                         infostream<<"Audio: Vorbis extension NOT present"<<std::endl;
     229           2 :                         m_can_vorbis = false;
     230             :                 }
     231             : 
     232           2 :                 m_context = alcCreateContext(m_device, NULL);
     233           2 :                 if(!m_context){
     234           0 :                         error = alcGetError(m_device);
     235           0 :                         infostream<<"Audio: Unable to initialize audio context, "
     236           0 :                                         <<"aborting audio initialization ("<<alcErrorString(error)
     237           0 :                                         <<")"<<std::endl;
     238           0 :                         alcCloseDevice(m_device);
     239           0 :                         m_device = NULL;
     240           0 :                         return;
     241             :                 }
     242             : 
     243           4 :                 if(!alcMakeContextCurrent(m_context) ||
     244           2 :                                 (error = alcGetError(m_device) != ALC_NO_ERROR))
     245             :                 {
     246           0 :                         infostream<<"Audio: Error setting audio context, aborting audio "
     247           0 :                                         <<"initialization ("<<alcErrorString(error)<<")"<<std::endl;
     248           0 :                         alcDestroyContext(m_context);
     249           0 :                         m_context = NULL;
     250           0 :                         alcCloseDevice(m_device);
     251           0 :                         m_device = NULL;
     252           0 :                         return;
     253             :                 }
     254             : 
     255           2 :                 alDistanceModel(AL_EXPONENT_DISTANCE);
     256             : 
     257           2 :                 infostream<<"Audio: Initialized: OpenAL "<<alGetString(AL_VERSION)
     258           4 :                                 <<", using "<<alcGetString(m_device, ALC_DEVICE_SPECIFIER)
     259           2 :                                 <<std::endl;
     260             : 
     261           2 :                 m_is_initialized = true;
     262             :         }
     263             : 
     264           4 :         ~OpenALSoundManager()
     265           4 :         {
     266           2 :                 infostream<<"Audio: Deinitializing..."<<std::endl;
     267             :                 // KABOOM!
     268             :                 // TODO: Clear SoundBuffers
     269           2 :                 alcMakeContextCurrent(NULL);
     270           2 :                 alcDestroyContext(m_context);
     271           2 :                 m_context = NULL;
     272           2 :                 alcCloseDevice(m_device);
     273           2 :                 m_device = NULL;
     274             : 
     275         396 :                 for (std::map<std::string, std::vector<SoundBuffer*> >::iterator i = m_buffers.begin();
     276         264 :                                 i != m_buffers.end(); i++) {
     277         840 :                         for (std::vector<SoundBuffer*>::iterator iter = (*i).second.begin();
     278         560 :                                         iter != (*i).second.end(); iter++) {
     279         150 :                                 delete *iter;
     280             :                         }
     281         130 :                         (*i).second.clear();
     282             :                 }
     283           2 :                 m_buffers.clear();
     284           2 :                 infostream<<"Audio: Deinitialized."<<std::endl;
     285           4 :         }
     286             :         
     287         150 :         void addBuffer(const std::string &name, SoundBuffer *buf)
     288             :         {
     289             :                 std::map<std::string, std::vector<SoundBuffer*> >::iterator i =
     290         150 :                                 m_buffers.find(name);
     291         150 :                 if(i != m_buffers.end()){
     292          20 :                         i->second.push_back(buf);
     293          20 :                         return;
     294             :                 }
     295         260 :                 std::vector<SoundBuffer*> bufs;
     296         130 :                 bufs.push_back(buf);
     297         130 :                 m_buffers[name] = bufs;
     298         130 :                 return;
     299             :         }
     300             : 
     301          63 :         SoundBuffer* getBuffer(const std::string &name)
     302             :         {
     303             :                 std::map<std::string, std::vector<SoundBuffer*> >::iterator i =
     304          63 :                                 m_buffers.find(name);
     305          63 :                 if(i == m_buffers.end())
     306           2 :                         return NULL;
     307          61 :                 std::vector<SoundBuffer*> &bufs = i->second;
     308          61 :                 int j = myrand() % bufs.size();
     309          61 :                 return bufs[j];
     310             :         }
     311             : 
     312          38 :         PlayingSound* createPlayingSound(SoundBuffer *buf, bool loop,
     313             :                         float volume)
     314             :         {
     315          38 :                 infostream<<"OpenALSoundManager: Creating playing sound"<<std::endl;
     316             :                 assert(buf);
     317          38 :                 PlayingSound *sound = new PlayingSound;
     318             :                 assert(sound);
     319          38 :                 warn_if_error(alGetError(), "before createPlayingSound");
     320          38 :                 alGenSources(1, &sound->source_id);
     321          38 :                 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
     322          38 :                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, true);
     323          38 :                 alSource3f(sound->source_id, AL_POSITION, 0, 0, 0);
     324          38 :                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
     325          38 :                 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
     326          38 :                 volume = MYMAX(0.0, volume);
     327          38 :                 alSourcef(sound->source_id, AL_GAIN, volume);
     328          38 :                 alSourcePlay(sound->source_id);
     329          38 :                 warn_if_error(alGetError(), "createPlayingSound");
     330          38 :                 return sound;
     331             :         }
     332             : 
     333          23 :         PlayingSound* createPlayingSoundAt(SoundBuffer *buf, bool loop,
     334             :                         float volume, v3f pos)
     335             :         {
     336          23 :                 infostream<<"OpenALSoundManager: Creating positional playing sound"
     337          23 :                                 <<std::endl;
     338             :                 assert(buf);
     339          23 :                 PlayingSound *sound = new PlayingSound;
     340             :                 assert(sound);
     341          23 :                 warn_if_error(alGetError(), "before createPlayingSoundAt");
     342          23 :                 alGenSources(1, &sound->source_id);
     343          23 :                 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
     344          23 :                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
     345          23 :                 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
     346          23 :                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
     347             :                 //alSourcef(sound->source_id, AL_ROLLOFF_FACTOR, 0.7);
     348          23 :                 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
     349          23 :                 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
     350          23 :                 volume = MYMAX(0.0, volume);
     351          23 :                 alSourcef(sound->source_id, AL_GAIN, volume);
     352          23 :                 alSourcePlay(sound->source_id);
     353          23 :                 warn_if_error(alGetError(), "createPlayingSoundAt");
     354          23 :                 return sound;
     355             :         }
     356             : 
     357          38 :         int playSoundRaw(SoundBuffer *buf, bool loop, float volume)
     358             :         {
     359             :                 assert(buf);
     360          38 :                 PlayingSound *sound = createPlayingSound(buf, loop, volume);
     361          38 :                 if(!sound)
     362           0 :                         return -1;
     363          38 :                 int id = m_next_id++;
     364          38 :                 m_sounds_playing[id] = sound;
     365          38 :                 return id;
     366             :         }
     367             : 
     368          23 :         int playSoundRawAt(SoundBuffer *buf, bool loop, float volume, v3f pos)
     369             :         {
     370             :                 assert(buf);
     371          23 :                 PlayingSound *sound = createPlayingSoundAt(buf, loop, volume, pos);
     372          23 :                 if(!sound)
     373           0 :                         return -1;
     374          23 :                 int id = m_next_id++;
     375          23 :                 m_sounds_playing[id] = sound;
     376          23 :                 return id;
     377             :         }
     378             :         
     379          57 :         void deleteSound(int id)
     380             :         {
     381             :                 std::map<int, PlayingSound*>::iterator i =
     382          57 :                                 m_sounds_playing.find(id);
     383          57 :                 if(i == m_sounds_playing.end())
     384           0 :                         return;
     385          57 :                 PlayingSound *sound = i->second;
     386             :                 
     387          57 :                 alDeleteSources(1, &sound->source_id);
     388             : 
     389          57 :                 delete sound;
     390          57 :                 m_sounds_playing.erase(id);
     391             :         }
     392             : 
     393             :         /* If buffer does not exist, consult the fetcher */
     394          62 :         SoundBuffer* getFetchBuffer(const std::string &name)
     395             :         {
     396          62 :                 SoundBuffer *buf = getBuffer(name);
     397          62 :                 if(buf)
     398          61 :                         return buf;
     399           1 :                 if(!m_fetcher)
     400           0 :                         return NULL;
     401           2 :                 std::set<std::string> paths;
     402           2 :                 std::set<std::string> datas;
     403           1 :                 m_fetcher->fetchSounds(name, paths, datas);
     404          69 :                 for(std::set<std::string>::iterator i = paths.begin();
     405          46 :                                 i != paths.end(); i++){
     406          22 :                         loadSoundFile(name, *i);
     407             :                 }
     408           3 :                 for(std::set<std::string>::iterator i = datas.begin();
     409           2 :                                 i != datas.end(); i++){
     410           0 :                         loadSoundData(name, *i);
     411             :                 }
     412           1 :                 return getBuffer(name);
     413             :         }
     414             :         
     415             :         // Remove stopped sounds
     416          68 :         void maintain()
     417             :         {
     418          68 :                 verbosestream<<"OpenALSoundManager::maintain(): "
     419         136 :                                 <<m_sounds_playing.size()<<" playing sounds, "
     420         136 :                                 <<m_buffers.size()<<" sound names loaded"<<std::endl;
     421         136 :                 std::set<int> del_list;
     422         550 :                 for(std::map<int, PlayingSound*>::iterator
     423          68 :                                 i = m_sounds_playing.begin();
     424         412 :                                 i != m_sounds_playing.end(); i++)
     425             :                 {
     426         138 :                         int id = i->first;
     427         138 :                         PlayingSound *sound = i->second;
     428             :                         // If not playing, remove it
     429             :                         {
     430             :                                 ALint state;
     431         138 :                                 alGetSourcei(sound->source_id, AL_SOURCE_STATE, &state);
     432         138 :                                 if(state != AL_PLAYING){
     433          57 :                                         del_list.insert(id);
     434             :                                 }
     435             :                         }
     436             :                 }
     437          68 :                 if(!del_list.empty())
     438          43 :                         verbosestream<<"OpenALSoundManager::maintain(): deleting "
     439          86 :                                         <<del_list.size()<<" playing sounds"<<std::endl;
     440         375 :                 for(std::set<int>::iterator i = del_list.begin();
     441         250 :                                 i != del_list.end(); i++)
     442             :                 {
     443          57 :                         deleteSound(*i);
     444             :                 }
     445          68 :         }
     446             : 
     447             :         /* Interface */
     448             : 
     449         172 :         bool loadSoundFile(const std::string &name,
     450             :                         const std::string &filepath)
     451             :         {
     452         172 :                 SoundBuffer *buf = loadOggFile(filepath);
     453         172 :                 if(buf)
     454         150 :                         addBuffer(name, buf);
     455         172 :                 return false;
     456             :         }
     457         150 :         bool loadSoundData(const std::string &name,
     458             :                         const std::string &filedata)
     459             :         {
     460             :                 // The vorbis API sucks; just write it to a file and use vorbisfile
     461             :                 // TODO: Actually load it directly from memory
     462         450 :                 std::string basepath = porting::path_user + DIR_DELIM + "cache" +
     463         450 :                                 DIR_DELIM + "tmp";
     464         300 :                 std::string path = basepath + DIR_DELIM + "tmp.ogg";
     465         150 :                 verbosestream<<"OpenALSoundManager::loadSoundData(): Writing "
     466         150 :                                 <<"temporary file to ["<<path<<"]"<<std::endl;
     467         150 :                 fs::CreateAllDirs(basepath);
     468         300 :                 std::ofstream of(path.c_str(), std::ios::binary);
     469         150 :                 of.write(filedata.c_str(), filedata.size());
     470         150 :                 of.close();
     471         300 :                 return loadSoundFile(name, path);
     472             :         }
     473             : 
     474        1166 :         void updateListener(v3f pos, v3f vel, v3f at, v3f up)
     475             :         {
     476        1166 :                 m_listener_pos = pos;
     477        1166 :                 alListener3f(AL_POSITION, pos.X, pos.Y, pos.Z);
     478        1166 :                 alListener3f(AL_VELOCITY, vel.X, vel.Y, vel.Z);
     479             :                 ALfloat f[6];
     480        1166 :                 f3_set(f, at);
     481        1166 :                 f3_set(f+3, -up);
     482        1166 :                 alListenerfv(AL_ORIENTATION, f);
     483        1166 :                 warn_if_error(alGetError(), "updateListener");
     484        1166 :         }
     485             :         
     486        1166 :         void setListenerGain(float gain)
     487             :         {
     488        1166 :                 alListenerf(AL_GAIN, gain);
     489        1166 :         }
     490             : 
     491          39 :         int playSound(const std::string &name, bool loop, float volume)
     492             :         {
     493          39 :                 maintain();
     494          39 :                 if(name == "")
     495           0 :                         return 0;
     496          39 :                 SoundBuffer *buf = getFetchBuffer(name);
     497          39 :                 if(!buf){
     498           1 :                         infostream<<"OpenALSoundManager: \""<<name<<"\" not found."
     499           1 :                                         <<std::endl;
     500           1 :                         return -1;
     501             :                 }
     502          38 :                 return playSoundRaw(buf, loop, volume);
     503             :         }
     504          27 :         int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
     505             :         {
     506          27 :                 maintain();
     507          27 :                 if(name == "")
     508           4 :                         return 0;
     509          23 :                 SoundBuffer *buf = getFetchBuffer(name);
     510          23 :                 if(!buf){
     511           0 :                         infostream<<"OpenALSoundManager: \""<<name<<"\" not found."
     512           0 :                                         <<std::endl;
     513           0 :                         return -1;
     514             :                 }
     515          23 :                 return playSoundRawAt(buf, loop, volume, pos);
     516             :         }
     517           0 :         void stopSound(int sound)
     518             :         {
     519           0 :                 maintain();
     520           0 :                 deleteSound(sound);
     521           0 :         }
     522           2 :         bool soundExists(int sound)
     523             :         {
     524           2 :                 maintain();
     525           2 :                 return (m_sounds_playing.count(sound) != 0);
     526             :         }
     527          59 :         void updateSoundPosition(int id, v3f pos)
     528             :         {
     529             :                 std::map<int, PlayingSound*>::iterator i =
     530          59 :                                 m_sounds_playing.find(id);
     531          59 :                 if(i == m_sounds_playing.end())
     532          26 :                         return;
     533          33 :                 PlayingSound *sound = i->second;
     534             : 
     535          33 :                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
     536          33 :                 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
     537          33 :                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
     538          33 :                 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
     539             :         }
     540             : };
     541             : 
     542           2 : ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher)
     543             : {
     544           2 :         OpenALSoundManager *m = new OpenALSoundManager(fetcher);
     545           2 :         if(m->m_is_initialized)
     546           2 :                 return m;
     547           0 :         delete m;
     548           0 :         return NULL;
     549           3 : };
     550             : 

Generated by: LCOV version 1.11