My way of playing wav files as sound effects (in simple Java2D)

Hi, quite analogous to the static class that is being widely used to accelerate images in your gfx card, I also made a static class which plays sampled media sounds, like .wav files

All you have to do is put this class in your project tree, initialize all the sounds by calling this once anywhere: SoundHandler.get().loadSoundFx();

and whenever you need to play a sound just call: SoundHandler.get().play(“boom1”);

I am also pretty much a beginner, so I hope other beginners can make good use of this class too. If you have any questions or comments, reply to this thread, or email me at k.verbist@student.tudelft.nl

I am also interested in what the advanced programmers have to say about this class.

/*

  • SoundHandler.java
  • Created on May 6, 2006, 1:39 AM
  • To change this template, choose Tools | Options and locate the template under
  • the Source Creation and Management node. Right-click the template and choose
  • Open. You can then make changes to the template in the Source Editor.
    */

package tankpwnage;

import java.util.HashMap;

import java.io.File;
import java.io.IOException;

import javax.sound.sampled.*;

/**
*

  • @author Cyclonis Delta
    */
    public class SoundHandler implements LineListener {

    private static final int BUFFER = 128000;

    private static SoundHandler instance = new SoundHandler();

    private HashMap soundFiles;

    public static SoundHandler get() {
    return instance;
    }

    public void loadSoundFx() {
    soundFiles = new HashMap();
    File directory = new File("./sound/fx");
    File[] files = directory.listFiles();
    for (int i=0;i<files.length;i++) {
    if (files[i].isFile()) {
    // This is a sound effect
    String filename = files[i].getName();
    String path = “./sound/fx/”+filename;
    File theFile = new File(path);
    int dot = filename.indexOf(".wav");

             String ref = filename.substring(0, dot);
             
             AudioInputStream audioInputStream = null;
             Clip clip = null;
             
             
             try {
                 audioInputStream = AudioSystem.getAudioInputStream(theFile);
                 if (audioInputStream != null) {
     	AudioFormat	format = audioInputStream.getFormat();
     	DataLine.Info	info = new DataLine.Info(Clip.class, format);
     	try
     	{
     		clip = (Clip) AudioSystem.getLine(info);
     		//clip.addLineListener(this);
     		clip.open(audioInputStream);
                             soundFiles.put(ref, clip);
     	}
     	catch (LineUnavailableException e)
     	{
     		e.printStackTrace();
     	}
     	catch (IOException e)
     	{
     		e.printStackTrace();
     	}
     	
                 }
             }
             catch (Exception e) {
                 e.printStackTrace();
             }
             
                             
         }
     }
    

    }

    public void update(LineEvent event)
    {
    if (event.getType().equals(LineEvent.Type.STOP))
    {
    Clip clip = (Clip)event.getLine();
    clip.setFramePosition(1);
    }
    else if (event.getType().equals(LineEvent.Type.CLOSE))
    {
    /*
    * There is a bug in the jdk1.3/1.4.
    * It prevents correct termination of the VM.
    * So we have to exit ourselves.
    */
    System.exit(0);
    }
    }

    public void play(String ref) {

     Clip clip = (Clip) soundFiles.get(ref);
     if (clip.isRunning()) {
         clip.stop();
         clip.setFramePosition(1);
     }
     clip.addLineListener(this);
     //while (!clip.isRunning()) {
     clip.start();
     //}
    

    }

}

Hi, i am a newbie and i am also interesting in your code. I think it is very easy to use.
However, i have two questions about the code.
1> When u have many wav files, does it need too much memory?
2> While playing many files together, does it work well?

Thanks!

Hmm i ve noticed that when u call the loadSoundFx() u always do soundFiles = new HashMap();
So if it gets called more than once it will spend unnecessary time loading again…It would be better to initialize it in singleton’s constructor…

Hi,

Yes, you could load it with the singleton, as long as you load it only once. I load it once when the game starts, I think that is ok too.

I didn’t notice a significant drop in frame rate, so I guess it does not take a lot of memory. my game plays around 400 fps, with or without the sounds

