From 362f374732a0aae9566d875de3ca4d2d7fd5eee3 Mon Sep 17 00:00:00 2001 From: LaurentGom Date: Tue, 26 Jan 2010 09:49:03 +0000 Subject: [PATCH 1/2] FS#104 - Fix crash when destroying a SoundBuffer used by a Sound git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/trunk@1370 4e206d99-4929-0410-ac5d-dfc041789085 --- include/SFML/Audio/Sound.hpp | 9 +++++++++ include/SFML/Audio/SoundBuffer.hpp | 25 +++++++++++++++++++++++++ src/SFML/Audio/Sound.cpp | 18 +++++++++++++++++- src/SFML/Audio/SoundBuffer.cpp | 30 ++++++++++++++++++++++++++++-- 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/include/SFML/Audio/Sound.hpp b/include/SFML/Audio/Sound.hpp index 691d6338c..366d7acfe 100644 --- a/include/SFML/Audio/Sound.hpp +++ b/include/SFML/Audio/Sound.hpp @@ -288,6 +288,15 @@ public : //////////////////////////////////////////////////////////// Sound& operator =(const Sound& Other); + //////////////////////////////////////////////////////////// + /// Reset the internal buffer + /// + /// This function is for internal use only, you don't have + /// to use it. + /// + //////////////////////////////////////////////////////////// + void ResetBuffer(); + private : friend class SoundStream; diff --git a/include/SFML/Audio/SoundBuffer.hpp b/include/SFML/Audio/SoundBuffer.hpp index af459f41c..023e5aa05 100644 --- a/include/SFML/Audio/SoundBuffer.hpp +++ b/include/SFML/Audio/SoundBuffer.hpp @@ -32,10 +32,13 @@ #include #include #include +#include namespace sf { +class Sound; + //////////////////////////////////////////////////////////// /// SoundBuffer is the low-level for loading and manipulating /// sound buffers @@ -174,12 +177,34 @@ private : //////////////////////////////////////////////////////////// bool Update(unsigned int ChannelsCount, unsigned int SampleRate); + //////////////////////////////////////////////////////////// + /// Add a sound to the list of sounds that use this buffer + /// + /// \param Instance : Sound object to attach + /// + //////////////////////////////////////////////////////////// + void AttachSound(Sound* Instance) const; + + //////////////////////////////////////////////////////////// + /// Remove a sound from the list of sounds that use this buffer + /// + /// \param Instance : Sound object to detach + /// + //////////////////////////////////////////////////////////// + void DetachSound(Sound* Instance) const; + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::set SoundList; ///< Set of unique sound instances + //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// unsigned int myBuffer; ///< OpenAL buffer identifier std::vector mySamples; ///< Samples buffer float myDuration; ///< Sound duration, in seconds + mutable SoundList mySounds; ///< List of sounds that are using this buffer }; } // namespace sf diff --git a/src/SFML/Audio/Sound.cpp b/src/SFML/Audio/Sound.cpp index cd953281d..29cac745c 100644 --- a/src/SFML/Audio/Sound.cpp +++ b/src/SFML/Audio/Sound.cpp @@ -90,6 +90,7 @@ Sound::~Sound() { Stop(); ALCheck(alSourcei(mySource, AL_BUFFER, 0)); + myBuffer->DetachSound(this); } ALCheck(alDeleteSources(1, &mySource)); } @@ -129,7 +130,8 @@ void Sound::Stop() void Sound::SetBuffer(const SoundBuffer& Buffer) { myBuffer = &Buffer; - ALCheck(alSourcei(mySource, AL_BUFFER, myBuffer ? myBuffer->myBuffer : 0)); + myBuffer->AttachSound(this); + ALCheck(alSourcei(mySource, AL_BUFFER, myBuffer->myBuffer)); } @@ -360,4 +362,18 @@ Sound& Sound::operator =(const Sound& Other) return *this; } + +//////////////////////////////////////////////////////////// +/// Reset the internal buffer +//////////////////////////////////////////////////////////// +void Sound::ResetBuffer() +{ + // First stop the sound in case it is playing + Stop(); + + // Detach the buffer + ALCheck(alSourcei(mySource, AL_BUFFER, 0)); + myBuffer = 0; +} + } // namespace sf diff --git a/src/SFML/Audio/SoundBuffer.cpp b/src/SFML/Audio/SoundBuffer.cpp index 7636a01db..e726b13ad 100644 --- a/src/SFML/Audio/SoundBuffer.cpp +++ b/src/SFML/Audio/SoundBuffer.cpp @@ -27,6 +27,7 @@ //////////////////////////////////////////////////////////// #include #include +#include #include #include #include @@ -55,7 +56,8 @@ AudioResource (Copy), Resource(Copy), myBuffer (0), mySamples (Copy.mySamples), -myDuration (Copy.myDuration) +myDuration (Copy.myDuration), +mySounds () // don't copy the attached sounds { // Create the buffer ALCheck(alGenBuffers(1, &myBuffer)); @@ -70,6 +72,11 @@ myDuration (Copy.myDuration) //////////////////////////////////////////////////////////// SoundBuffer::~SoundBuffer() { + // First detach the buffer from the sounds that use it (to avoid OpenAL errors) + for (SoundList::const_iterator it = mySounds.begin(); it != mySounds.end(); ++it) + (*it)->ResetBuffer(); + + // Destroy the buffer if (myBuffer) ALCheck(alDeleteBuffers(1, &myBuffer)); } @@ -268,9 +275,10 @@ SoundBuffer& SoundBuffer::operator =(const SoundBuffer& Other) { SoundBuffer Temp(Other); - mySamples.swap(Temp.mySamples); + std::swap(mySamples, Temp.mySamples); std::swap(myBuffer, Temp.myBuffer); std::swap(myDuration, Temp.myDuration); + std::swap(mySounds, Temp.mySounds); // swap sounds too, so that they are detached when Temp is destroyed return *this; } @@ -305,4 +313,22 @@ bool SoundBuffer::Update(unsigned int ChannelsCount, unsigned int SampleRate) return true; } + +//////////////////////////////////////////////////////////// +/// Add a sound to the list of sounds that use this buffer +//////////////////////////////////////////////////////////// +void SoundBuffer::AttachSound(Sound* Instance) const +{ + mySounds.insert(Instance); +} + + +//////////////////////////////////////////////////////////// +/// Remove a sound from the list of sounds that use this buffer +//////////////////////////////////////////////////////////// +void SoundBuffer::DetachSound(Sound* Instance) const +{ + mySounds.erase(Instance); +} + } // namespace sf From 3247f441f890dc73fc14985bccab668d41527479 Mon Sep 17 00:00:00 2001 From: LaurentGom Date: Tue, 26 Jan 2010 10:31:09 +0000 Subject: [PATCH 2/2] Made the assignment operator in sf::Sound work with the last modification git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/trunk@1371 4e206d99-4929-0410-ac5d-dfc041789085 --- src/SFML/Audio/Sound.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/SFML/Audio/Sound.cpp b/src/SFML/Audio/Sound.cpp index 29cac745c..84136db12 100644 --- a/src/SFML/Audio/Sound.cpp +++ b/src/SFML/Audio/Sound.cpp @@ -129,6 +129,14 @@ void Sound::Stop() //////////////////////////////////////////////////////////// void Sound::SetBuffer(const SoundBuffer& Buffer) { + // First detach from the previous buffer + if (myBuffer) + { + Stop(); + myBuffer->DetachSound(this); + } + + // Assign and use the new buffer myBuffer = &Buffer; myBuffer->AttachSound(this); ALCheck(alSourcei(mySource, AL_BUFFER, myBuffer->myBuffer)); @@ -354,10 +362,27 @@ Sound::Status Sound::GetStatus() const //////////////////////////////////////////////////////////// Sound& Sound::operator =(const Sound& Other) { - Sound Temp(Other); + // Here we don't use the copy-and-swap idiom, because it would mess up + // the list of sound instances contained in the buffers - std::swap(mySource, Temp.mySource); - std::swap(myBuffer, Temp.myBuffer); + // Detach the sound instance from the previous buffer (if any) + if (myBuffer) + { + Stop(); + myBuffer->DetachSound(this); + myBuffer = NULL; + } + + // Copy the sound attributes + if (Other.myBuffer) + SetBuffer(*Other.myBuffer); + SetLoop(Other.GetLoop()); + SetPitch(Other.GetPitch()); + SetVolume(Other.GetVolume()); + SetPosition(Other.GetPosition()); + SetRelativeToListener(Other.IsRelativeToListener()); + SetMinDistance(Other.GetMinDistance()); + SetAttenuation(Other.GetAttenuation()); return *this; } @@ -373,7 +398,7 @@ void Sound::ResetBuffer() // Detach the buffer ALCheck(alSourcei(mySource, AL_BUFFER, 0)); - myBuffer = 0; + myBuffer = NULL; } } // namespace sf