Author
Topic: 3D Sound System (Read 194450 times)

I thought I would give a progress update. I am still working out bugs with the new single-thread streaming stuff. I haven't seen anything major that would make me believe I won't be able to get it to work. As with any new system, it is just going to take time to work out all the kinks.

As for the rest of the SoundSystem, I have got quite a bit done today. Switching Javasound over to using Clips instead of SourceDataLines is now totally finished and debugged. Non-streaming sources work perfectly for both libraries, and all functions and combinations of play, pause, rewind, and stop are working. Sounds can reach the end and then be replayed again with no problem. Sample rates are correct for 90% of my test files. Attenuation and panning still work like they should. I have all messages generated in any class routed through the SoundSystemLogger. And finally, I finished renaming classes and varriables. I am starting to get a little burned out, so I think I'll call it quits for today and work on debugging the stream-thread stuff some more tomorrow.

This week, I took a little break from the project, because I got a little burned out on it. Starting tomorrow, I have a 4-day weekend, so I am going to get back to finishing. When I get the stream-thread working properly, I want to spend at least a day running tests to make sure everything is stable and there are no problems. There are a couple of things I want to focus on. First is using multiple sources, streaming and non-streaming, in both OpenAL and JavaSound. The second thing I want to focus on is library-switching and shutting-down, making sure the cleanup() method is clearing everything out in the correct order and avoiding any exceptions. I'll try and have a new release posted by Monday evening.

I'm looking forward to the next release. I'm quite happy with the old version under Windows, but under Linux, i have to use JavaSound, i.e. multiple threads, i.e. jerky behaviour on the 630Mhz cpu that the Linux machine uses.

I discovered a couple of really strange bugs today. I was using one particular .ogg file while working on the Stream Thread, and I got everything working for a single streaming source in both OpenAL and JavaSound (i.e. looping or nonlooping, play, pause, stop, and rewind, and various combinations of them). When I then tried to use some different files and to stream multiple sources at the same time, I found two problems. The first problem is that some sounds are skipping in JavaSound but not in OpenAL (it almost sounds like the stream buffers are playing out of order). The second problem is that for some sounds, I get to the line of code where I read from the AudioInputStream, and then the AudioInputStream.read( byte[], int, int ) method never returns (thus knocking the StreamThread out of commission). The weird thing about this second bug is that the files which are causing the problem were working fine in the second release of SoundSystem, which used the same code for reading them.

