Crashes when playing (multiple Sound objects from one file)

mattstermiller

29-03-2008 02:38:18

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:
Sound* sndHi[3];

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");
sndHi[i]->setMinGain(0.2);
sndHi[i]->setMaxGain(3.0);
sndHi[i]->setGain(3.0);
sndHi[i]->setRolloffFactor(6);
node->attachObject(sndHi[i]);
}

(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!

mattstermiller

29-03-2008 03:22:07

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.

mattstermiller

04-04-2008 15:10:45

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*

Elenssar

06-04-2008 19:29:28

Hello,
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.


//OgreALSound.cpp

Ogre::MovableObject* SoundFactory::createInstanceImpl(const Ogre::String& name,
const Ogre::NameValuePairList* params)
{
...

if(!stream)
{
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[0], AL_FREQUENCY, &mFreq);
alGetBufferi(mBuffers[0], AL_BITS, &mBPS);
alGetBufferi(mBuffers[0], AL_CHANNELS, &mChannels);
alGetBufferi(mBuffers[0], AL_SIZE, &mSize);



I solved this adding:

loadBuffers();

At the end of the creation of the first instance, in my case I use an ogg file:

//OgreALOggSound.cpp
OggSound::OggSound(const Ogre::String& name, const Ogre::DataStreamPtr& soundStream, bool loop, bool stream) :
Sound(name, soundStream->getName(), stream)
{
try
{
mSoundStream = soundStream;

// Set up custom accessors
ov_callbacks callbacks;
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;

calculateFormatInfo();

mLengthInSeconds = ov_time_total(&mOggStream, -1);

generateBuffers();
//Added:
if(!mBuffersLoaded)
{
mBuffersLoaded = loadBuffers();
}
}

I think for .wav has to be the same, in the wav creator.
Hope this helps.

pra

06-04-2008 21:50:42

that did not work for me, but a really ugly hack did:
after creating the sound object, I did
snd->play();
snd->pause();

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

pra

16-04-2008 22:07:29

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

Elenssar

17-04-2008 05:43:25

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.

pra

17-04-2008 07:33:39

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