diff --git a/extern/audaspace/bindings/C/AUD_Sound.cpp b/extern/audaspace/bindings/C/AUD_Sound.cpp index 30860acde62..1f40f5c608b 100644 --- a/extern/audaspace/bindings/C/AUD_Sound.cpp +++ b/extern/audaspace/bindings/C/AUD_Sound.cpp @@ -212,7 +212,7 @@ AUD_API const char* AUD_Sound_write(AUD_Sound* sound, const char* filename, AUD_ std::shared_ptr writer = FileWriter::createWriter(filename, specs, static_cast(container), static_cast(codec), bitrate); FileWriter::writeReader(reader, writer, 0, buffersize); } - catch(Exception& e) + catch(Exception&) { return "An exception occured while writing."; } diff --git a/extern/audaspace/bindings/python/PySound.cpp b/extern/audaspace/bindings/python/PySound.cpp index 2ab1974be49..82c6036012b 100644 --- a/extern/audaspace/bindings/python/PySound.cpp +++ b/extern/audaspace/bindings/python/PySound.cpp @@ -140,8 +140,6 @@ Sound_data(Sound* self) std::memcpy(data, buffer->getBuffer(), buffer->getSize()); - Py_INCREF(array); - return reinterpret_cast(array); } diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp index 09b70897c31..2cd3261bd20 100644 --- a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp +++ b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp @@ -261,6 +261,8 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo case CHANNELS_SURROUND71: channel_layout = AV_CH_LAYOUT_7POINT1; break; + default: + AUD_THROW(FileException, "File couldn't be written, channel layout not supported."); } try diff --git a/extern/audaspace/plugins/openal/OpenALDevice.cpp b/extern/audaspace/plugins/openal/OpenALDevice.cpp index 2a609789a6d..6ad87c183aa 100644 --- a/extern/audaspace/plugins/openal/OpenALDevice.cpp +++ b/extern/audaspace/plugins/openal/OpenALDevice.cpp @@ -61,10 +61,58 @@ bool OpenALDevice::OpenALHandle::pause(bool keep) return false; } +bool OpenALDevice::OpenALHandle::reinitialize() +{ + DeviceSpecs specs = m_device->m_specs; + specs.specs = m_reader->getSpecs(); + + ALenum format; + + if(!m_device->getFormat(format, specs.specs)) + return true; + + m_format = format; + + // OpenAL playback code + alGenBuffers(CYCLE_BUFFERS, m_buffers); + if(alGetError() != AL_NO_ERROR) + return true; + + m_device->m_buffer.assureSize(m_device->m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs)); + int length; + bool eos; + + for(m_current = 0; m_current < CYCLE_BUFFERS; m_current++) + { + length = m_device->m_buffersize; + m_reader->read(length, eos, m_device->m_buffer.getBuffer()); + + if(length == 0) + break; + + alBufferData(m_buffers[m_current], m_format, m_device->m_buffer.getBuffer(), length * AUD_DEVICE_SAMPLE_SIZE(specs), specs.rate); + + if(alGetError() != AL_NO_ERROR) + return true; + } + + alGenSources(1, &m_source); + if(alGetError() != AL_NO_ERROR) + return true; + + alSourceQueueBuffers(m_source, m_current, m_buffers); + if(alGetError() != AL_NO_ERROR) + return true; + + alSourcei(m_source, AL_SOURCE_RELATIVE, m_relative); + + return false; +} + OpenALDevice::OpenALHandle::OpenALHandle(OpenALDevice* device, ALenum format, std::shared_ptr reader, bool keep) : m_isBuffered(false), m_reader(reader), m_keep(keep), m_format(format), m_eos(false), m_loopcount(0), m_stop(nullptr), m_stop_data(nullptr), m_status(STATUS_PLAYING), - m_device(device) + m_relative(1), m_device(device) { DeviceSpecs specs = m_device->m_specs; specs.specs = m_reader->getSpecs(); @@ -162,6 +210,9 @@ bool OpenALDevice::OpenALHandle::stop() if(!m_status) return false; + if(m_stop) + m_stop(m_stop_data); + m_status = STATUS_INVALID; alDeleteSources(1, &m_source); @@ -525,8 +576,6 @@ bool OpenALDevice::OpenALHandle::setOrientation(const Quaternion& orientation) bool OpenALDevice::OpenALHandle::isRelative() { - int result; - if(!m_status) return false; @@ -535,9 +584,9 @@ bool OpenALDevice::OpenALHandle::isRelative() if(!m_status) return false; - alGetSourcei(m_source, AL_SOURCE_RELATIVE, &result); + alGetSourcei(m_source, AL_SOURCE_RELATIVE, &m_relative); - return result; + return m_relative; } bool OpenALDevice::OpenALHandle::setRelative(bool relative) @@ -550,7 +599,9 @@ bool OpenALDevice::OpenALHandle::setRelative(bool relative) if(!m_status) return false; - alSourcei(m_source, AL_SOURCE_RELATIVE, relative); + m_relative = relative; + + alSourcei(m_source, AL_SOURCE_RELATIVE, m_relative); return true; } @@ -852,6 +903,80 @@ void OpenALDevice::updateStreams() { lock(); + if(m_checkDisconnect) + { + ALCint connected; + alcGetIntegerv(m_device, alcGetEnumValue(m_device, "ALC_CONNECTED"), 1, &connected); + + if(!connected) + { + // quit OpenAL + alcMakeContextCurrent(nullptr); + alcDestroyContext(m_context); + alcCloseDevice(m_device); + + // restart + if(m_name.empty()) + m_device = alcOpenDevice(nullptr); + else + m_device = alcOpenDevice(m_name.c_str()); + + // if device opening failed, there's really nothing we can do + if(m_device) + { + // at least try to set the frequency + + ALCint attribs[] = { ALC_FREQUENCY, (ALCint)specs.rate, 0 }; + ALCint* attributes = attribs; + if(specs.rate == RATE_INVALID) + attributes = nullptr; + + m_context = alcCreateContext(m_device, attributes); + alcMakeContextCurrent(m_context); + + m_checkDisconnect = alcIsExtensionPresent(m_device, "ALC_EXT_disconnect"); + + alcGetIntegerv(m_device, ALC_FREQUENCY, 1, (ALCint*)&specs.rate); + + // check for specific formats and channel counts to be played back + if(alIsExtensionPresent("AL_EXT_FLOAT32") == AL_TRUE) + specs.format = FORMAT_FLOAT32; + else + specs.format = FORMAT_S16; + + // if the format of the device changed, all handles are invalidated + // this is unlikely to happen though + if(specs.format != m_specs.format) + stopAll(); + + m_useMC = alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE; + + if((!m_useMC && specs.channels > CHANNELS_STEREO) || + specs.channels == CHANNELS_STEREO_LFE || + specs.channels == CHANNELS_SURROUND5) + specs.channels = CHANNELS_STEREO; + + alGetError(); + alcGetError(m_device); + + m_specs = specs; + + std::list > stopSounds; + + for(auto& handle : m_playingSounds) + if(handle->reinitialize()) + stopSounds.push_back(handle); + + for(auto& handle : m_pausedSounds) + if(handle->reinitialize()) + stopSounds.push_back(handle); + + for(auto& sound : stopSounds) + sound->stop(); + } + } + } + alcSuspendContext(m_context); cerr = alcGetError(m_device); if(cerr == ALC_NO_ERROR) @@ -957,12 +1082,14 @@ void OpenALDevice::updateStreams() // if it really stopped if(sound->m_eos && info != AL_INITIAL) { - if(sound->m_stop) - sound->m_stop(sound->m_stop_data); - // pause or if(sound->m_keep) + { + if(sound->m_stop) + sound->m_stop(sound->m_stop_data); + pauseSounds.push_back(sound); + } // stop else stopSounds.push_back(sound); @@ -1005,16 +1132,16 @@ void OpenALDevice::updateStreams() /******************************************************************************/ OpenALDevice::OpenALDevice(DeviceSpecs specs, int buffersize, std::string name) : - m_playing(false), m_buffersize(buffersize) + m_name(name), m_playing(false), m_buffersize(buffersize) { // cannot determine how many channels or which format OpenAL uses, but // it at least is able to play 16 bit stereo audio specs.format = FORMAT_S16; - if(name.empty()) + if(m_name.empty()) m_device = alcOpenDevice(nullptr); else - m_device = alcOpenDevice(name.c_str()); + m_device = alcOpenDevice(m_name.c_str()); if(!m_device) AUD_THROW(DeviceException, "The audio device couldn't be opened with OpenAL."); @@ -1028,6 +1155,8 @@ OpenALDevice::OpenALDevice(DeviceSpecs specs, int buffersize, std::string name) m_context = alcCreateContext(m_device, attributes); alcMakeContextCurrent(m_context); + m_checkDisconnect = alcIsExtensionPresent(m_device, "ALC_EXT_disconnect"); + alcGetIntegerv(m_device, ALC_FREQUENCY, 1, (ALCint*)&specs.rate); // check for specific formats and channel counts to be played back diff --git a/extern/audaspace/plugins/openal/OpenALDevice.h b/extern/audaspace/plugins/openal/OpenALDevice.h index b9b461a327c..c2bec443933 100644 --- a/extern/audaspace/plugins/openal/OpenALDevice.h +++ b/extern/audaspace/plugins/openal/OpenALDevice.h @@ -95,11 +95,16 @@ private: /// Current status of the handle Status m_status; + /// Whether the source is relative or not. + ALint m_relative; + /// Own device. OpenALDevice* m_device; AUD_LOCAL bool pause(bool keep); + AUD_LOCAL bool reinitialize(); + // delete copy constructor and operator= OpenALHandle(const OpenALHandle&) = delete; OpenALHandle& operator=(const OpenALHandle&) = delete; @@ -173,11 +178,21 @@ private: */ DeviceSpecs m_specs; + /** + * The device name. + */ + std::string m_name; + /** * Whether the device has the AL_EXT_MCFORMATS extension. */ bool m_useMC; + /** + * Whether the ALC_EXT_disconnect extension is present and device disconnect should be checked repeatedly. + */ + bool m_checkDisconnect; + /** * The list of sounds that are currently playing. */ diff --git a/extern/audaspace/src/respec/ChannelMapperReader.cpp b/extern/audaspace/src/respec/ChannelMapperReader.cpp index 850e54b73cf..1af5e70bfc8 100644 --- a/extern/audaspace/src/respec/ChannelMapperReader.cpp +++ b/extern/audaspace/src/respec/ChannelMapperReader.cpp @@ -296,72 +296,77 @@ const Channel* ChannelMapperReader::CHANNEL_MAPS[] = ChannelMapperReader::SURROUND71_MAP }; +constexpr float deg2rad(double angle) +{ + return float(angle * M_PI / 180.0); +} + const float ChannelMapperReader::MONO_ANGLES[] = { - 0.0f * M_PI / 180.0f + deg2rad(0.0) }; const float ChannelMapperReader::STEREO_ANGLES[] = { - -90.0f * M_PI / 180.0f, - 90.0f * M_PI / 180.0f + deg2rad(-90.0), + deg2rad( 90.0) }; const float ChannelMapperReader::STEREO_LFE_ANGLES[] = { - -90.0f * M_PI / 180.0f, - 90.0f * M_PI / 180.0f, - 0.0f * M_PI / 180.0f + deg2rad(-90.0), + deg2rad( 90.0), + deg2rad( 0.0) }; const float ChannelMapperReader::SURROUND4_ANGLES[] = { - -45.0f * M_PI / 180.0f, - 45.0f * M_PI / 180.0f, - -135.0f * M_PI / 180.0f, - 135.0f * M_PI / 180.0f + deg2rad( -45.0), + deg2rad( 45.0), + deg2rad(-135.0), + deg2rad( 135.0) }; const float ChannelMapperReader::SURROUND5_ANGLES[] = { - -30.0f * M_PI / 180.0f, - 30.0f * M_PI / 180.0f, - 0.0f * M_PI / 180.0f, - -110.0f * M_PI / 180.0f, - 110.0f * M_PI / 180.0f + deg2rad( -30.0), + deg2rad( 30.0), + deg2rad( 0.0), + deg2rad(-110.0), + deg2rad( 110.0) }; const float ChannelMapperReader::SURROUND51_ANGLES[] = { - -30.0f * M_PI / 180.0f, - 30.0f * M_PI / 180.0f, - 0.0f * M_PI / 180.0f, - 0.0f * M_PI / 180.0f, - -110.0f * M_PI / 180.0f, - 110.0f * M_PI / 180.0f + deg2rad( -30.0), + deg2rad( 30.0), + deg2rad( 0.0), + deg2rad( 0.0), + deg2rad(-110.0), + deg2rad( 110.0) }; const float ChannelMapperReader::SURROUND61_ANGLES[] = { - -30.0f * M_PI / 180.0f, - 30.0f * M_PI / 180.0f, - 0.0f * M_PI / 180.0f, - 0.0f * M_PI / 180.0f, - 180.0f * M_PI / 180.0f, - -110.0f * M_PI / 180.0f, - 110.0f * M_PI / 180.0f + deg2rad( -30.0), + deg2rad( 30.0), + deg2rad( 0.0), + deg2rad( 0.0), + deg2rad( 180.0), + deg2rad(-110.0), + deg2rad( 110.0) }; const float ChannelMapperReader::SURROUND71_ANGLES[] = { - -30.0f * M_PI / 180.0f, - 30.0f * M_PI / 180.0f, - 0.0f * M_PI / 180.0f, - 0.0f * M_PI / 180.0f, - -110.0f * M_PI / 180.0f, - 110.0f * M_PI / 180.0f, - -150.0f * M_PI / 180.0f, - 150.0f * M_PI / 180.0f + deg2rad( -30.0), + deg2rad( 30.0), + deg2rad( 0.0), + deg2rad( 0.0), + deg2rad(-110.0), + deg2rad( 110.0), + deg2rad(-150.0), + deg2rad( 150.0) }; const float* ChannelMapperReader::CHANNEL_ANGLES[] =