I did notice that with a lot of sounds, sometimes a particular sound gets skipped or played a little too late. If someone manages to fix that in this class, I’d be happy to see it

400 fps? Are u sure about that…sounds a bit too much :wink:

hi,

Yeah I get around 400 fps when I only let the thread sleep for 1 ms I used to get only a maximum of 60 but I changed my code according to that hardware acceleration tutorial for Java and it boosted all my game’s FPS up to around 400.

what hardware accelation tutorial for Java? Tnx.

U see…i m really not sure that your results are correct. Especially if u r using Thread.sleep() which is very innacurate…well…mayb u r testing on linux tho…more accurate there than on win…

400 FPS with a sleep of 1 ms means you take only 1ms (plus a tiny bit) to paint the screen. I can’t see how that’s possible whatever acceleration (OGL or direct draw) you’re using, unless you don’t paint the whole screen & just re-render the parts that changed.

I think sleep gaurantees a minimum that is accurate, but the maximum is innaccurate. Regardless, 400fps does seem too high.

This is how you calculate FPS:

float avMillisBetweenUpdates = (float)((cumulativeNanosBetweenUpdates)/(counter*1000000f));
// where cumulativeNanosBetweenUpdates is nanos over which we’re measuring framerate. (nanosecond time from System.nanoTime() )
// counter is number of frame draws over the above time.

float fps = (float)(1000/avMillisBetweenUpdates);

If 400 FPS is possible & you repaint the whole screen, I’d like to know how too :slight_smile:
Keith

if you sleep 1ms every tick and you have 400 fps, that would mean you sleep 400ms in one second and on the rest 600 ms you manage to render 400 fps… not likely :wink:

Hi,

I was gone for a long time, and I am back into making some games in Java ;D

Yes, I did manage to get 400 fps.

I used the following code to accomplish this:

http://www.cokeandcode.com/info/showsrc/showsrc.php?src=../spaceinvaders/org/newdawn/spaceinvaders/SpriteStore.java

What it does to my understanding is that it stores your sprite into your graphics accelerator hardware. I don’t know the rest, but with the same calculation for my FPS, I saw it increase from 50-60 fps to around 400, with a geforce 6800

[quote]I think sleep gaurantees a minimum that is accurate, but the maximum is innaccurate. Regardless, 400fps does seem too high.
[/quote]
Well, if there’s just a little rendering going on, 400fps doesn’t seem too high to me, even with a sleep of 1ms.

Having said that, my experience is that on some versions of windows, a sleep of less than a certain number of ms seemed to do nothing (iirc the threshold was 5 but I’m not sure). This was in the early java 1.4 days, so maybe this isn’t the case anymore (haven’t tested this in a long time)…

I noticed that your SndHr is instanced statically, but when you instance the class you will have an infinite loopback on your static instance, because of this recursivity. I suppose it doesn’t affect much the heap memory, but this might be noticeable with multithreading.
Plus I’d recommend you to use some kind of WeakHashMap impl or SoftReferences in your HashMap, and that is the question if you intend to load larger amount of SFX. Personnally I will use no HashMaps but WeakHashMap<Integer, SoftReference> with the int keys stored in some LIFO-HIFO (that is, last-recently-used and most-recently-used) as a soft-cache would behave.
Nevertheless this class is quite correct. :slight_smile:

thankx for the tips. I will see if I can improve my class. I made it on base of that graphic accelerator class and converted it for sound fx :slight_smile:

I thought so too, but apparently this is not the case.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6313903

Hi
I am new to Java and i have 1 question . Why this class have static instance ?
Why it cant be just simple created somewhere in for example my mainGame class ?

class mainGame {
static SoundHandler sh = new Soundhandler();

//…
}

And second question : where should I keep all wav s ? In jar or rather in simple folder ? ???
I think loading from JAR will take long time, but then when it is loaded it doesn’t matter because the class keep all wav s in RAM , right ?
Sorry for poor English :stuck_out_tongue: ;D

Singleton Pattern: http://en.wikipedia.org/wiki/Singleton_pattern

Loading from JAR or folder shouldn’t make much of a difference.