Sound Application

Hi,

I am using the following class (that I found on these forums) to play long songs in my application.

import java.io.*;

import javax.sound.sampled.*;

import javax.sound.sampled.DataLine.*;

publicclass SoundPlayerimplements LineListener

{

privatefloat bufTime;

private File soundFile;

private SourceDataLine line;

private AudioInputStream stream;

private AudioFormat format;

private Info info;

privateboolean opened;

privateint frameSize;

privatelong frames;

privateint bufFrames;

privateint bufsize;

privateboolean running;

privateboolean shutdown;

privatelong firstFrame, lastFrame;

privatefloat frameRate;

privatelong currentFrame;

privatefloat currentTime;

private Thread playThread;

// constructor, take a path to an audio file

public SoundPlayer(String path)

{

this(path, 2);// use 2 second buffer

}

// or a path and a buffer size

public SoundPlayer(String path,float bt)

{

this(new File(path),bt);

}

public SoundPlayer(File sf)

{

this(sf, 2);// use 2 second buffer

}

public SoundPlayer(File sf,float bt)

{

bufTime = bt;// seconds per buffer

soundFile = sf;

openSound();

}

privatevoid openSound()

{

System.out.println("Opening file"+soundFile.getName());

try

{

firstFrame = 0;

currentFrame = 0;

shutdown =false;

running =false;

stream=AudioSystem.getAudioInputStream(soundFile);

format=stream.getFormat();

if(format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED)

{

System.out.println("Converting Audio stream format");

stream = AudioSystem.getAudioInputStream(AudioFormat.Encoding.PCM_SIGNED,stream);

format = stream.getFormat();

}

frameSize = format.getFrameSize();

frames = stream.getFrameLength();

lastFrame = frames;

frameRate = format.getFrameRate();

bufFrames = (int)(frameRate*bufTime);

bufsize = frameSize * bufFrames;

System.out.println("frameRate="+frameRate);

System.out.println("frames="+frames+" frameSize="+frameSize+" bufFrames="+bufFrames+" bufsize="+bufsize);

info=new Info(SourceDataLine.class,format,bufsize);

line = (SourceDataLine)AudioSystem.getLine(info);

line.addLineListener(this);

line.open(format,bufsize);

opened =true;

}

catch(Exception e)

{

e.printStackTrace();

}

}

publicvoid stop()

{

System.out.println ("Stopping");

if(running)

{

running =false;

shutdown =true;

if(playThread !=null)

{

playThread.interrupt();

try{playThread.join();}

catch(Exception e){e.printStackTrace();}

}

}

if (opened) close();

}

privatevoid close()

{

System.out.println("close line");

line.close();

try{stream.close();}catch(Exception e){}

line.removeLineListener(this);

opened =false;

}

// set the start and stop time

publicvoid setTimes(float t0,float tz)

{

currentTime = t0;

firstFrame = (long)(frameRate*t0);

if(tz > 0)

lastFrame = (long)(frameRate*tz);

else lastFrame = frames;

if(lastFrame > frames)lastFrame = frames;

if(firstFrame > lastFrame)firstFrame = lastFrame;

}

publicvoid playAsync(float start,float end)

{

setTimes(start,end);

playAsync();

}

// play the sound asynchronously */

publicvoid playAsync()

{

System.out.println("Play async");

if(!opened)openSound();

if(opened && !running)

{

playThread =new Thread(new Runnable(){publicvoid run(){play();}});

playThread.start();

}

}

publicvoid play(float start,float end)

{

setTimes(start,end);

play();

}

// play the sound in the calling thread

publicvoid play()

{

if(!opened)openSound();

if(opened && !running)

{

running =true;

int writeSize = frameSize*bufFrames/2;// amount we write at a time

byte buf[] =newbyte[writeSize];// our io buffer

int len;

long framesRemaining = lastFrame-firstFrame;

int framesRead;

currentFrame=firstFrame;

System.out.println("playing file, firstFrame="+firstFrame+" lastFrame="+lastFrame);

try

{

line.start();

if(firstFrame > 0)

{

long sa = firstFrame * frameSize;

System.out.println("Skipping "+firstFrame+" frames="+sa+" bytes");

while(sa > 0)sa -= stream.skip(sa);

}

while (running && framesRemaining > 0)

{

len = stream.read(buf,0,writeSize);// read our block

if(len > 0)

{

framesRead = len/frameSize;

framesRemaining -= framesRead;

currentTime = currentFrame/frameRate;

if(currentTime < 0)throw(new Exception("time too low"));

System.out.println("time="+currentTime+" writing "+len+" bytes");

line.write(buf,0,len);

currentFrame+=framesRead;

}

else framesRemaining = 0;

}

if(running)

{

line.drain();// let it play out

while(line.isActive() && running)

{

System.out.println("line active");

Thread.sleep(100);

}

shutdown =true;

}

running =false;

}

catch(Exception e)

{

e.printStackTrace();

shutdown =true;

running =false;

}

if(shutdown)

{

close();

}

}

}

// return current time relative to start of sound

publicfloat getTime()

{

return ((float)line.getMicrosecondPosition())/1000000;

}

// return total time

publicfloat getLength()

{

return (float)frames / frameRate;

}

// stop the sound playback, return time in seconds

publicfloat pause()

{

running =false;

line.stop();

return getTime();

}

publicvoid update(LineEvent le)

{

System.out.println("Line event"+le.toString());

}

// play a short simple PCM encoded clip

publicstaticvoid playShortClip(String fnm)

{

java.applet.AudioClip clip=null;

try

{

java.io.File file =new java.io.File(fnm);// get a file for the name provided

if(file.exists())// only try to use a real file

{

clip = java.applet.Applet.newAudioClip(file.toURL());// get the audio clip

}

else

System.out.println("file="+fnm+" not found");

}

catch(Exception e)

{

System.out.println("Error building audio clip from file="+fnm);

e.printStackTrace();

}

if(clip !=null)// we may not actually have a clip

{

final java.applet.AudioClip rclip = clip;

new Thread

(new Runnable()

{

publicvoid run()

{

rclip.play();

}

}

).start();

}

}

publicboolean isOpened()

{

return opened;

}

publicboolean isRunning()

{

return running;

}

}

