Crashes when playing (multiple Sound objects from one file)
I've been going over this crap all day and still have no answers. It seems like it would be fairly simple...
I have a "unit" class that has an array of sounds:
when a unit is created, the following code is called:
for (int i=0; i<3; i++)
sndHi[i] = SoundManager::getSingletonPtr()->createSound("hi" + StringConverter::toString(i)
+ StringConverter::toString(myId), "hi" + StringConverter::toString(i) + ".wav");
(myId is unique for each instance)
When a unit is clicked, it randomly picks one of the sounds and (tries to) play it. I can click around on some of the units; if it picks the first sound, it will play fine. But if I click on the first unit and it picks one of the other sounds, it crashes; if I click on any other unit and it picks one of the other sounds, nothing happens.
When it crashes, it throws this exception message:
OGRE EXCEPTION(40963:): Could not load buffer data: OpenAL Error: The value pointer given is not valid in OgreAL::WavSound::loadBuffers
The really crazy thing is, every once in a while (read: rarely) it will actually work perfectly! Even without recompiling!
It doesn't matter if the program is in debug or release. I've tried clean builds, etc. Even tried using separate variables instead of an array, or only two sounds, all with the same damn results. If I use only one sound, it is very random whether it will work or not.
This is for a group school project, I would really appreciate any help!
I checked my Ogre.log for the first time (didn't know about it) and found something that is probably a clue. My program creates 14 units, each of which creates its own sounds. The log file had 13 sets of these messages:
!!WARNING!! Could not determine buffer format! Defaulting to MONO
These messages are apparently from all of the units after the first one. I did check to make sure my sounds were mono, and after that I tried 8-bit and ogg, neither of which changed the results. But the fact that it doesn't say anything when the first unit is created is strange, especially since it doesn't work. When the other units are created, it finds a buffer for the sounds that the first unit created and tries to use them also, but doesn't recognise the format... I guess because the buffer gets corrupted somehow.
I don't know why I didn't try this before, but I made it create only 1 unit. It always works fine with just 1 unit, but as soon as I add another, it does the same thing it had been doing. SO there's definitely a problem there with creating multiple Sound objects using the same sound file.
I also discovered from the log that I'm using the non-threaded version of OgreAL.
The cause of the problem is still unknown to me, but I worked around it by simply creating each sound when it first needs to be played. *shrug*
I had the same problem, and I think I found the cause.
When you create a second instance of a sound, the buffer info is taken from the first buffer loaded.
Ogre::MovableObject* SoundFactory::createInstanceImpl(const Ogre::String& name,
const Ogre::NameValuePairList* params)
BufferMap::iterator bufferItr = mBufferMap.find(fileName);
if(bufferItr != mBufferMap.end())
// We have this buffer loaded already!
return new Sound((BufferRef)bufferItr->second, name, fileName, loop);
The problem is that this information is not complete filled till the first instance is played (firstintance->play() )
When I debugged the creation of the second instance, this values were 0:
alGetBufferi(mBuffers, AL_FREQUENCY, &mFreq);
alGetBufferi(mBuffers, AL_BITS, &mBPS);
alGetBufferi(mBuffers, AL_CHANNELS, &mChannels);
alGetBufferi(mBuffers, AL_SIZE, &mSize);
I solved this adding:
At the end of the creation of the first instance, in my case I use an ogg file:
OggSound::OggSound(const Ogre::String& name, const Ogre::DataStreamPtr& soundStream, bool loop, bool stream) :
Sound(name, soundStream->getName(), stream)
mSoundStream = soundStream;
// Set up custom accessors
callbacks.close_func = OgreALOggStreamClose;
callbacks.tell_func = OgreALOggStreamTell;
callbacks.read_func = OgreALOggStreamRead;
callbacks.seek_func = OgreALOggStreamSeek;
// Open the Ogre::DataStreamPtr
CheckCondition(ov_open_callbacks(&mSoundStream, &mOggStream, NULL, 0, callbacks) >= 0, 1, "Could not open Ogg stream.");
mVorbisInfo = ov_info(&mOggStream, -1);
unsigned long channels = mVorbisInfo->channels;
mFreq = mVorbisInfo->rate;
mChannels = mVorbisInfo->channels;
mBPS = 16;
mLoop = loop;
mLengthInSeconds = ov_time_total(&mOggStream, -1);
mBuffersLoaded = loadBuffers();
I think for .wav has to be the same, in the wav creator.
Hope this helps.
that did not work for me, but a really ugly hack did:
after creating the sound object, I did
the full story:
i have several sound files as background music, "Normal" and for "combat". the error ocurred when i re-loaded the level ("Start new game") and combat music should be played.
to load another (or reload the same) level, my app loads a new instance, assigns viewport, player control and so on to it, and deletes the old one in the next frame. The music is stored as pre-created Sound objects.
So the creation and deletion of the music looked somehow like this:
- first instance: create sounds
- first instance: play random "normal" sound
- first instance: play random "combat" sound: ok
- first instance: delete sounds (destruction preparation method)
- second instance: create sounds
- second instance: play random "normal" sound
- first instance: delete
- second instance: play random "combat" sound: crash
the "normal" music is played right after level creation, this might be the reason why it did not crash then. i also tried putting the deletion of the sounds into the real destructor instead of the preparation method, no difference
update: Elenssar's fix did work when this problem appeared in another place.
generally it seems to be a bad idea to keep OgreAL::Sounds around, creating and playing then necessary seems to work better
edit: no, i have to take it back. it didn't do anything. it was just luck
Before the fix, It was not possible for me to create a second instance of one sound. Now I have 4 instances of the same sound, and works.
I still have a random crash that appears sometimes.
I don't think the problem is the multiple instances of one sound, I think is something about what you say
it seems to be a bad idea to keep OgreAL::Sounds around, creating and playing then necessary seems to work better Because crash in the function updateAll (of the soundmanager) updating the list of sounds, in diferent sounds, even when the sound is a unique instance.
I'm still looking for solve this randomly crash, because I need multiple sounds at the same time.
I semi-solved it by streaming the sounds that I want to keep around.
(footsteps in this case, would make absolutely no sense to re-create it each time, since I almost loop it)
but I think that would consume memory if I have too many characters walking around, i think it creates an own buffer for each streaming sound instance