I solved the JavaSound skipping bug. The reason this problem popped up is that during the main loop in the Stream Tread, I told it to sleep for a bit between each time it loops through the list of streaming sources (so the thread won't be very CPU intensive). This sleeping created a problem because of the way I was checking if more data needed to be queued:

if( sourceDataLine.available() >= sourceDataLine.getBufferSize() ) // ... queue another chunk of dataThe above statement was only true when sourceDataLine.available() == sourceDataLine.getBufferSize() (i.e. when all queued data was processed). So basically there would be a skip every time all data finished being processed while the Stream Thread was sleeping. The solution to the problem was to change the above code to:

if( sourceDataLine.available() > 0 ) // ... queue another chunk of dataAnother thing that would help if this problem resurfaces (on a slower computer, for example), would be to increase the streaming buffer size, using SoundSystemConfig.setStreamingBufferSize( int ).

As for the AudioInputStream read-hanging problem, I have determined that it is only occuring on two specific .ogg files and only when more than one .ogg are streaming simultaneously. Other than that, I am completely stumped on this problem. I can track the problem down to the exact line of code where it is hanging, and I can not figure out why it would hang there, expecially since it works fine when the file in question is streamed by itself. It doesn't seem likely that this is a thread synchronization problem, but I'm not ruling that out as a possibility. I'm kind of grasping for straws at this point.

--EDIT--I've decided to place this problem on a back burner for now, and finish getting everything else stable and debugged for the next release. I am beginning to think this may be a bug in the j-ogg library (or how I am using it), since it only seems to be happening specifically with .ogg files. For now, I'm putting this in the "incompatibility issues" category along with the sample-rate problem. Basically what it will mean is if anyone wants to stream more than one .ogg file at once, they will have to make sure their files can be streamed together. Eventually I will come back and try to solve this problem, but for now it is rather low-priority for me, since I don't intend to stream more than one file at a time in my game anyway.

The differences in this release are mentioned in my previous posts. If you discover any problems or bugs, let me know and I will work on them. I am going to begin working on the new SoundManager, which will make use of the SoundSystem.

The one thing that I hadn't tested before yesterday's release was the ability to cull and activate sources (methods which SoundManager will use for SourceManagement). I had to change how QuickPlay works, so that instead of immediately playing the new source, it queues a command to play it, so it doesn't bypass the culling/activating. I ran several tests, and there doesn't seem to be any problems with this change. I also made a few other minor tweaks to the default settings, such as increasing the default streaming-buffer size (some higher-quality sounds were skipping in JavaSound).

I also forgot to mention a couple of quick notes for anyone who is switching to a newer release of SoundSystem from the initial release. There have been a couple of changes to JavaSound since then. First of all, rolloff attenuation in JavaSound is much closer to OpenAL's rolloff attenuation, so you will most likely need to change whatever rolloff factor you were using before. Secondly, 3D panning in JavaSound was backwards in the initial release of SoundSystem, so if you had put some type of code to compensate for that bug, it will need to be removed when switching to the new release.

Unless I or someone else using the SoundSystem finds a major problem, this will probably be the last release of SoundSystem for a while, at least until I finish the SoundManager.

Wow, so many problems! The first one sounds like I need to take a serious look at the FileReader class, and perhaps rethink the whole thing rather than trying to fix something that simply doesn't work (I tend to get a little tunnel vision occasionally. This class has been giving me headaches from day one). As for the null channel problem, I haven't encountered it before, but I will try and replicate the problem by running more strenuous tests over a longer period of time. Sounds like a thread synchronization problem to me, but I'm not sure. I should also run more tests different machines, not just my main PC, to see if things break down on less-than-ideal computers.

I suppose I shouldn't have released the library yet - I honestly thought everything was working. I will keep you posted on my progress.

About the stop thing: Maybe i've called stop on an already finished sound. I'm using this for the water pistol sound...it plays as long as you press the button and/or you aren't out of water. If this happens, i call stop. Maybe the sound has been played to the end already? I'm not checking this.

About the stop thing: Maybe i've called stop on an already finished sound. I'm using this for the water pistol sound...it plays as long as you press the button and/or you aren't out of water. If this happens, i call stop. Maybe the sound has been played to the end already? I'm not checking this.

Calling stop() on a finished sound should not cause a problem, but I will look into that. BTW, how was the source originally created, with quickPlay() or createSource()? -- EDIT -- Looking at the stack trace you mentioned above, I'm guessing the source was created with quickPlay().

I looked into the stop() error message problem, and I found one way that error message could occur. Basically what could happen is that if a source finishes playing, and then several other sources play so that the channel iterator gets back to the channel which that first source was playing on, and then if stop() is called on that original source, it checks to see if the source has a channel, which it no longer does, and therefore generates the error message. I believe I can solve this problem by setting the state of the first source to "stopped" at the time a second source is queued to play on the first source's channel. That way the stop() method will simply return since the source's state is already set to "stopped", rather than trying to stop the first source's channel to which there is no longer a handle.

That being said, I do NOT think this is what caused your problem, because as you mentioned, sound output disappeared after you got the error message. That can't be explained by the scenario I mentioned above, so I will continue to try and recreate the problem you experienced. It could be explained by a bug in the channel-iterator code, so I will go back and look at that again. One thing I was wondering, are you creating your sources as "priority" sources or just regular ones? Another thing I should take a second look at is the case where enough priority sources are playing that there are no channels available, and make sure there isn't any bug there.

Thanks for the great feedback, btw. Your descriptions of the bugs are thorough, which is very helpful.

-- EDIT --Oh, one more thing in case you come across it, I fixed a small unrelated bug where an error message about a sound skipping was occasionally being printed when a streaming source reached its end. Simple logic error on my part. I had added this message in last minute, and before I posted the library, I hadn't tested it in the case where a stream actually reached its end.

I've decided to replace the FileReader class. Instead I will utilize org.lwjgl.util.WaveData for pre-loading audio files. I will have to make a choice, however. WaveData loads the entire audio file, which may not be idea for large files that you would normally stream. So my choices are:

1) Use WaveData for all sources (would use more memory for streaming sources and would require large files to be pre-loaded to avoid noticable lag the first time they were played)

2) Use WaveData only for normal sources and keep the current AudioInputStream infrastructure for streaming sources (less compatible, some files sound distorted in OpenAL but not in JavaSound).

Does anyone have any thoughts on which route sounds better? I really haven't decided yet - I can see the benefits of either choice.