[quote]Setting a volume to zero should mean completely silent. However for
about 50% of users the volume of the MIDI source can never become completely silent
(it will get quieter, but not silent). Unfortunately, this is a limitation of the synthesizers
generally available in Java, and can not be avoided until (or if) I write my own MIDI
synthesizer in the future.
[/quote]
The only “easy” solution would be to write a codec plug-in that utilizes the Gervil Software Synthesizer. Unfortunately, that API is licensed by the GPL, which means it wouldn’t be an option for commercial applications or applets or for any project you didn’t want to be restricted by the GPL. The best solution would be for me to write my own software synthesizer, but that would be a major undertaking, and certainly not a priority in the foreseeable future.
Ah! I see.
No problem - I’ll just use some other music format for background music. Between Ogg or one of those tracker formats you added, I’m sure I can find something suitable :o)
Thanks again for a brilliant library!
Peter.
Is there any issue with calling SoundSystem.loadSound or SoundSystem.newStreamingSource multiple times with the same file? I’m asking because I’m wondering if it’s worth it to have a HashMap in my SoundManager class to prohibit this from happening, or if SoundSystem will just ignore duplicates.
Also, should I just be using addSource every time I want to play a sound? I was thinking I would just make a few sources, but because there is a filename parameter in the addSource method, it seems like you’re only supposed to have one sound per source.
For loadSound (and quickPlay) the data from each filename (or identifier if you are loading from a URL instance) is only loaded once. Subsequent calls to loadSound are ignored (SoundSystem has its own HashMap to keep track of what has already been loaded).
For newStreamingSource (and backgroundMusic) nothing is actually loaded until the new streaming source begins playing. While it is playing, SoundSystem reads in chunks of data from the specified file (or URL) and sends them to an available channel to be played. If your single streaming source is set to loop, when the end of stream is reached, it will go back to the beginning and start reading in the data again. (Sorry if that is obvious to you, just making sure you understand what is going on behind the scenes). Thus, calling newStreamingSource multiple times to create multiple streaming sources, and if they are playing simultaneously, SoundSystem WILL BE READING THE DATA MULTIPLE TIMES. If you want to only read the data once or use it multiple times for simultaneously playing streaming sources, you should use the rawDataStream and feedRawAudioData methods instead. This is somewhat more complicated, because you have to come up with some way of managing the data once you read it in (depending on the needs and memory requirements of your particular project). Let me know if you need a simple example to demonstrate one possible way to do this.
[quote=“Demonpants,post:63,topic:33341”]
Each source has only one sound effect associated with it. For normal sources, each audio file is loaded only once and the data is stored in memory. That sample data can be played from as many sources as you like. The source itself is just a few floats and booleans that indicate how and where in 3D space it should play. That information is sent to an available channel when the source is played. Hopefully that makes sense.
You should not have to call addSource every time you want to play a sound. There are a couple of options you can go with. The easiest option is to call quickPlay(), which creates a temporary source, plays it on an available channel, and then removes it from memory (best suited for rapid sound effects in-game, like explosions, gunshots, etc). Another option is to create all the sources you need for each sound effect, and play them when you want them to be played (best suited for menu sounds, ambient looping sounds like crickets, etc).
I saw quickPlay, but from the docs I got the feeling that it would also unload the sound file after playing. I don’t want to be loading and unloading the same sound a bazillion times, so I figured I shouldn’t be using that.
As for the sources - assumedly then I should have one source per entity, or something along those lines? i.e. each unit can play one sound at a time. Is there a way, then, to change the sound associated with a source? Like if I wanted to play a shoot sound and then an explode sound from the same source.
If quickPlay just creates and removes a source from memory, I will probably just go with that instead (assuming the sound files stay in memory), as that should be plenty cheap enough.
Others have said that as well. I need to clarify this point a little better in the guide.
[quote=“Demonpants,post:65,topic:33341”]
In the case of shooting and explosion sounds, I would either do it with two sources located at the same position, or easier with two calls to quickPlay. Currently, there isn’t a simple way to change the sample data associated with a normal source. This is because I made an assumption way back in the beginning of this project that each source would be associated with a single sound effect (this grew out of the underlying libraries OpenAL and JavaSound which also make this assumption in their “Source” and “Clip” entities). Much later on, after I eventually separated and defined the two concepts of “Source” and “Channel”, I just continued to make that original assumption, even though it is really no longer a restriction. I could go back and change things a bit to allow this, but I’m not sure if there would be much demand for it. Most people use quickPlay, which was designed for easily playing sound effects in 3D without having to constantly worry about source management.
[quote=“Demonpants,post:65,topic:33341”]
Yes, quickPlay only creates and removes the source information (which is a few floats and booleans). The sample data stays in memory once loaded until unloadSound is called (or cleanup to shut down).
I had another thought - I could add a method which would allow you to specify the synthesizer to use if you didn’t want to go with the default Java synthesizer. That way you could tell SoundSystem to use the Microsoft SW synthesizer if it exists, which would eliminate the volume problem for all Windows users (90% of your clients). Not a perfect solution (half of the remaining Linux, Mac, Solaris, etc users would still experience the volume problem), but it might be a reasonable work-around.
Thanks for the help, that makes more sense.
I have an issue getting it to work, though, probably because it can’t find the sound files. How does it browse for them? How do I search via File or classpath? I see I can put http in there to look for an online resource, but no clear differentiation between local files and things inside the JAR (classpath).
EDIT: Nevermind, I figured it out. But now I have a different problem.
Starting up SoundSystem...
Initializing LWJGL OpenAL
(The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org)
OpenAL initialized.
Error in class 'ChannelLWJGL OpenAL'
Error creating buffers in method 'preLoadBuffers'
ERROR MESSAGE:
ByteBuffer is not direct
STACK TRACE:
org.lwjgl.BufferChecks.checkDirect(BufferChecks.java:105)
org.lwjgl.openal.AL10.alBufferData(AL10.java:956)
paulscode.sound.libraries.ChannelLWJGLOpenAL.preLoadBuffers(ChannelLWJGLOpenAL.java:301)
paulscode.sound.libraries.SourceLWJGLOpenAL.preLoad(SourceLWJGLOpenAL.java:676)
paulscode.sound.Source.stream(Source.java:845)
paulscode.sound.StreamThread.run(StreamThread.java:129)
[quote]Error in class ‘ChannelLWJGL OpenAL’
Error creating buffers in method ‘preLoadBuffers’
ERROR MESSAGE:
ByteBuffer is not direct
STACK TRACE:
org.lwjgl.BufferChecks.checkDirect(BufferChecks.java:105)
org.lwjgl.openal.AL10.alBufferData(AL10.java:956)
paulscode.sound.libraries.ChannelLWJGLOpenAL.preLoadBuffers(ChannelLWJGLOpenAL.java:301)
paulscode.sound.libraries.SourceLWJGLOpenAL.preLoad(SourceLWJGLOpenAL.java:676)
paulscode.sound.Source.stream(Source.java:845)
paulscode.sound.StreamThread.run(StreamThread.java:129)
[/quote]
That is the incompatibility that was introduced after LWJGL decided to stop supporting indirect buffers in their binding of OpenAL. This is fixed in the upcoming release. I’m doing some final clean-up work and hope to put it out later this week.
If you want to use a temporary fix in the mean time, make the following changes:
in LibraryLWJGLOpenAL.loadSound:
// AL10.alBufferData( intBuffer.get( 0 ), soundFormat,
// ByteBuffer.wrap( buffer.audioData ),
// (int) audioFormat.getSampleRate() );
// CHANGE TO:
AL10.alBufferData( intBuffer.get( 0 ), soundFormat,
(ByteBuffer) BufferUtils.createByteBuffer(
buffer.audioData.length ).put(
buffer.audioData ).flip(),
(int) audioFormat.getSampleRate() );
in ChannelLWJGLOpenAL.preLoadBuffers:
//byteBuffer = ByteBuffer.wrap( bufferList.get(i), 0,
// bufferList.get(i).length );
//CHANGE TO:
byteBuffer = (ByteBuffer) BufferUtils.createByteBuffer(
bufferList.get(i).length ).put( bufferList.get( i ) ).flip();
in ChannelLWJGLOpenAL.queueBuffer:
//ByteBuffer byteBuffer = ByteBuffer.wrap( buffer, 0, buffer.length );
//CHANGE TO:
ByteBuffer byteBuffer = (ByteBuffer) BufferUtils.createByteBuffer(
buffer.length ).put( buffer ).flip();
in ChannelLWJGLOpenAL.feeRawAudioData:
//ByteBuffer byteBuffer = ByteBuffer.wrap( buffer, 0, buffer.length );
//CHANGE TO:
ByteBuffer byteBuffer = (ByteBuffer) BufferUtils.createByteBuffer(
buffer.length ).put( buffer ).flip();
Cool, thanks. If it’s done later this week (I’ll hold you to that! :)) then I’ll check back on friday - but I’ll need it implemented by Sunday for sure, so if it’s not ready on Friday I’ll just do the hotfix changes.
Just saw this reading through some recent posts having just got back from holiday …
This statement isn’t exactly true. Gervill is GPL with Classpath Exception, as it’s part of OpenJDK. That means you can easily distribute it with any project whatever the licence. Might have to keep it in a distinct JAR mind you (never been quite sure about that!)
[quote=“paulscode,post:69,topic:33341”]
Clean-up is taking a bit longer than I anticipated. I’ll have this thing ready soon…
No worries. Java sound is fine for me in the mean time.
Sound System, Major Update, Beta Release
Sound System
Sound System jPCT
JavaSound library pluggin
LWJGL OpenAL library pluggin
JOAL library pluggin
WAV codec pluggin
JOgg codec pluggin
JOrbis codec pluggin
IBXM codec pluggin
I am calling this a beta release, because this has been one of the biggest overhauls of the library yet, and I fully expect there to be bugs. I’ll post additional updates in the coming days and problems are discovered. I’m working on updating the tutorials as well.
There have been extensive changes since the last release. I’ll try and explain all of them quickly.
The big/important changes:
1) I fixed the incompatibility introduced back in LWJGL 2.3 when they stopped supporting indirect buffers.
2) I added a Doppler effect algorithm to LibraryJavaSound using sample-rate controls. Note: normal sample-rate ranges in JavaSound are 4KHz - 48Khz, so this can effect how well certain sound effects do with the Doppler effect.
3) I implemented a standard interface for Doppler effect, which can now be used with all library plug-ins. There are also new Doppler-effect interface methods in SoundSystemJPCT with SimpleVector parameters in jPCT’s coordinate system.
4) I implemented a new stream-listener interface, which enables listening for End of Stream events (most useful for playing a sequence of music clips)
5) I added in an intelligent auto-search for common MIDI synthesizers when the default is missing. This makes MIDI possible on non-Sun Java versions (such as OpenJDK)
6) I added the ability to create normal sources from raw PCM data. Most useful for playing procedurally-generated sound effects.
7) I added the ability to check the millisecond position of any playing source
8) I added a Mixer ranking system, and an intelligent Mixer-picking based on the functions compatible with each Mixer. This allowed an intelligent work-around for the Java Sound “webcam chosen as default Mixer” bug, as well as the fact that non-Sun Java (such as OpenJDK) may not have the “Java Sound Audio Engine” mixer available.
Additional changes:
1) I fixed a reverse-byte-order bug in CodecIBXM which caused some sounds to be loud and scratchy.
2) I fixed a bug where switching libraries caused pre-loaded sounds not to re-load.
3) I fixed various bugs when running 64-bit Java plug-in for Firefox on Linux. There are still more (see below).
4) I added an error message when attempting to load a missing file from the JAR. Before it acted as if there were no problem if a file was not present.
5) I added in a workaround for the Java Sound bug where a random InterruptedException is sometimes thrown when trying to access the default MIDI sequencer.
6) I added a varriable to SoundSystemCongfig for specifying which MIDI synthesizer to try first
7) I fixed the message-flooding bug that would happen when Mixer controls are not available.
8) I fixed various potential thread-synchronization bugs.
There are still several know issues with 64-bit Java on Linux which I am currently working on, including:
1) No MIDI
2) Random blocking for a half-second every few seconds
3) No sound from Java Sound when switching from OpenAL to Java Sound on the fly
4) JFrame ‘paint’ method causes system graphics to go wacky when playing JavaSound, and can even result in a complete OS lock-up requiring reset.
Please let me know if you run into any problems, and I will work on correcting them right away.
Thanks a lot.
But I think your download links don’t point to the new files (except the docs) so I can’t try the new features.
Is there another download link?
edit: I tried the links from your homepage, SoundSystem.jar is from nov last year. (unless I’m terribly stupid regarding downloading files)
[quote=“Hansdampf,post:75,topic:33341”]
Thanks for pointing that out. I tried re-uploading the files, and still getting the old version when I download them ??? I have no idea why the old version is being cached and sent instead of the new version. It must be a bug with either my FTP program or the server, I’ll have to try and track it down.
In the mean time, I changed to links to point to the 21 August version archive directory instead of the “latest version” directory, and that seems to be working. Give it a shot and let me know if you are still getting the old version.
Thanks. I’m going to try it as soon as possible, maybe tonight. I let you know what happens.
So far I been running the beta without issues on windows 7. Maybe a few skips on high cpu usage now, but that might be the hardware mode…
[quote=“zammbi,post:78,topic:33341”]
I’ll look into this (could potentially be caused by poor synchronization between the StreamThread and CommandThread). You could also try increasing the streaming buffer size or number (I’ve had problems in the past with the fact that JOrbis is quite slow, and had to tweak the numbers a bit to avoid skipping when streaming from .ogg files.)
[quote]I’ll look into this (could potentially be caused by poor synchronization between the StreamThread and CommandThread). You could also try increasing the streaming buffer size or number (I’ve had problems in the past with the fact that JOrbis is quite slow, and had to tweak the numbers a bit to avoid skipping when streaming from .ogg files.)
[/quote]
Ah righto, well its rare, so I haven’t taken much notice to it. But I’m using XM files if that helps.