hiccups when playing sounds

I have a problem where sometimes when calling .play() on a sound there is a delay which can be anywhere from a few ms to 200ms (depending on length of sound I assume).
I pre-load all of the sounds (AudioManager.getSound) when the game loads. Even still, the hiccups continue after all the sounds have already been played multiple times.
I am using FMOD. Switching to OpenAL is not an option as I need to use the audio filters in FMOD.
Any ideas?

Well, the first thing would be to try switching to OpenAL, at least temporarily, to narrow down the cause of the problem. If you observe the same behavior in OpenAL, then you can rule out the audio API as a factor.

The next thing is to examine the sound samples and make sure that these delays are not actually part of the sounds. This is a common problem with, e.g., mp3 files, which cannot stop and start sounds at arbitrary points (usually a certain amount of silence is introduced at the tail end of an mp3 file when it is converted). Try using the original samples in wav or whatever form they were originally to make sure.

David

When I say delay, I mean the program is actually freezing for a split second which can be seen in pstats as a spike when play is called. All of the sounds are in wav format.
I will try OpenAL and follow up.

Do you get the same problems if the sounds are converted to ogg or mp3 format?

With OpenAL there are no hiccups, but I do not hear anything either. I tried the music box sample it also does not play audio with OpenAL. Clicking the “Close” button in the music box sample causes an assertion:

:interval(error): Event 1 not on active list.
Assertion failed: false at line 898 of c:\work\sp1src_1.7.0\direct\src\interval\cMetaInterval.cxx
Traceback (most recent call last):
  File "C:\work\sp1\Panda3D\direct\showbase\ShowBase.py", line 1664, in __ivalLoop
    IntervalManager.ivalMgr.step()
  File "C:\work\sp1\Panda3D\direct\interval\IntervalManager.py", line 95, in step
    CIntervalManager.step(self)
AssertionError: false at line 898 of c:\work\sp1src_1.7.0\direct\src\interval\cMetaInterval.cxx
:task(error): Exception occurred in PythonTask ivalLoop
Traceback (most recent call last):
  File "Tut-Music-Box.py", line 149, in <module>
    run()
  File "C:\work\sp1\Panda3D\direct\showbase\ShowBase.py", line 2630, in run
    self.taskMgr.run()
  File "C:\work\sp1\Panda3D\direct\task\Task.py", line 502, in run
    self.step()
  File "C:\work\sp1\Panda3D\direct\task\Task.py", line 460, in step
    self.mgr.poll()
  File "C:\work\sp1\Panda3D\direct\showbase\ShowBase.py", line 1664, in __ivalLoop
    IntervalManager.ivalMgr.step()
  File "C:\work\sp1\Panda3D\direct\interval\IntervalManager.py", line 95, in step
    CIntervalManager.step(self)
AssertionError: false at line 898 of c:\work\sp1src_1.7.0\direct\src\interval\cMetaInterval.cxx

It runs fine if I switch it to FMOD.

I will try converting the sounds to OGG.

From searching the forum, apparently the OpenAL crash is due to my build having threads disabled.
Though note that this is not the cause of the original problem as I did test FMOD with a (default) threads enabled build.

Converting to OGG seems to have made the problem worse. I would guess this is because it now has to decode the sounds.

I recompiled again with default thread options but still get the same problems with OpenAL.

What if you compile with the system threads option? That is, with HAVE_THREADS enabled, but SIMPLE_THREADS disabled? I suspect this is what is needed to avoid the OpenAL crash. And it might be related to your problem as well.

David

That configuration results in a crash (running anything it seems). I will try a clean rebuild and see if that makes a difference.

Unhandled exception at 0x1e005f21 (python26.dll) in python.exe: 0xC0000005: Access violation reading location 0x00000004.

Call Stack:
python26.dll!PySys_GetObject()  + 0x5 bytes	
 	[Frames below may be incorrect and/or missing, no symbols loaded for python26.dll]	
 	4e49414d()	
>	libp3dtoolconfig.dll!ConfigVariableSearchPath::reload_search_path()  Line 39 + 0x12 bytes	C++
 	libpanda.dll!Loader::load_file(const Filename & filename={...}, const LoaderOptions & options={...})  Line 203 + 0x19 bytes	C++
 	libpanda.dll!Loader::load_sync(const Filename & filename={...}, const LoaderOptions & options={...})  Line 196 + 0x16 bytes	C++
 	libpanda.dll!Dtool_Loader_load_sync_1221(_object * self=0x04ebc590, _object * args=0x0514a918, _object * kwds=0x00000000)  Line 53258 + 0x12 bytes	C++
 	python26.dll!PyEval_EvalCodeEx()  + 0x93c bytes	
 	04ebcd70()

Nope, wiped out the built directory and compiled clean, same crash still occurs.

Hmm, well, that doesn’t make sense at all; Panda generally runs fine in the system threads build–I run it that way on Windows all the time. The stack trace might suggest a discontinuity between libpanda.dll and libp3dtoolconfig.dll; is it possible that you are inadvertently pulling in the dtool dll from a previous build at runtime?

But all of this is a distraction from the original problem, which is that playing sounds caused a frame chug. I find this strange too. How large a file are we talking about, and what file format are they? Is there anything unusual about the way they are stored and loaded on disk (e.g. are you loading them from a shared network drive, or a USB disk, or something)? Does it happen with any sound files, or just certain ones? If you examine the code in the Python profiler, is there just one function call that appears to be spending all the time?

David

I don’t see where I would have mixed the files. I build using makepanda, then I run a diff program and copy any modified files to their final destination in my SVN working copy. Even if files were being read from the wrong directory, they are exactly the same files. I’m using source from panda CVS with only very minor changes. Maybe I’ll try pulling the latest from CVS, or running directly from makepanda’s built directory.

The sounds are all standard 16-bit 44100Hz mono wav files. There are about 40 of them ranging in length from 1sec to 1min, totalling about 50mb. The purpose is positional environmental audio: bells ringing in the distance, dogs barking, water dripping, and so on. I preload all the sounds, then I have a task that pseudo-randomly plays them. They are loading straight from disk which is an SSD.

What I did was use pstats to keep narrowing down the problem area until I was down to one single line of code which is the “sound.play()” call so this is definitely where the time is being spent.

My guess is that some sounds are being dropped out of memory and then reloaded when play is called. I keep a reference to my sounds at all times, but I guess internally FMOD could be doing whatever it likes.

The problem seems to stem from this line in fmodAudioSound.cxx:

  int streamflag = (size > 250000) ? FMOD_CREATESTREAM : FMOD_CREATESAMPLE;

If I change it to:

  int streamflag = FMOD_CREATESAMPLE;

then there are only tiny (less than 1ms) spikes when playing, which is perfectly reasonable.

So it looks like Panda is telling FMOD to stream any sound bigger than 250000 bytes, which is only 2 or 3 seconds of wav data. Most of my sounds are bigger than that, so FMOD would be trying to stream dozens of sounds at the same time which is pretty nasty!

I would suggest that the interface be changed to provide a choice of load or stream. Perhaps AudioManager.getSound and AudioManager.getStream and then map loader.loadSfx to getSound and loader.loadMusic to getStream… something like that. I’d be happy to do the work if we can agree on an appropriate convention.

If nothing else, it should use audio-preload-threshold, a config variable which already exists for precisely this purpose, instead of a hardcoded number. Then you could easily tweak that config variable according to your game’s particular needs.

That would be a very easy fix to make. :wink:

David

Strange… I’m experiencing the same crash on a recent Panda3D build:
bugs.launchpad.net/panda3d/+bug/1157772

I solved the problem by building with FFMPEG.