ISoundSource* CSoundManager::CreateSource(const wchar *filename, Vec3 position, bool relativeToListener) { CSoundBuffer* buff = CreateBuffer(filename); if(!buff) return NULL; CSoundSource* source = new CSoundSource(); if(!source) { DestroyBuffer(buff); return NULL; } source->Create(m_extensions, buff, position, relativeToListener); m_sources.push_back(source); return source; }
void AudioChannel::FindSourceAndPlay(size_t id, const float3& pos, const float3& velocity, float volume, bool relative) { if (!enabled) return; if (volume <= 0.0f) return; boost::recursive_mutex::scoped_lock slck(soundMutex); SoundItem* sndItem = sound->GetSoundItem(id); if (!sndItem) { sound->numEmptyPlayRequests++; return; } if (pos.distance(sound->GetListenerPos()) > sndItem->MaxDistance()) { if (!relative) return; else LogObject(LOG_SOUND) << "CSound::PlaySample: maxdist ignored for relative payback: " << sndItem->Name(); } if (emmitsThisFrame >= emmitsPerFrame) return; emmitsThisFrame++; CSoundSource* sndSource = sound->GetNextBestSource(); if (!sndSource) return; if (sndSource->GetCurrentPriority() < sndItem->GetPriority()) { if (sndSource->IsPlaying()) sound->numAbortedPlays++; sndSource->Play(this, sndItem, pos, velocity, volume, relative); CheckError("CSound::FindSourceAndPlay"); boost::recursive_mutex::scoped_lock lck(chanMutex); cur_sources[sndSource] = true; } }
CSoundSource* CSound::GetNextBestSource(bool lock) { boost::recursive_mutex::scoped_lock lck(soundMutex, boost::defer_lock); if (lock) lck.lock(); if (sources.empty()) return NULL; CSoundSource* bestPos = NULL; for (sourceVecT::iterator it = sources.begin(); it != sources.end(); ++it) { if (!it->IsPlaying()) { return &(*it); } else if (it->GetCurrentPriority() <= (bestPos ? bestPos->GetCurrentPriority() : INT_MAX)) { bestPos = &(*it); } } return bestPos; }
__FORCE_ALIGN_STACK__ void CSound::StartThread(int maxSounds) { { boost::recursive_mutex::scoped_lock lck(soundMutex); // alc... will create its own thread it will copy the name from the current thread. // Later we finally rename `our` audio thread. Threading::SetThreadName("openal"); // NULL -> default device const ALchar* deviceName = NULL; std::string configDeviceName = ""; // we do not want to set a default for snd_device, // so we do it like this ... if (configHandler->IsSet("snd_device")) { configDeviceName = configHandler->GetString("snd_device"); deviceName = configDeviceName.c_str(); } ALCdevice* device = alcOpenDevice(deviceName); if ((device == NULL) && (deviceName != NULL)) { LOG_L(L_WARNING, "Could not open the sound device \"%s\", trying the default device ...", deviceName); configDeviceName = ""; deviceName = NULL; device = alcOpenDevice(deviceName); } if (device == NULL) { LOG_L(L_ERROR, "Could not open a sound device, disabling sounds"); CheckError("CSound::InitAL"); return; } else { ALCcontext *context = alcCreateContext(device, NULL); if (context != NULL) { alcMakeContextCurrent(context); CheckError("CSound::CreateContext"); } else { alcCloseDevice(device); LOG_L(L_ERROR, "Could not create OpenAL audio context"); return; } } maxSounds = GetMaxMonoSources(device, maxSounds); LOG("OpenAL info:"); if(alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) { LOG(" Available Devices:"); const char* deviceSpecifier = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); while (*deviceSpecifier != '\0') { LOG(" %s", deviceSpecifier); while (*deviceSpecifier++ != '\0') ; } LOG(" Device: %s", (const char*)alcGetString(device, ALC_DEVICE_SPECIFIER)); } LOG(" Vendor: %s", (const char*)alGetString(AL_VENDOR)); LOG(" Version: %s", (const char*)alGetString(AL_VERSION)); LOG(" Renderer: %s", (const char*)alGetString(AL_RENDERER)); LOG(" AL Extensions: %s", (const char*)alGetString(AL_EXTENSIONS)); LOG(" ALC Extensions: %s", (const char*)alcGetString(device, ALC_EXTENSIONS)); // Init EFX efx = new CEFX(device); // Generate sound sources for (int i = 0; i < maxSounds; i++) { CSoundSource* thenewone = new CSoundSource(); if (thenewone->IsValid()) { sources.push_back(thenewone); } else { maxSounds = std::max(i-1, 0); LOG_L(L_WARNING, "Your hardware/driver can not handle more than %i soundsources", maxSounds); delete thenewone; break; } } LOG(" Max Sounds: %i", maxSounds); // Set distance model (sound attenuation) alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); alDopplerFactor(0.2f); alListenerf(AL_GAIN, masterVolume); } Threading::SetThreadName("audio"); Watchdog::RegisterThread(WDT_AUDIO); while (!soundThreadQuit) { boost::this_thread::sleep(boost::posix_time::millisec(50)); //! 20Hz Watchdog::ClearTimer(WDT_AUDIO); Update(); } Watchdog::DeregisterThread(WDT_AUDIO); sources.clear(); // delete all sources delete efx; // must happen after sources and before context efx = NULL; ALCcontext* curcontext = alcGetCurrentContext(); ALCdevice* curdevice = alcGetContextsDevice(curcontext); alcMakeContextCurrent(NULL); alcDestroyContext(curcontext); alcCloseDevice(curdevice); }
void AudioChannel::FindSourceAndPlay(size_t id, const float3& pos, const float3& velocity, float volume, bool relative) { boost::recursive_mutex::scoped_lock lck(soundMutex); if (!enabled) return; if (volume <= 0.0f) return; SoundItem* sndItem = sound->GetSoundItem(id); if (!sndItem) { sound->numEmptyPlayRequests++; return; } if (pos.distance(sound->GetListenerPos()) > sndItem->MaxDistance()) { if (!relative) { return; } else { LOG("CSound::PlaySample: maxdist ignored for relative playback: %s", sndItem->Name().c_str()); } } if (emmitsThisFrame >= emmitsPerFrame) return; emmitsThisFrame++; if (cur_sources.size() >= maxConcurrentSources) { CSoundSource* src = NULL; int prio = INT_MAX; for (std::map<CSoundSource*, bool>::iterator it = cur_sources.begin(); it != cur_sources.end(); ++it) { if (it->first->GetCurrentPriority() < prio) { src = it->first; prio = it->first->GetCurrentPriority(); } } if (src && prio <= sndItem->GetPriority()) { src->Stop(); } else { LOG_L(L_DEBUG, "CSound::PlaySample: Max concurrent sounds in channel reached! Dropping playback!"); return; } } CSoundSource* sndSource = sound->GetNextBestSource(); if (!sndSource) { LOG_L(L_DEBUG, "CSound::PlaySample: Max sounds reached! Dropping playback!"); return; } if (sndSource->GetCurrentPriority() < sndItem->GetPriority()) { if (sndSource->IsPlaying()) sound->numAbortedPlays++; sndSource->Play(this, sndItem, pos, velocity, volume, relative); CheckError("CSound::FindSourceAndPlay"); cur_sources[sndSource] = true; } }
void AudioChannel::FindSourceAndPlay(size_t id, const float3& pos, const float3& velocity, float volume, bool relative) { std::lock_guard<spring::recursive_mutex> lck(soundMutex); if (!enabled) return; if (volume <= 0.0f) return; // generate the sound item SoundItem* sndItem = sound->GetSoundItem(id); if (sndItem == nullptr) { sound->numEmptyPlayRequests++; return; } // check distance to listener if (pos.distance(sound->GetListenerPos()) > sndItem->MaxDistance()) { if (!relative) return; LOG("CSound::PlaySample: maxdist ignored for relative playback: %s", sndItem->Name().c_str()); } // don't spam to many sounds per frame if (emitsThisFrame >= emitsPerFrame) return; emitsThisFrame++; // check if the sound item is already played if (curSources.size() >= maxConcurrentSources) { CSoundSource* src = nullptr; int prio = INT_MAX; for (auto it = curSources.begin(); it != curSources.end(); ++it) { if ((*it)->GetCurrentPriority() < prio) { src = *it; prio = src->GetCurrentPriority(); } } if (src == nullptr || prio > sndItem->GetPriority()) { LOG_L(L_DEBUG, "CSound::PlaySample: Max concurrent sounds in channel reached! Dropping playback!"); return; } src->Stop(); } // find a sound source to play the item in CSoundSource* sndSource = sound->GetNextBestSource(); if (sndSource == nullptr || (sndSource->GetCurrentPriority() >= sndItem->GetPriority())) { LOG_L(L_DEBUG, "CSound::PlaySample: Max sounds reached! Dropping playback!"); return; } if (sndSource->IsPlaying()) sound->numAbortedPlays++; // play the sound item sndSource->PlayAsync(this, sndItem, pos, velocity, volume, relative); curSources.insert(sndSource); }
void CSound::StartThread(int maxSounds) { { boost::recursive_mutex::scoped_lock lck(soundMutex); // NULL -> default device const ALchar* deviceName = NULL; std::string configDeviceName = ""; // we do not want to set a default for snd_device, // so we do it like this ... if (configHandler->IsSet("snd_device")) { configDeviceName = configHandler->GetString("snd_device", "YOU_SHOULD_NOT_EVER_SEE_THIS"); deviceName = configDeviceName.c_str(); } ALCdevice* device = alcOpenDevice(deviceName); if ((device == NULL) && (deviceName != NULL)) { LogObject(LOG_SOUND) << "Could not open the sound device \"" << deviceName << "\", trying the default device ..."; configDeviceName = ""; deviceName = NULL; device = alcOpenDevice(deviceName); } if (device == NULL) { LogObject(LOG_SOUND) << "Could not open a sound device, disabling sounds"; CheckError("CSound::InitAL"); return; } else { ALCcontext *context = alcCreateContext(device, NULL); if (context != NULL) { alcMakeContextCurrent(context); CheckError("CSound::CreateContext"); } else { alcCloseDevice(device); LogObject(LOG_SOUND) << "Could not create OpenAL audio context"; return; } } const bool airAbsorptionSupported = alcIsExtensionPresent(device, "ALC_EXT_EFX"); LogObject(LOG_SOUND) << "OpenAL info:\n"; if(alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) { LogObject(LOG_SOUND) << " Available Devices:"; const char *s = alcGetString(NULL, ALC_DEVICE_SPECIFIER); while (*s != '\0') { LogObject(LOG_SOUND) << " " << s; while (*s++ != '\0') ; } LogObject(LOG_SOUND) << " Device: " << alcGetString(device, ALC_DEVICE_SPECIFIER); } LogObject(LOG_SOUND) << " Vendor: " << (const char*)alGetString(AL_VENDOR ); LogObject(LOG_SOUND) << " Version: " << (const char*)alGetString(AL_VERSION); LogObject(LOG_SOUND) << " Renderer: " << (const char*)alGetString(AL_RENDERER); LogObject(LOG_SOUND) << " AL Extensions: " << (const char*)alGetString(AL_EXTENSIONS); LogObject(LOG_SOUND) << " ALC Extensions: " << (const char*)alcGetString(device, ALC_EXTENSIONS); // Init EFX efx = new CEFX(device); // Generate sound sources for (int i = 0; i < maxSounds; i++) { CSoundSource* thenewone = new CSoundSource(); if (thenewone->IsValid()) { sources.push_back(thenewone); } else { maxSounds = std::max(i-1, 0); LogObject(LOG_SOUND) << "Your hardware/driver can not handle more than " << maxSounds << " soundsources"; delete thenewone; break; } } LogObject(LOG_SOUND) << " Max Sounds: " << maxSounds; // Set distance model (sound attenuation) alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); alDopplerFactor(0.2f); alListenerf(AL_GAIN, masterVolume); } configHandler->Set("MaxSounds", maxSounds); while (!soundThreadQuit) { boost::this_thread::sleep(boost::posix_time::millisec(50)); //! 20Hz Update(); } sources.clear(); // delete all sources delete efx; // must happen after sources and before context ALCcontext* curcontext = alcGetCurrentContext(); ALCdevice* curdevice = alcGetContextsDevice(curcontext); alcMakeContextCurrent(NULL); alcDestroyContext(curcontext); alcCloseDevice(curdevice); }