Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/archive/environment2/src/orxonox/sound/SoundManager.cc @ 10241

Last change on this file since 10241 was 8351, checked in by rgrieder, 14 years ago

Merged kicklib2 branch back to trunk (includes former branches ois_update, mac_osx and kicklib).

Notes for updating

Linux:
You don't need an extra package for CEGUILua and Tolua, it's already shipped with CEGUI.
However you do need to make sure that the OgreRenderer is installed too with CEGUI 0.7 (may be a separate package).
Also, Orxonox now recognises if you install the CgProgramManager (a separate package available on newer Ubuntu on Debian systems).

Windows:
Download the new dependency packages versioned 6.0 and use these. If you have problems with that or if you don't like the in game console problem mentioned below, you can download the new 4.3 version of the packages (only available for Visual Studio 2005/2008).

Key new features:

  • *Support for Mac OS X*
  • Visual Studio 2010 support
  • Bullet library update to 2.77
  • OIS library update to 1.3
  • Support for CEGUI 0.7 —> Support for Arch Linux and even SuSE
  • Improved install target
  • Compiles now with GCC 4.6
  • Ogre Cg Shader plugin activated for Linux if available
  • And of course lots of bug fixes

There are also some regressions:

  • No support for CEGUI 0.5, Ogre 1.4 and boost 1.35 - 1.39 any more
  • In game console is not working in main menu for CEGUI 0.7
  • Tolua (just the C lib, not the application) and CEGUILua libraries are no longer in our repository. —> You will need to get these as well when compiling Orxonox
  • And of course lots of new bugs we don't yet know about
  • Property svn:eol-style set to native
