kuusisto
|
 |
«
Posted
2012-03-10 05:06:56 » |
|
https://github.com/finnkuusisto/TinySoundI 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.
|
|
|
|
ReBirth
|
 |
«
Reply #1 - Posted
2012-03-10 05:24:31 » |
|
I read the example, and it's really simple!
|
|
|
|
kuusisto
|
 |
«
Reply #2 - Posted
2012-03-11 14:26:40 » |
|
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.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
ra4king
|
 |
«
Reply #3 - Posted
2012-03-11 15:42:40 » |
|
Really nice and simple library, I like it  Instead of an init() method, you could simply put that in a static block:
|
|
|
|
davedes
|
 |
«
Reply #4 - Posted
2012-03-11 15:48:08 » |
|
Really nice and simple library, I like it  Instead of an init() method, you could simply put that in a static block: But then you can't shutdown() and re-init() ... 
|
|
|
|
ra4king
|
 |
«
Reply #5 - Posted
2012-03-11 15:57:41 » |
|
O__o why would you shutdown then re-init?
|
|
|
|
kuusisto
|
 |
«
Reply #6 - Posted
2012-03-11 16:33:06 » |
|
Really nice and simple library, I like it  Instead of an init() method, you could simply put that in a static block: That's a reasonable idea, but I like the symmetry of having to initialize and shutdown.
|
|
|
|
sproingie
|
 |
«
Reply #7 - Posted
2012-03-11 19:10:02 » |
|
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.
|
|
|
|
ra4king
|
 |
«
Reply #8 - Posted
2012-03-11 19:58:58 » |
|
Ah OK 
|
|
|
|
gouessej
|
 |
«
Reply #9 - Posted
2012-03-11 22:07:06 » |
|
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.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
kuusisto
|
 |
«
Reply #10 - Posted
2012-03-11 22:32:49 » |
|
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.
|
|
|
|
davedes
|
 |
«
Reply #11 - Posted
2012-03-12 05:32:44 » |
|
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: 1 2
| 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.
|
|
|
|
nsigma
|
 |
«
Reply #12 - Posted
2012-03-12 09:53:30 » |
|
Don't be discouraged by gouessej -- that's an impressive little library you've got.
+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. It's a great library if you plan to support a wide variety of systems because (a) it's thread-safe ...
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-nothingIn 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
|
Praxis LIVE - hybrid visual IDE for (live) creative coding
|
|
|
kuusisto
|
 |
«
Reply #13 - Posted
2012-03-12 16:24:06 » |
|
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.
|
|
|
|
gouessej
|
 |
«
Reply #14 - Posted
2012-03-12 21:02:54 » |
|
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. I have never tried to discourage him and I wrote his library has a pedagogical interest. Please avoid such false accusations. 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. 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?
|
|
|
|
davedes
|
 |
«
Reply #15 - Posted
2012-03-12 22:14:04 » |
|
If you really think Paul's source code contains tons of repetition, why haven't you suggested him some improvements? 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.
|
|
|
|
dimension17
Junior Newbie Medals: 1
|
 |