However, when the song is playing, everything stops. Does anyone have any suggestions on how to fix this? Thanks ahead of time.

[16578 byte] By [Bobert.a] at [2007-10-3 3:24:53]
# 1
Is that running in a different thread then the application?You use threads to make processes concurrent.Otherwise the program will just process the sound and everythingelse will have to wait for the sound to finish.
TuringPesta at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 2
Yes, I think it is using a different thread. Could you please help me with making the processes concurrent? I am still new to java and I dont know how to do that.
Bobert.a at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 3

Just look up Thread tutorials:

http://java.sun.com/docs/books/tutorial/essential/concurrency/

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Thread.html

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Runnable.html

http://www.javaworld.com/javaworld/jw-04-1996/jw-04-threads.html

You want to IMPLEMENT RUNNABLE not EXTEND THREAD.

Itll run the same both way actually so its not like it technically

matters in this situation but its good conceptual design.

Your program isnt a thread rather its runs in a thread so dont

extend instead implement.

Its really very easy.

Just have a class and do

(new Thread(your class that implements runnable)).start();

and in you runnable class implement one method:

public void run(){

start sound here();

}

TuringPesta at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 4
And dont ask how to stop a thread, lol. : )
TuringPesta at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 5
Thanks a lot TuringPest. Ill try my best and come back if I have any problems.
Bobert.a at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 6
Ive solved my problem, but I have another question. Does anyone know how I could put in volume control? Ive searched the forums, but I still cant figure it out.
Bobert.a at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 7
> And dont ask how to stop a thread, lol. : )Did anyone here happen to notice the playAsync and stop methods? playAsync starts a thread to play the sound, and stop goes to a lot of trouble to stop the thread.
pkwoostera at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 8
Oh lord, so now i have to actually READ what these people are posting? ; )
TuringPesta at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 9

> > And dont ask how to stop a thread, lol. : )

>

> Did anyone here happen to notice the playAsync and

> stop methods? playAsync starts a thread to play the

> sound, and stop goes to a lot of trouble to stop the

> thread.

Yes, the playAsync() method is how I solved my problem. Does anyone know how I could control the volume of this sound though?

Bobert.a at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 10

> Ive solved my problem, but I have another question.

> Does anyone know how I could put in volume control?

> Ive searched the forums, but I still cant figure it

> out.

The SourceDataLine has a control called "Master Gain" that can be used to control volume. Note that it is not linear, it's calibrated in decibles. So an adjustment of -10 will cut the volume in half. It also has range limits that may vary with your system and will trhow exceptions if they are exceeded.Here's the code you need to set it.

public void setGain(float gain) {

FloatControl g = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN);

g.setValue(gain);

}

You'll find some documentation [url=http://java.sun.com/j2se/1.5.0/docs/guide/sound/programmer_guide/chapter6.html]here[/url].

pkwoostera at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 11
> Oh lord, so now i have to actually READ what these> people are posting? ; )Not really, but the person using the code probably should. I have the unfair advantage of having written that utility several years ago.
pkwoostera at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 12

> > Oh lord, so now i have to actually READ what these

> > people are posting? ; )

>

> Not really, but the person using the code probably

> should. I have the unfair advantage of having

> written that utility several years ago.

I did read the code. I found the playAsync() method, just not right away.

Bobert.a at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 13

> > > Oh lord, so now i have to actually READ what

> these

> > > people are posting? ; )

> >

> > Not really, but the person using the code probably

> > should. I have the unfair advantage of having

> > written that utility several years ago.

>

> I did read the code. I found the playAsync() method,

> just not right away.

Yes, I see from your previous reply, but I hadn't seen that when I responded to the one about reading the code.

Did the Master Gain control do what you need?

pkwoostera at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 14
> Yes, I see from your previous reply, but I hadn't> seen that when I responded to the one about reading> the code. > > Did the Master Gain control do what you need?I havent tried it yet, but it looks like what I was looking for. Thanks
Bobert.a at 2007-7-14 21:17:44 > top of Java-index,Java Essentials,Java Programming...
# 15

Your welcome, and good luck with this, it all seems far more complicated than it needs to be, but that's how it gets if AudioClip doesn't do what you want. Also the naming seems backwards, output goes to a "SourceDataLine".

In that example, I left the documentation as an exercise for the reader, as they say in the math texts.

pkwoostera at 2007-7-21 10:10:30 > top of Java-index,Java Essentials,Java Programming...