Skip to main content
gamedev.net
🔒 Locked

[java] Java Sound

Started by Halsafar Oct 13, 2005 at 11:24 PM 18 replies 1.8k views
Original Post
Halsafar
Halsafar
Is there by any chance a sound platform for the JVM? Mostly I need to be able to create minor noise's like bleeps and crackles... Asteroid ship shooting bleep and asteroid exploding boom... I have FMOD for Java, I used FMOD extensivly with C++ but just for music. I'm sure I could use it for sound effects... But then I'd need to find wav samples.
H_o_p_s
H_o_p_s
Here is a simple sound manager class.
import java.applet.*;import java.io.*;public class Sound_Manager {    private Applet a;    private AudioClip onceClip;    private AudioClip loopClip;    private boolean looping;        public Sound_Manager(){	    System.out.println("Created Sound_Manager...");    }     public void play(String playFile){        File file = new File(playFile);        try{            onceClip = a.newAudioClip(file.toURL());            onceClip.play();               }        catch(Exception e){            System.out.println("Error: "+e);        }   }    public void loop(String playFile){	    stopLoop();		    File file = new File(playFile);		    try{			    loopClip = a.newAudioClip(file.toURL());			    loopClip.loop();       		    }		    catch(Exception e){			    System.out.println("Error: "+e);		    }		    looping = true;   }            public void stopLoop() {	if (looping)		loopClip.stop();	looping = false;    }}
BRING BACK THE BLACK (or at least something darker)
CaptainJester
CaptainJester
Don't forget about midi.