«
Reply #16 - Posted
2012-03-14 15:20:08 » |
|
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: 1 2 3 4 5 6 7 8
| 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: 1 2 3 4 5
| private static byte[][] readAllBytesTwoChannel(AudioInputStream stream) { 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?
|
|
|
|
kuusisto
|
 |
«
Reply #17 - Posted
2012-03-14 16:20:00 » |
|
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: 1 2 3 4 5 6 7 8
| 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: 1 2 3 4 5
| private static byte[][] readAllBytesTwoChannel(AudioInputStream stream) { 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.
|
|
|
|
ra4king
|
 |
«
Reply #18 - Posted
2012-03-14 17:27:44 » |
|
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.
|
|
|
|
kuusisto
|
 |
«
Reply #19 - Posted
2012-03-14 17:34:27 » |
|
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.
|
|
|
|
dimension17
Junior Newbie Medals: 1
|
 |
«
Reply #20 - Posted
2012-03-14 19:54:30 » |
|
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.
No probs at all. It was just a random .wav file that I downloaded to test drive the library. Grab it here http://dnfw.org/hl/sound/kart/coin.wavHope it helps 
|
|
|
|
kuusisto
|
 |
«
Reply #21 - Posted
2012-03-14 20:36:17 » |
|
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.
No probs at all. It was just a random .wav file that I downloaded to test drive the library. Grab it here http://dnfw.org/hl/sound/kart/coin.wavHope it helps  Thanks. It would appear that, after conversion to the internal format using Java's AudioSystem class, the getFrameLength() function is returning -1. I can read all the bytes into a list instead of precomputing, but perhaps someone else knows why this is the case. It doesn't appear to be documented. I'm at work right now, but I'll try to fix this sometime tonight.
|
|
|
|
kuusisto
|
 |
«
Reply #22 - Posted
2012-03-15 04:55:05 » |
|
I 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.
No probs at all. It was just a random .wav file that I downloaded to test drive the library. Grab it here http://dnfw.org/hl/sound/kart/coin.wavHope it helps  Thanks. It would appear that, after conversion to the internal format using Java's AudioSystem class, the getFrameLength() function is returning -1. I can read all the bytes into a list instead of precomputing, but perhaps someone else knows why this is the case. It doesn't appear to be documented. I'm at work right now, but I'll try to fix this sometime tonight. It looks like this conversion is supported since Java 7 and the file simply won't load in 6. Since I'm not entirely convinced yet that this isn't a bug, I've just pushed changes that check for negative frame length and don't load the sound if so. Unfortunately, that means you'll need to use a different audio file to play around. For generating nice, simple sound effects I highly recommend as3sfxr ( http://www.superflashbros.net/as3sfxr/), which is a Flash port of Dr. Petter's sfxr ( http://www.drpetter.se/project_sfxr.html).
|
|
|
|
dimension17
Junior Newbie Medals: 1
|
 |
«
Reply #23 - Posted
2012-03-15 10:38:02 » |
|
Wow, that's a really useful tool. Thanks! 
|
|
|
|
philfrei
|
 |
«
Reply #24 - Posted
2012-03-15 22:17:23 » |
|
Anyone with half a brain can take a sound file and load it into Audacity (free) and convert it to the format required by the sound service. I see no reason why conversion has to be a requirement, as long as the game can play the sound correctly.
I spent some time looking at Paul Lamb's sound system and was overwhelmed. Modular or not, it is like a couple phone books is size. I was hoping to learn a thing or two but mostly got lost. So I can sympathize with the desire to make a small sound system.
Based on things I've heard from folks here, though, and on my own experiences, a web game pretty much can't use .wav files other than a few short sf/x, because of the download time. Some sort of compression is needed and Ogg/Vorbis is preferred. I think if you can figure out a way to support Ogg/Vorbis, you will have solved a big obstacle. Paul's system does so, and is to be recommended for that.
I couldn't figure out how to do some "fancy" things I wanted to do, like looping (via alternating two playbacks) longer Ogg/Vorbis files without getting memory leaks. Also, the very act of playing a compressed sound is significantly more costly than playing a PCM format file. (Was looking at decompressing and storing as .wav on the client, but that gets into a lot of hoohah about Signing.)
Hopefully you will have better luck if you decide to tackle this. For myself, I've decided to ditch Ogg/Vorbis and to generate my sounds on the fly. I can do this because I have a lot of background with FM and it is pretty efficient for sound synthesis.
Best of luck with your project!
|
|
|
|
davedes
|
 |
«
Reply #25 - Posted
2012-03-15 22:35:09 » |
|
philfrei - Decoding an OGG to PCM data can be done relatively painlessly with libraries like JOrbis. Alternatively, you could use Slick-Util's OGGInputStream, or Paul's OGG decoders on their own. Then you don't need to worry about how to play the compressed data, or having to sign anything, or storing WAV files on the user's machine, or whatever you were trying to do before.
|
|
|
|
philfrei
|
 |
«
Reply #26 - Posted
2012-03-15 23:23:55 » |
|
Thanks. JOrbis didn't work 100% for me. Maybe it reflects more on my competence than the library. I was having memory leak problems, using code based on this tutorial: http://www.jcraft.com/jorbis/tutorial/Tutorial.html Perhaps there is a better example to use for implementing. Or I didn't modify the code in a good way for the degree of replays I was trying to build into the app in question. For sure, others have had good results with JOrbis. And I have a very appealing FM workaround, so I haven't looked back to figure out where I went wrong. But to stay on topic, a big plus for TinySound would be to allow use of JOrbis, and the above link has both a program that works and lots of references & useful links, if the OP doesn't already know about them and is interested. 
|
|
|
|
kuusisto
|
 |
«
Reply #27 - Posted
2012-03-16 16:34:07 » |
|
But to stay on topic, a big plus for TinySound would be to allow use of JOrbis, and the above link has both a program that works and lots of references & useful links, if the OP doesn't already know about them and is interested.  This isn't a bad idea. I like that JOrbis is pure java (no native libraries to distribute) and wouldn't require me to change my license. I'll look into this. On the other hand, it might be kind of interesting/fun to write my own Vorbis decoder, but that would perhaps take a different level of motivation.
|
|
|
|
|
kuusisto
|
 |
«
Reply #29 - Posted
2012-03-18 16:59:08 » |
|
I've updated TinySound for better format conversion and lag prevention (frame-skipping). I'm working on Vorbis support using Javazoom's VorbisSPI library. It should work right out of the box, but something is off. I hope to have that working by the end of today.
|
|
|
|
|