stahlworks technologies
 
 
 
 
 
 
 
 
 
 
Fast and Compatible Sound Loading within Java

a tutorial with free source code for download.

just like fast image loading, fast sound loading uses compression and background loading. bundling and loading on demand are so far not covered by d3caster, more about that later.

compression

In the origin, sound consists of .wav files, in the case of d3caster encoded with 32 kHz, 16 bits. All sounds together make up about 5 MBytes of data - far too much to load them in their original format.

The new state-of-the-art sound compression format is Ogg Vorbis. Just like being made for online games, it provides a great sound quality AND maximum compression. I researched what Java implementations are available, and concluded for myself that the best and easiest implementation is JOrbis from JCraft, also because their package contained a nice sample source, the JOrbisPlayer, showing quick and easy how the stuff is used. Still, it took me half a day to turn this into glue code bringing JOrbis loading and the demo game's sound system together. The result can be found in d3sound2.java, method "loadOgg()".

To create .ogg from .wav, there are quite a number of free tools available. I'm using OggEnc. For example, the command "oggenc --resample 32000 -q0 %1.wav" encodes a .wav of any sample rate to an .ogg with 32 kHz, at maximum compression (q0), which still provides great sound quality.

background loading

Again, the idea is simple but effective: from a total of 17 sounds, we only load the most important 4 ones immediately (-> loadSounds()), and the others after the game has started, step by step (-> stepSoundLoading()).

There is probably some room left for optimization: stepSoundLoading() isn't done in a separate thread, and the importand sounds aren't bundled within a JAR. Nevertheless, as it is, the supplied demo game loads fast enough.

compatible?

Of course, you could now keep it that way - just supply a game for Java 2 sound, and that's it. However, there are still some browsers out there which do NOT speak Java JDK 2. Within these browsers, sound is coded completely different, using Sun's Audioclip classes. I won't go into detail about this, it's all done in d3sound1.java, so you may check the source directly.

But when do we use Java 2 version, and when Java 1? At first, I compiled two different engines, leading two 2 different binaries, installation directories, and startup html files. A painful and uncomfortable process. The final solution was to create an abstract interface, the d3soundsys, and to turn d3sound1 and d3sound2 into implementations of this interface. Now, in the main engine (d3caster.java), we can simply try it:


   d3soundsys sif = null;
   boolean bJava2Attached = false;
   public void attachSound() 
   {
      System.out.println("trying Java 2 Sound:");
      try {
         sif = new d3sound2();               // trying,
         sif.attach(this, urlbase, bLocal);  // trying...
         bJava2Attached = true;
         return;
      }  catch (Throwable e) {
         // and if it fails ...
         System.out.println(e.getMessage());
         System.out.println("Java 2 sound failed, retrying on Java 1");
      }  // ... fall through and retry.
      System.out.println("trying Java 1 Sound:");
      try {
         sif = new d3sound1();
         sif.attach(this, urlbase, bLocal);
         return;
      }  catch (Throwable e) {
         System.out.println(e.getMessage());
         System.out.println("Java 1 sound failed");
      }
   }

An old Java JDK 1 will already fail at the statement "new d3sound2()", as it won't be able to load Java 2 bytecode. But that's no problem - in this case, the system simply falls through to use Java 1 sound.

As a result, with have an all-compatible sound system, which detects automatically the environment it is running on.