javax.sound.midi.*
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][
Halsafar
Halsafar
Are these sound buffers like DSound?
As in there is only one read/write pointer and thus the same buffer can only be played once until the pointer reaches the end. Which means you have to create multiple versions of the same buffer to allow simultaneous plays of the same sound.
H_o_p_s
H_o_p_s
Quote:
Original post by CaptainJester
Don't forget about midi.

javax.sound.midi.*
You don't have to do this. The AudioClip class handles both midi and wav files.
Quote:
Original post by Halsafar
Are these sound buffers like DSound?
As in there is only one read/write pointer and thus the same buffer can only be played once until the pointer reaches the end. Which means you have to create multiple versions of the same buffer to allow simultaneous plays of the same sound.
I believe so, but frankly I use an external API that allows for mp3 playback as well.
BRING BACK THE BLACK (or at least something darker)
Halsafar
Halsafar
Hmmm.
Well I believe all sound buffers may fall on the lines of this problem.

I plan on using FMOD for music, it supports xm, s3m, wav, midi, mod, mp3 i'm pretty sure, etc...

I could use FMOD for sfx but again like I said I'd need to find sample waves since it doesn't support basic sound generation. Neither does the clip you sent me (I think)... Its to bad, I was hoping to manually generate the sfx for the game...

Oh well.
Thanks for your help.
Marianne
Marianne
you CAN generate sound in java... look at javax.sound.sampled.line (or audioline, or something like this i don't remember) just create a line and send byte samples to it. i've never done it before so you may need to document yourself a bit but i guess it is possible. (using a sound editor is however much easier)
CaptainJester
CaptainJester
Quote:
Original post by H_o_p_s
Quote:
Original post by CaptainJester
Don't forget about midi.

javax.sound.midi.*
You don't have to do this. The AudioClip class handles both midi and wav files.


I mean for generating sounds programatically. AudioClip is also for applets. For applications you should use javax.sound.sampled.*
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][
Son of Cain
Son of Cain
I recommed taking a look at this book, chapter IV to be more precise. Brackeen's book is wonderful.

Son Of Cain
a.k.a javabeats at yahoo.ca
Halsafar
Halsafar
After some reaserch it seems that some of these methods are 'blocking' as in they don't finish till the sound does...

It also seems there is several choices for Java Sound...

I have decided to use Wav files, unfortunatly after looking over the API I believe I will be using FMOD...
H_o_p_s
H_o_p_s
Here is an easy non-blocking wav/au player:
package Battle.Sound;//////////////////////////////////////                     	          //// Battle: The Fight for Eternity ////				  //////////////////////////////////////import	java.io.*;import	javax.sound.sampled.*;public class WavPlayer {	private Clip clip;		public static void main(String[] args) {		WavPlayer w = new WavPlayer("./Music/Pluck.wav");		w.setVolume(1D);		System.out.println("Playing non-blocking clip…");		w.play();		while(!w.isDone()) {			System.out.print('.');			try {				Thread.sleep(10);			} catch {Exception e) {}		}		System.out.println("Finished Playback. Do fade in test…");		w.fadeIn((long)w.getDuration());		System.out.println("Finished Fadein. Do fade out test…");		w.fadeOutStop((long)w.getDuration());	}		public WavPlayer(String filename) {		try {			// From file			AudioInputStream stream = AudioSystem.getAudioInputStream(new File(filename));			AudioFormat format = stream.getFormat();			DataLine.Info info = new DataLine.Info(Clip.class, stream.getFormat(), ((int)stream.getFrameLength()*format.getFrameSize()));			clip = (Clip)AudioSystem.getLine(info);    			// This method does not return until the audio file is completely loaded			clip.open(stream);					} catch (IOException e) {		} catch (LineUnavailableException e) {		} catch (UnsupportedAudioFileException e) {		}	}		public void play() {		clip.setFramePosition(0);		clip.start();	}		public void play(int times) {		clip.setFramePosition(0);		clip.loop(times);	}		public void loop() {		clip.setFramePosition(0);		clip.loop(clip.LOOP_CONTINUOUSLY);	}		public void stop() {		clip.stop();	}		public boolean isDone() {		return !clip.isRunning();	}		public void fadeOutStop(long miliseconds) {		Thread t = new Thread(new fadeout(this, miliseconds));		t.setPriority(t.MIN_PRIORITY);		t.start();	}		public void fadeIn(long miliseconds) {		Thread t = new Thread(new fadein(this, miliseconds));		t.setPriority(t.MIN_PRIORITY);		setVolume(0);		play();		t.start();	}		public void setVolume(double gain) {//1D = 100% .5D = 50%		// Set Volume		FloatControl gainControl = (FloatControl)clip.getControl(FloatControl.Type.MASTER_GAIN);		float dB = (float)(Math.log(gain)/Math.log(10.0)*20.0);		gainControl.setValue(dB);	}		public double getVolume() {		FloatControl gainControl = (FloatControl)clip.getControl(FloatControl.Type.MASTER_GAIN);		return Math.pow(10.0, gainControl.getValue()/20.0);	}		public double getDuration() {		return clip.getBufferSize()/(clip.getFormat().getFrameSize() * clip.getFormat().getFrameRate());	}		public double getPosition() {		return clip.getMicrosecondPosition()/1000000.0d;	}	private class fadeout implements Runnable {		private WavPlayer w;		private long wait;		public fadeout(WavPlayer w, long wait) {			this.w = w;			this.wait = wait;		}		public void run() {			for(double v = 1D; v >= 0D; v-=0.001D) {				w.setVolume(v);				try{Thread.sleep(wait);}catch(Exception e) {}			}			w.stop();		}	}		private class fadein implements Runnable {		private WavPlayer w;		private long wait;		public fadein(WavPlayer w, long wait) {			this.w = w;			this.wait = wait;		}		public void run() {			for(double v = 0D; v < 1D; v+=0.001D) {				w.setVolume(v);				try{Thread.sleep(wait);}catch(Exception e) {}			}			w.stop();		}	}}
BRING BACK THE BLACK (or at least something darker)
Halsafar
Halsafar
Nice, works just fine.
I did a lot of reading on my own and I've read up on a problem with shutting down ur program while a sound is playing. Apparently it cause's the JVM to crash or not close... Something like that.

I am curious if this example suffers from that bug; I could never find a bug report on it so I'm not sure the specifics on the bug.
AllTheLuck
AllTheLuck
In the past I have used JOrbis to decode ogg vorbis audio in games that I have been working on. I don't know why Sun does not support ogg sound files in their standard VM. Does anyone know why?

I found that playing back of sound files is not easy to set up, but that may just be that I have been blessed with wonderfully easy API's in the past.

Halsafar
Halsafar
Looking to play wave files.


Hops the class you posted works fine however playing the sound effect really bogs down the game.
A good example would be holding down a button to constantly fire off sound effects... The game lags down to a few frames a second.

I do believe it is the:
clip.setFramePosition(0);

Which is causing this amazing slow down...
H_o_p_s
H_o_p_s
Well, I don't know why that it slows your system way down… and if it does the same thing in my game on other platforms I will have to look into it more…

As far as the JVM not shutting down right, you can make sure this doesn't happen (I've never had it happen) by making sure you manually stop all sound before the program exits. A simple ClipManager that that has a method for doing this to all of it's Clips would work wonderfully.

If you really want to just play Wav files see the first source I posted. This will work great for just playing wav files (yes even in an application, Applet is just used for creating the AudioClip).

Or you could always look HERE for some generalized sources.
BRING BACK THE BLACK (or at least something darker)
Halsafar
Halsafar
Well I had already implimented a SoundManager to manage instances of the ClipClass so the game could call SFX from anywhere in the program without knowledge of any particular ClipClass.

I also fixed the lag problem with the feature I was planning to impliment anyways.

See the sound buffers only 1 read/write pointer and thus any consecutive calls to play just cause the playback to continue where the pointer is... Unless you set the FramePosition back to 0. So to get multiple playing instances of 1 sound clip I modify the ClipClass to contain a pool of its own clips. This method takes up extra memory since you now load many instances of the one sound. This is particularly good with bullets, assuming you have a limit on how many bullets can be fired you can rather easily guess the max number of sfx needed. Just add a LineListener and have it tell an array of bool's whether that particular instance is free for playback whenever it recieves a STOP event. Then modify your playsound method to loop through the clips boolean until it finds a free one, of course a for loop tho, if there are no free sounds we don't want the game to wait; in that scenerio the user will be out a sfx.

I can post the class if you want.
H_o_p_s
H_o_p_s
That'd be cool. I thought about doing this, but decided that I wouldn't want to waste the memory on loading so many sounds into memory… but if you had a limit set with a size constraint (5mb per sfx) I could see that being useful.

Another way to get around this would be to do the whole thing streaming from a single byte buffer in memory, have it synchronized, and then each sound effect will could have a bunch of pointers to the buffer without the increase in size.

for example: (in half coded java mind you)
public class StreamingBufferedClip {     byte[][] data; //This would be a double array in case we run out of int value     long[] pointers;//the playback counters     static final int MAX_PLAYS = 5;          public void StreamingBufferedClip(String filename) {          if(getFileSize(filename) > Integer.MAX_VALUE)              //load data from filename to data[0]…data          else              //load data from filename to data[0]     }     public void play() {          for(int i = 0; i < MAX_PLAYS; i++) {               if(pointers==null) {                    pointers = 0;                    return;               }          }     }     public void render() {          byte[] frame_data = new byte[1024*4];          for(int i = 0; i < MAX_PLAYS; i++) {               if(pointers==null)                    frame_data = //frame_data mixed with data[][]          }          line.write(frame_data);     }}
So all you have to do would be to call render() as often as you can. Just remember that I didn't write much of the code required for this example, but I think you get the idea… this would make it so one byte[][] object could supply all the data to as many pointers as you want, without loading them to memory multiple times…

I don't have time to implement this right now, but maybe later I'll take a crack at writing it.
BRING BACK THE BLACK (or at least something darker)
Halsafar
Halsafar
That would probably be great for an MP3 Player or apps alike but for a game you usually wish to avoid streaming audio. Unless Im wrong with this statement: I do believe that it is much faster to play a loaded audio clip from memory than stream a file from the hard drive. Since when its in memory it can be accessed with any read overhead from the HD.

But yes, my idea has that flaw of excess memory waste. However for my Asteroids game it is rather fine since the largest sfx is like 20kb and I happen to load 5 instances of that so 100kb right there...

Memory isn't so much an issue in computer todays unless we are refering to something like one instance taking up 100mb+... which is ridiculous. An extra 100kb is negligible.
H_o_p_s
H_o_p_s
The above concept would load all the data into memory, and then stream from the memory to the different instances running. So in a sense your streaming from memory instead of the HD, and then for every audioclip have a collection of pointers that are representing the number of instances of the audio file playing. And then when you call the render() method it'll mix down all the pointers into one output to the line.

But either way, for your game, 100kb means nothing [smile]
BRING BACK THE BLACK (or at least something darker)
Halsafar
Halsafar
Hmmm, that method is still rather smart.
I'll think about trying that out when I get my next project for C++.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.