I made TinySound for fun and potentially for use in my own projects. Have a look if you’re interested. If you find any bugs, please submit them to the issue tracker on the Github.
I read the example, and it’s really simple!
I’m glad you think so. That was the goal after all. That is, unless you only mean that the example isn’t sufficient for understanding how to use the library.
Really nice and simple library, I like it
Instead of an init() method, you could simply put that in a static block:
static {
//this stuff is called when this class is loaded into memory
}
But then you can’t shutdown() and re-init() …
O__o why would you shutdown then re-init?
That’s a reasonable idea, but I like the symmetry of having to initialize and shutdown.
The init method does a lot of side-effectful things including starting up the mixer. It’s probably not a good idea to put things like that into a static initializer. Also, like kuusisto says, you’re also able to shut it down and presumably even start it back up, something I could reasonably see doing if you did something like switch the output device.
Ah OK
Hi
The intention is noble but there are already a lot of “tiny” libraries wrapping only JavaSound. I don’t want to discourage you, such a project has a pedagogical interest as it helps you to learn lots of things about JavaSound but I don’t really see how it could be useful outside this scope. You wrap only JavaSound, therefore your library inherits its limitations. Your library just has less features than Paul Lamb Sound Library which is quite modular (it’s subdivided into several plugins, you can take only the useful parts, it is not heavy), you have no support of OpenAL. I have looked at your source code and I’ve found some typical “beginner” mistakes. For example, the internal format used by TinySound is hardcoded, what do you do if this one is not supported on a given platform? All your helpers won’t work. You seem to use the default mixer, you don’t even try to get the “best” one, the one with the best support of mixing. Good luck. Thanks for sharing your source code.
Like I said, I did this mostly for fun and I’m not trying to compete with Paul’s library. Also, I don’t see having fewer features as an inherent flaw unless you need those features, in which case you would use something that has those features. By no means is TinySound supposed to be feature-rich. It’s just supposed to be really simple.
Edit:
I should also mention for others who may be reading this that TinySound doesn’t support only one format as was suggested, but it does store all audio data in memory in a single format. There is at least some attempt to convert other formats to the internal format. For those interested, the internal format is 44.1kHz, 16-bit stereo.
Don’t be discouraged by gouessej – that’s an impressive little library you’ve got. At the very least, the source code provides an excellent starting point for those wanting to write a software mixer but don’t have a clue where to begin. And since this library is basically just sending PCM data, I don’t see why it couldn’t be extended to support OpenAL.
Paul’s library is excellent but it’s by no means the holy grail of java sound. Have you looked at the source code? It’s pretty brutal; tons of repetition and lots of unnecessary bloat.
It’s a great library if you plan to support a wide variety of systems because (a) it’s thread-safe and (b) it can use Java Sound as a fallback. But say you are programming a simple OpenGL game using a single thread – these bonuses are not really necessary, and SoundSystem just becomes a rather bulky wrapper around OpenAL. Because of the compatibility with Java Sound, we lose some nice features of OpenAL like synchronized playback and EFX. And because the actual AL commands are queued and processed in another thread, you can run into issues like this:
SoundSystem.play(source);
boolean b = SoundSystem.playing(source); <-- returns false
On the other hand, Paul’s decoders are awesome – I might use them alongside my own thin OpenAL wrapper for my game.
+1 You’ve got the start of a nice, simple API there. There’s a definite need for a robust but simple software mixing JavaSound solution around here (not sure if Paul Lamb’s library finally has this yet?). I did make a promise a short time ago to fork out the software mixing code from Praxis, but paid work kind of got in the way, and it’s never going to be as simple a solution as this anyway.
I particularly like the look of the code for your UpdateRunner (caveat - not tried it yet!) - seems you’re writing to the audio line without blocking on write()? This is the way to get decent performance out of JavaSound.
You say that like it’s a good thing! Naive synchronization is one of the main causes of bad performance in audio libraries. Worth reading this article - http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing
In particular with regards to the TinySound library I’d suggest getting rid of all the synchronized methods in Mixer and instead passing events into your audio thread by way of a ConcurrentLinkedQueue. Just pass in a Runnable to manipulate the lists if you’re not in the audio thread, draining the queue on each read().
Best wishes, Neil
Thanks for the feedback, everyone.
I was reluctant at first to introduce synchronization in the mixer and I would certainly consider some amount of redesign if there were enough complaints about latency, but at this point I’m not sure there is a need. I didn’t really consider OpenAL support as users would then need to distribute native libraries with their projects, making TinySound more complex. Beside that, TinySound was never meant to be a 3D sound library, so OpenAL support seemed like overkill. There may be other reasons for support, however, in which case I may eventually consider it.
Ultimately, my thought was that TinySound might be used in projects at the scale of Ludum Dare entries or similar.
Edit:
Of course, I don’t want to make it sound like TinySound couldn’t be used for more complicated projects than those of Ludum Dare scale. It could be used anywhere that more advanced audio features are unnecessary and/or where you just want to get sounds working quickly.
I have never tried to discourage him and I wrote his library has a pedagogical interest. Please avoid such false accusations.
JavaSound is by no means the holy grail of sound in Java. If you really think Paul’s source code contains tons of repetition, why haven’t you suggested him some improvements?
[quote]If you really think Paul’s source code contains tons of repetition, why haven’t you suggested him some improvements?
[/quote]
Because my suggestion would be “rewrite the library with better coding standards.” Truth is, it doesn’t really matter since most of the users seem happy enough with the rather limiting SoundSystem singleton.
Thanks for sharing this. I love the simplicity.
Just a quick nooby question if I may. I’m just working on sound for my first game, and decided to use your library to make things easier. However I keep getting the following exception when I attempt to load a new sound. Here’s the callstack:
Exception in thread "Thread-4" java.lang.NegativeArraySizeException
at kuusisto.tinysound.TinySound.readAllBytesTwoChannel(TinySound.java:412)
at kuusisto.tinysound.TinySound.readAllBytes(TinySound.java:365)
at kuusisto.tinysound.TinySound.loadSound(TinySound.java:335)
at kuusisto.tinysound.TinySound.loadSound(TinySound.java:310)
at brickout6.Game.LoadContent(Game.java:95)
at brickout6.Game.access$100(Game.java:28)
at brickout6.Game$1.run(Game.java:61)
and the code fragment it fails at:
private static byte[][] readAllBytesTwoChannel(AudioInputStream stream) {
//read all the bytes (assuming 16-bit, 2-channel)
int numBytesPerChannel = (int)stream.getFrameLength() *
(stream.getFormat().getFrameSize() / 2);
byte[] left = new byte[numBytesPerChannel];
Now, I get that a NegativeArraySizeException is telling me that numBytesPerChannel is returning an invalid array index. but I’m not quite sure why I should be getting it in this case? Checking the code, it performs multiple data validity/null checks on the loaded file prior to reaching this line so if there was something wrong with say, the path to the file, or the integrity of the file, surely this would be flagged sooner by the built-in error handling?
Sorry for the nooby question as I’m very much a beginner at all this. Any idea what’s going on here?
This isn’t a nooby question; I think you’ve just encountered a bug in my code. Either the frame length is negative or the frame size is. I would bet that the frame size is -1, meaning that your audio file has no specified frame size. I’m not sure how I should handle that in the code, but I guess if it’s linear PCM, which it should be if it reaches this point in the code, then the frame size is just the number of bytes per sample multiplied by the number of channels. I’ll open an issue on the TinySound Github page to take care of this ASAP. It would also help a lot if I could get a copy of your audio file for testing, but since it’s an asset I understand if that isn’t possible.
You’re casting stream.getFrameLength() to an int, meaning that if the value of the long was greater than 2147483647 ((2^31)-1), the value will become a negative number.
True. I should check for that too (I’ll open an issue). Still, that would mean that the audio file being loaded is over 13 hours long, so I feel like that’s a less likely explanation for this specific scenario.