File size: 23.6 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *       Erwin 'vaiursch' Herrsche
24 *       Kevin Young
25 *       Reto Grieder
26 *   Co-authors:
27 *      ...
28 *
29 */
30
31#include "SoundManager.h"
32
33#include <utility>
34#include <alut.h>
35#include <loki/ScopeGuard.h>
36
37#include "util/Exception.h"
38#include "util/Math.h"
39#include "util/Clock.h"
40#include "util/ScopedSingletonManager.h"
41#include "core/ConfigValueIncludes.h"
42#include "core/CoreIncludes.h"
43#include "core/GameMode.h"
44#include "core/Resource.h"
45#include "SoundBuffer.h"
46#include "BaseSound.h"
47#include "AmbientSound.h"
48#include "WorldSound.h"
49
50namespace orxonox
51{
52    ManageScopedSingleton(SoundManager, ScopeID::Graphics, true);
53
54    std::string SoundManager::getALErrorString(ALenum code)
55    {
56        switch (code)
57        {
58        case AL_NO_ERROR:          return "No error";
59        case AL_INVALID_NAME:      return "Invalid AL parameter name";
60        case AL_INVALID_ENUM:      return "Invalid AL enum";
61        case AL_INVALID_VALUE:     return "Invalid AL value";
62        case AL_INVALID_OPERATION: return "Invalid AL operation";
63        case AL_OUT_OF_MEMORY:     return "AL reports out of memory";
64        default:                   return "Unknown AL error";
65        }
66    }
67
68    SoundManager::SoundManager()
69        : effectsPoolSize_(0)
70    {
71        RegisterRootObject(SoundManager);
72
73        this->bDestructorCalled_ = false;
74
75        // Clear error messages (might be problematic on some systems)
76        alGetError();
77        alutGetError();
78
79        // See whether we even want to load
80        bool bDisableSound_ = false;
81        SetConfigValue(bDisableSound_, false);
82        if (bDisableSound_)
83            ThrowException(InitialisationAborted, "Sound: Not loading at all");
84        if (!alutInitWithoutContext(NULL, NULL))
85            ThrowException(InitialisationFailed, "Sound Error: ALUT initialisation failed: " << alutGetErrorString(alutGetError()));
86        Loki::ScopeGuard alutExitGuard = Loki::MakeGuard(&alutExit);
87
88/*
89        // Get list of available sound devices and display them
90        const char* devices = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
91        char* device = new char[strlen(devices)+1];
92        strcpy(device, devices);
93        std::string renderDevice;
94        SetConfigValue(renderDevice, std::string(device)).description("Sound device used for rendering");
95        COUT(4) << "Sound: Available devices: ";
96        while (true)
97        {
98            this->deviceNames_.push_back(devices);
99            COUT(4) << '"' << devices << "\", ";
100            devices += strlen(devices) + 1;
101            if (*devices == '\0')
102                break;
103        }
104        COUT(4) << std::endl;
105
106        // Open the selected device
107        COUT(3) << "Sound: Opening device \"" << renderDevice << '\' << std::endl;
108        this->device_ = alcOpenDevice(renderDevice.c_str());
109*/
110        this->device_ = alcOpenDevice(NULL);
111        if (this->device_ == NULL)
112            ThrowException(InitialisationFailed, "Sound Error: Could not open sound device.");
113        Loki::ScopeGuard closeDeviceGuard = Loki::MakeGuard(&alcCloseDevice, this->device_);
114
115        // Create sound context and make it the currently used one
116        this->context_ = alcCreateContext(this->device_, NULL);
117        if (this->context_ == NULL)
118            ThrowException(InitialisationFailed, "Sound Error: Could not create ALC context");
119        Loki::ScopeGuard desroyContextGuard = Loki::MakeGuard(&alcDestroyContext, this->context_);
120        if (!alcMakeContextCurrent(this->context_))
121            ThrowException(InitialisationFailed, "Sound Error: Could not use ALC context");
122
123        GameMode::setPlaysSound(true);
124        Loki::ScopeGuard resetPlaysSoundGuard = Loki::MakeGuard(&GameMode::setPlaysSound, false);
125
126        // Get some information about the sound
127        if (const char* version = alGetString(AL_VERSION))
128            COUT(4) << "Sound: --- OpenAL Version: " << version << std::endl;
129        if (const char* vendor = alGetString(AL_VENDOR))
130            COUT(4) << "Sound: --- OpenAL Vendor : " << vendor << std::endl;
131        if (const char* types = alutGetMIMETypes(ALUT_LOADER_BUFFER))
132            COUT(4) << "Sound: --- Supported MIME Types: " << types << std::endl;
133        else
134            COUT(2) << "Sound Warning: MIME Type retrieval failed: " << alutGetErrorString(alutGetError()) << std::endl;
135
136        this->mute_[SoundType::All]     = 1.0f;
137        this->mute_[SoundType::Music]   = 1.0f;
138        this->mute_[SoundType::Effects] = 1.0f;
139
140        this->setConfigValues();
141
142        // Try to get at least one source
143        ALuint source;
144        alGenSources(1, &source);
145        if (!alGetError() && alIsSource(source))
146            this->availableSoundSources_.push_back(source);
147        else
148            ThrowException(InitialisationFailed, "Sound Error: Could not create even a single source");
149        // Create a few initial sources
150        this->createSoundSources(this->minSources_ - 1);
151
152        // Disarm guards
153        alutExitGuard.Dismiss();
154        closeDeviceGuard.Dismiss();
155        desroyContextGuard.Dismiss();
156        resetPlaysSoundGuard.Dismiss();
157
158        COUT(4) << "Sound: Initialisation complete" << std::endl;
159    }
160
161    SoundManager::~SoundManager()
162    {
163        // Erase fade lists because of the smart pointers
164        this->bDestructorCalled_ = true;
165        this->fadeInList_.clear();
166        this->fadeOutList_.clear();
167
168        // If there are still used buffers around, well, that's just very bad...
169        if (this->soundBuffers_.size() != this->effectsPool_.size())
170            COUT(1) << "Sound Error: Some sound buffers are still in use but OpenAL is about to shut down. Fix this!" << std::endl;
171        // Empty buffer pool and buffer list
172        this->effectsPool_.clear();
173        this->soundBuffers_.clear();
174
175        // There should not be any sources in use anymore
176        if (!this->usedSoundSources_.empty())
177            COUT(1) << "Sound Error: Some sound sources are still in use but OpenAL is about to shut down. Fix this!" << std::endl;
178        while (!this->availableSoundSources_.empty())
179        {
180            alDeleteSources(1, &this->availableSoundSources_.back());
181            this->availableSoundSources_.pop_back();
182        }
183
184        GameMode::setPlaysSound(false);
185
186        // Relieve context to destroy it
187        if (!alcMakeContextCurrent(NULL))
188            COUT(1) << "Sound Error: Could not unset ALC context" << std::endl;
189        alcDestroyContext(this->context_);
190        if (ALCenum error = alcGetError(this->device_))
191        {
192            if (error == AL_INVALID_OPERATION)
193                COUT(1) << "Sound Error: Could not destroy ALC context because it is the current one" << std::endl;
194            else
195                COUT(1) << "Sound Error: Could not destroy ALC context because it is invalid" << std::endl;
196        }
197#ifdef AL_VERSION_1_1
198        if (!alcCloseDevice(this->device_))
199            COUT(1) << "Sound Error: Could not destroy ALC device. This might be because there are still buffers in use!" << std::endl;
200#else
201        alcCloseDevice(this->device_);
202#endif
203        if (!alutExit())
204            COUT(1) << "Sound Error: Closing ALUT failed: " << alutGetErrorString(alutGetError()) << std::endl;
205    }
206
207    void SoundManager::setConfigValues()
208    {
209        SetConfigValue(crossFadeStep_, 0.2f)
210            .description("Determines how fast sounds should fade, per second.")
211            .callback(this, &SoundManager::checkFadeStepValidity);
212
213        SetConfigValueAlias(volume_[SoundType::All], "soundVolume_", 1.0f)
214            .description("Defines the overall volume.")
215            .callback(this, &SoundManager::checkSoundVolumeValidity);
216        SetConfigValueAlias(volume_[SoundType::Music], "ambientVolume_", 1.0f)
217            .description("Defines the ambient volume.")
218            .callback(this, &SoundManager::checkAmbientVolumeValidity);
219        SetConfigValueAlias(volume_[SoundType::Effects], "effectsVolume_", 1.0f)
220            .description("Defines the effects volume.")
221            .callback(this, &SoundManager::checkEffectsVolumeValidity);
222
223        SetConfigValue(minSources_, 16)
224            .description("Minimum number of sources being generated (if possible)");
225        SetConfigValue(maxSources_, 1024)
226            .description("Maximum number of sources to be made available");
227    }
228
229    void SoundManager::preUpdate(const Clock& time)
230    {
231        this->processCrossFading(time.getDeltaTime());
232
233        // Check whether a sound object has stopped playing
234        for (unsigned int i = 0; i < this->usedSoundSources_.size(); ++i)
235        {
236            ALint state;
237            alGetSourcei(this->usedSoundSources_[i].first, AL_SOURCE_STATE, &state);
238            if (state == AL_STOPPED)
239            {
240                if (this->usedSoundSources_[i].second->stop()) // if stop() returns true, the sound source was removed, thus decrement the array index
241                    --i;
242            }
243        }
244    }
245
246    void SoundManager::checkFadeStepValidity()
247    {
248        if (crossFadeStep_ <= 0.0 || crossFadeStep_ >= 1.0 )
249        {
250            COUT(2) << "Sound warning: fade step out of range, ignoring change." << std::endl;
251            ResetConfigValue(crossFadeStep_);
252        }
253    }
254
255    void SoundManager::checkVolumeValidity(SoundType::Value type)
256    {
257        float clampedVolume = clamp(this->volume_[type], 0.0f, 1.0f);
258        if (clampedVolume != this->volume_[type])
259            COUT(2) << "Sound warning: Volume setting (" << type << ") out of range, clamping." << std::endl;
260        this->updateVolume(type);
261    }
262
263    void SoundManager::setVolume(float vol, SoundType::Value type)
264    {
265        if (type < 0 || type > SoundType::Effects)
266            return;
267        this->volume_[type] = vol;
268        this->checkVolumeValidity(type);
269    }
270
271    float SoundManager::getVolume(SoundType::Value type)
272    {
273        if (type < 0 || type > SoundType::Effects)
274            return 0.0f;
275        return this->volume_[type];
276    }
277
278    float SoundManager::getRealVolume(SoundType::Value type)
279    {
280        if (type != SoundType::Music && type != SoundType::Effects)
281            return 0.0f;
282        return this->volume_[SoundType::All] * this->mute_[SoundType::All] * this->volume_[type] * this->mute_[type];
283    }
284
285    void SoundManager::updateVolume(SoundType::Value type)
286    {
287        switch(type)
288        {
289        case SoundType::All:
290            for (ObjectList<BaseSound>::iterator it = ObjectList<BaseSound>::begin(); it != ObjectList<BaseSound>::end(); ++it)
291                (*it)->updateVolume();
292            break;
293        case SoundType::Music:
294            for (ObjectList<AmbientSound>::iterator it = ObjectList<AmbientSound>::begin(); it != ObjectList<AmbientSound>::end(); ++it)
295                (*it)->updateVolume();
296            break;
297        case SoundType::Effects:
298            for (ObjectList<WorldSound>::iterator it = ObjectList<WorldSound>::begin(); it != ObjectList<WorldSound>::end(); ++it)
299                (*it)->updateVolume();
300            break;
301        default:
302            assert(false);
303        }
304    }
305
306    void SoundManager::toggleMute(SoundType::Value type)
307    {
308        if (type < 0 || type > SoundType::Effects)
309            return;
310        this->mute_[type] = (this->mute_[type] == 0) ? 1.0f : 0.0f;
311        this->updateVolume(type);
312    }
313
314    bool SoundManager::getMute(SoundType::Value type)
315    {
316        if (type < 0 || type > SoundType::Effects)
317            return true;
318        return (this->mute_[type] == 0);
319    }
320
321    void SoundManager::setListenerPosition(const Vector3& position)
322    {
323        alListener3f(AL_POSITION, position.x, position.y, position.z);
324        ALenum error = alGetError();
325        if (error == AL_INVALID_VALUE)
326            // @TODO: Follow this constantly appearing, nerve-racking warning
327            COUT(2) << "Sound: OpenAL: Invalid listener position" << std::endl;
328    }
329
330    void SoundManager::setListenerOrientation(const Quaternion& orientation)
331    {
332        // update listener orientation
333        const Vector3& direction = -orientation.zAxis();
334        const Vector3& up = orientation.yAxis();
335
336        ALfloat orient[6] = { direction.x, direction.y, direction.z, up.x, up.y, up.z };
337
338        alListenerfv(AL_ORIENTATION, orient);
339        ALenum error = alGetError();
340        if (error == AL_INVALID_VALUE)
341            COUT(2) << "Sound: OpenAL: Invalid listener orientation" << std::endl;
342    }
343
344    void SoundManager::registerAmbientSound(AmbientSound* newAmbient)
345    {
346        if (newAmbient != NULL && !this->bDestructorCalled_)
347        {
348            for (AmbientList::const_iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
349            {
350                if (it->first == newAmbient)
351                {
352                    COUT(2) << "Sound warning: Will not play an AmbientSound twice." << std::endl;
353                    return;
354                }
355            }
356
357            if (!this->ambientSounds_.empty())
358            {
359                this->fadeOut(ambientSounds_.front().first);
360            }
361            this->ambientSounds_.push_front(std::make_pair(newAmbient, false));
362            newAmbient->doPlay();
363            this->fadeIn(newAmbient);
364        }
365    }
366
367    void SoundManager::unregisterAmbientSound(AmbientSound* oldAmbient)
368    {
369        if (oldAmbient == NULL || ambientSounds_.empty() || this->bDestructorCalled_)
370            return;
371
372        if (this->ambientSounds_.front().first == oldAmbient)
373        {
374            this->fadeOut(oldAmbient);
375            this->ambientSounds_.pop_front();
376            if (!this->ambientSounds_.empty())
377            {
378                if (!this->ambientSounds_.front().second) // Not paused before
379                {
380                    this->ambientSounds_.front().first->doPlay();
381                }
382                this->fadeIn(this->ambientSounds_.front().first);
383            }
384        }
385        else
386        {
387            for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
388            {
389                if (it->first == oldAmbient)
390                {
391                    this->fadeOut(oldAmbient);
392                    this->ambientSounds_.erase(it);
393                    break;
394                }
395            }
396        }
397    }
398
399    void SoundManager::pauseAmbientSound(AmbientSound* ambient)
400    {
401        if (ambient != NULL)
402        {
403            for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
404            {
405                if (it->first == ambient)
406                {
407                    it->second = true;
408                    this->fadeOut(it->first);
409                    return;
410                }
411            }
412        }
413    }
414
415    void SoundManager::fadeIn(const SmartPtr<AmbientSound>& sound)
416    {
417        // If we're already fading out --> remove that
418        for (std::list<SmartPtr<AmbientSound> >::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); it++)
419        {
420            if (*it == sound)
421            {
422                this->fadeOutList_.erase(it);
423                break;
424            }
425        }
426        // No duplicate entries
427        if (std::find(this->fadeInList_.begin(), this->fadeInList_.end(), sound) == this->fadeInList_.end())
428            this->fadeInList_.push_back(sound);
429    }
430
431    void SoundManager::fadeOut(const SmartPtr<AmbientSound>& sound)
432    {
433        // If we're already fading in --> remove that
434        for (std::list<SmartPtr<AmbientSound> >::iterator it = this->fadeInList_.begin(); it != this->fadeInList_.end(); it++)
435        {
436            if (*it == sound)
437            {
438                this->fadeInList_.erase(it);
439                break;
440            }
441        }
442        // No duplicate entries
443        if (std::find(this->fadeOutList_.begin(), this->fadeOutList_.end(), sound) == this->fadeOutList_.end())
444            this->fadeOutList_.push_back(sound);
445    }
446
447    void SoundManager::processCrossFading(float dt)
448    {
449
450        // Hacky solution to the fade delay while loading a level.
451        if(dt > 0.2)
452        {
453            return;
454        }
455
456        // FADE IN
457        for (std::list<SmartPtr<AmbientSound> >::iterator it= this->fadeInList_.begin(); it != this->fadeInList_.end(); )
458        {
459            if ((*it)->getVolume() + this->crossFadeStep_*dt > 1.0f)
460            {
461                (*it)->setVolume(1.0f);
462                this->fadeInList_.erase(it++);
463            }
464            else
465            {
466                (*it)->setVolume((*it)->getVolume() + this->crossFadeStep_*dt);
467                ++it;
468            }
469        }
470
471        // FADE OUT
472        for (std::list<SmartPtr<AmbientSound> >::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); )
473        {
474            if ((*it)->getVolume() - this->crossFadeStep_*dt < 0.0f)
475            {
476                (*it)->setVolume(0.0f);
477
478                // If sound is in the ambient list --> pause
479                for (AmbientList::const_iterator it2 = this->ambientSounds_.begin(); it2 != this->ambientSounds_.end(); ++it2)
480                {
481                    if (it2->first == *it)
482                    {
483                        (*it)->doPause();
484                        break;
485                    }
486                }
487                // If not pause (by loop above for instance) --> stop
488                if (!(*it)->isPaused())
489                    (*it)->doStop();
490
491                this->fadeOutList_.erase(it++);
492            }
493            else
494            {
495                (*it)->setVolume((*it)->getVolume() - this->crossFadeStep_*dt);
496                ++it;
497            }
498        }
499    }
500
501    shared_ptr<SoundBuffer> SoundManager::getSoundBuffer(const std::string& filename)
502    {
503        shared_ptr<SoundBuffer> buffer;
504        // Check active or pooled buffers
505        SoundBufferMap::const_iterator it = this->soundBuffers_.find(filename);
506        if (it != this->soundBuffers_.end())
507        {
508            buffer = it->second;
509
510            // Remove from effects pool if not active used before
511            if (buffer->poolIterator_ != this->effectsPool_.end())
512            {
513                this->effectsPoolSize_ -= buffer->getSize();
514                this->effectsPool_.erase(buffer->poolIterator_);
515                buffer->poolIterator_ = this->effectsPool_.end();
516            }
517        }
518        else
519        {
520            try
521            {
522                buffer.reset(new SoundBuffer(filename, this->effectsPool_.end()));
523            }
524            catch (const std::exception& ex)
525            {
526                COUT(1) << ex.what() << std::endl;
527                return buffer;
528            }
529            this->soundBuffers_[filename] = buffer;
530        }
531        return buffer;
532    }
533
534    void SoundManager::releaseSoundBuffer(const shared_ptr<SoundBuffer>& buffer, bool bPoolBuffer)
535    {
536        // Check if others are still using the buffer
537        if (buffer.use_count() != 2)
538            return;
539        SoundBufferMap::iterator it = this->soundBuffers_.find(buffer->getFilename());
540        if (it != this->soundBuffers_.end())
541        {
542            if (bPoolBuffer)
543            {
544                // Pool already too large?
545                while (this->effectsPoolSize_ + it->second->getSize() > this->maxEffectsPoolSize_s && !this->effectsPool_.empty())
546                {
547                    shared_ptr<SoundBuffer> bufferDel = this->effectsPool_.back();
548                    this->effectsPoolSize_ -= bufferDel->getSize();
549                    bufferDel->poolIterator_ = this->effectsPool_.end();
550                    this->effectsPool_.pop_back();
551                    // Remove from buffer map too
552                    SoundBufferMap::iterator itDel = this->soundBuffers_.find(bufferDel->getFilename());
553                    if (itDel != this->soundBuffers_.end())
554                        this->soundBuffers_.erase(itDel);
555                }
556                // Put buffer into the pool
557                this->effectsPoolSize_ += it->second->getSize();
558                this->effectsPool_.push_front(it->second);
559                it->second->poolIterator_ = this->effectsPool_.begin();
560            }
561            else
562                this->soundBuffers_.erase(it);
563        }
564    }
565
566    ALuint SoundManager::getSoundSource(BaseSound* object)
567    {
568        if (!this->availableSoundSources_.empty())
569        {
570            ALuint source = this->availableSoundSources_.back();
571            this->availableSoundSources_.pop_back();
572            this->usedSoundSources_.push_back(std::make_pair(source, object));
573            return source;
574        }
575        else
576        {
577            if (this->usedSoundSources_.size() < this->maxSources_)
578            {
579                ALuint source;
580                alGenSources(1, &source);
581                // Try to create new sources (50% more, but at least one)
582                if (alIsSource(source) && !alGetError())
583                {
584                    this->usedSoundSources_.push_back(std::make_pair(source, object));
585                    return source;
586                }
587            }
588            // Return no source ID
589            ALuint source = 123456789;
590            while (alIsSource(++source));
591            return source;
592        }
593    }
594
595    void SoundManager::releaseSoundSource(ALuint source)
596    {
597#ifndef NDEBUG
598        for (std::vector<ALuint>::const_iterator it = this->availableSoundSources_.begin(); it != this->availableSoundSources_.end(); ++it)
599            assert((*it) != source);
600#endif
601        this->availableSoundSources_.push_back(source);
602        for (std::vector<std::pair<ALuint, BaseSound*> >::iterator it = this->usedSoundSources_.begin();
603            it != this->usedSoundSources_.end(); ++it)
604        {
605            if (it->first == source)
606            {
607                this->usedSoundSources_.erase(it);
608                break;
609            }
610        }
611        int used = std::max((unsigned int)(this->usedSoundSources_.size()), this->minSources_);
612        // Subtract those we added in the statement above trough std::max
613        int available = (int)this->availableSoundSources_.size() - (used - (int)this->usedSoundSources_.size());
614        // Delete sources again to free resources if appropriate (more than 50% more available than used)
615        int toDelete = available - used / 2;
616        while (toDelete-- > 0)
617        {
618            alDeleteSources(1, &this->availableSoundSources_.back());
619            if (alGetError())
620                COUT(1) << "Sound Error: Failed to delete a source --> lost forever" << std::endl;
621            this->availableSoundSources_.pop_back();
622        }
623    }
624
625    unsigned int SoundManager::createSoundSources(unsigned int n)
626    {
627        unsigned int count = this->availableSoundSources_.size() + this->usedSoundSources_.size();
628        while (count < this->maxSources_ && count <= n)
629        {
630            ALuint source;
631            alGenSources(1, &source);
632            if (alIsSource(source) && !alGetError())
633                this->availableSoundSources_.push_back(source);
634            else
635                break;
636            ++count;
637        }
638        return count - this->availableSoundSources_.size() - this->usedSoundSources_.size();
639    }
640}
Note: See TracBrowser for help on using the repository browser.