I have searched and searched, and have not found the cause of my problem.
Setting: I am trying to play a list of clips in sequence indefinitely till the GUI of the program tells to stop. Also, the user can adjust the volume while the clips are being played.
Let's say I have clips A, B and C. The sequence of play will be ABCABCABCABC.....
Problem: The problem is that the first time clips A, B and C start - there are POPs - after that for the GUI tells to stop, there are no POPs.
Code: In the run() method of the thread, get all filenames of the clips, create all clips and save them in a LinkedHashSet. Next, play these clips in loop, creating the volume control object for each.
My Observation: The offending lines are commented (with // TODO: UNCOMMENT ME!!!!!) With the commented lines, there are no POPs, but the volume control is disabled. When these lines are uncommented, the POPs return.
Question: Where am I going wrong? I don't have any hair on the head to pull out! :)
private LinkedHashSet<Clip> clips = new LinkedHashSet<Clip>();
private FloatControl volControl = null;
.
.
.
.
#Override
public void run() {
List<String> fileNames = smd.getFiles();
if ( !(numFiles.isEmpty()) ) {
try {
// Create all clips and save in LinkedHashSet
//
for (String s: fileNames) {
clips.add(CreateClip(s));
}
// Play each clip till GUI says to stop
//
while (smd.getStopPlayStatus()) {
for (Clip c: clips) {
// Calculate and set the clip volume to what GUI says
//
float dB = (float) (Math.log(smd.getSwarMVolume()/100f) / Math.log(10.0) * 80.0);
System.out.println(" vol = " + volumeLevel/100f + " || dB = " + dB);
Control[ ] ctls = c.getControls();
for (Control ctl : ctls) {
if (ctl.toString().toLowerCase().contains("master gain")) {
volControl = (FloatControl) ctl;
break;
}
}
// volControl.setValue(dB); // TODO: UNCOMMENT ME!!!!!!!!
// Play the clip
//
loop(c, 0);
}
}
} catch (ConcurrentModificationException ex) {
}
}
}
void loop(Clip clip, int times){
if (times == -1) {
clip.loop(Clip.LOOP_CONTINUOUSLY);
} else {
clip.loop(times);
}
while (clip.isRunning()) {
float dB = (float) (Math.log(smd.getVolume()/100f) / Math.log(10.0) * 80.0);
// volControl.setValue(dB); // TODO: UNCOMMENT ME!!!!!!!!
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
clip.drain();
}
private Clip CreateClip(String fileName) {
Clip c = null;
try {
File file = new File(fileName);
AudioInputStream sound = AudioSystem.getAudioInputStream(file);
AudioFormat format = sound.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
c = (Clip) AudioSystem.getLine(info);
c.addLineListener(this);
c.open(sound);
} catch (MalformedURLException ex) {
} catch (UnsupportedAudioFileException ex) {
} catch (IOException ex) {
} catch (LineUnavailableException ex) {
}
return c;
}
The volume controls that are provided are very crude. When you set a new volume, the entire change happens all at once. This can create a discontinuity in the sound that results in a pop.
To eliminate this, one can try making the volume change more gradually. Sometimes this works. You will have to tinker with it to find the best trade-off of the amount of time needed for a transition and smoothness.
There are several issues that pertain. (1) The "distance" one can travel in a single volume change without a pop can be different at the low end versus the high end, depending on the scaling in use. (2) The number of changes you can make over a period of time is limited by the buffer size. You can only make one change per buffer. Thus decreasing the buffer size will allow more granularity in the volume changes, but will increase the risk of drop-outs.
Frankly, I just threw up my hands and gave up using the provided volume lines. Instead, I program the changes to transition on a per-frame basis. This can be done by taking each buffer and converting the bytes to PCM, doing the volume multiplication on the individual frames and converting back to bytes. The processing cost turns out to be pretty minor.
Related
I have a program that will ask the user which songs they want to play out of a list of available songs and after the user selects one once the song finishes it asks the user which song they want to play again. My question is how do I prevent the loop from asking the user which song they want to play until the selected song is finished so they don't repeat?
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String[] pathnames;
File MusicFileChosen;
String musicDir;
boolean songComplete = false;
pathnames = ProgramMap.musicDir.list();
// Print the names of files and directories
for (int ListNum = 0; ListNum < pathnames.length; ListNum++) {
System.out.println(ListNum + 1 + ". " + pathnames[ListNum]);
}
for (int playlistLength = 0; playlistLength < pathnames.length; playlistLength++){
if (!songComplete) {
System.out.println("Which Song would you like to play?");
int musicChoice = input.nextInt();
musicDir = ProgramMap.userDir + "\\src\\Music\\" + pathnames[musicChoice - 1];
MusicFileChosen = new File(musicDir);
PlaySound(MusicFileChosen, pathnames[musicChoice - 1]);
}
}
}
public static void PlaySound(File sound, String FileName){
try{
// Inits the Audio System
Clip clip = AudioSystem.getClip();
AudioInputStream AudioInput = AudioSystem.getAudioInputStream(sound);
//Finds and accesses the clip
clip.open(AudioInput);
//Starts the clip
clip.start();
System.out.println("Now Playing " + FileName);
clip.drain();
}catch (Exception e){
System.out.println("Error playing music");
}
}
}
You can use a LineListener. Then, register and listen for LineEvent.Type.CLOSE.
By the way, you might do better to use SourceDataLine than Clip. Maybe not a big deal, but given what you've coded, there could be audible lag, depending on the size of the file, every time you open a clip and load the complete file into memory (this has to be completed before playing can start). The SourceDataLine will commence playing almost immediately (only loads one buffer before starting to play) and only consumes the one buffer of memory instead of the entire sound file.
A lot of people that are new to javax.sound.sampled are wary of using SourceDataLine but it really isn't that much more difficult to code than a Clip, and for the use you are showing, it would be a better fit.
I want to play the microphone input in realtime using the JavaFX media player (to analyse its frequencies). The problem is, that the MediaPlayer only accepts Strings as source. I know how to write the microphone input into a byte array and into a file.
Using the byte array as source for the MediaPlayer is (for me) not possible. I tried using a temporary file, but that causes the following error:
Exception in thread "JavaFX Application Thread" MediaException: MEDIA_UNSUPPORTED : Empty signature!
I think this is, because I'm using a file as input while I'm still writing new data into it. My full code until now:
public class Music {
static AudioFormat format;
static DataLine.Info info;
public static void input(int i, int j, int pinState) {
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
try {
info = new DataLine.Info(TargetDataLine.class, format);
final TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(info);
targetLine.open();
AudioInputStream audioStream = new AudioInputStream(targetLine);
File temp = File.createTempFile("Input", ".wav");
temp.deleteOnExit();
Thread targetThread = new Thread() {
public void run() {
targetLine.start();
try {
AudioSystem.write(audioStream, AudioFileFormat.Type.WAVE, temp);
} catch (IOException e) {
e.printStackTrace();
}
}
};
targetThread.start();
Media media = new Media(temp.toURI().toURL().toString());
MediaPlayer player = new MediaPlayer(media);
player.setAudioSpectrumThreshold(-100);
player.setMute(false);
player.setAudioSpectrumListener(new AudioSpectrumListener() {
#Override
public void spectrumDataUpdate(double timestamp, double duration, float[] magnitudes, float[] phases) {
if(Var.nodeController[i] == 3) { //testing if the targetLine should keep on capturing sound
} else {
targetLine.stop();
targetLine.close();
player.stop();
}
}
});
player.play();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I need to find a solution to use the microphone input as MediaPlayer input, either using a file or a byte array or any other possible solution.
I am going to speculate that the following library might be helpful.
https://github.com/SzymonKatra/AudioAnalyzer
Note that it makes use of FFmpeg which claims to be:
A complete, cross-platform solution to record, convert and stream
audio and video.
The key component (based on my cursory look-over) seems to be the class FFTAnalyzer.java which the documentation says is based upon an FFT code/algorithm from Princeton.
So, the basic plan (I believe) would be the following:
obtain microphone input (a stream of bytes) from targetdataline
convert N frames of bytes to normalized floats or doubles and package as an array to send to FFTAnalyzer.analyze(double[] samples)
request the analysis results via FFTAnalyzer.getAmplitudes()
examine the result for each equalization band and apply smoothing as appropriate
repeat
I'm unclear as to exactly how much of the library is needed. It could be that since you are not dealing with video or cross-platform issues, only a class or two from this library would be needed.
Hey there stack overflow.
I'm creating a playlist player in Java, so far so good, I got all the logic down and the project is nearing completion. We've been testing the playback by creating some large playlist and just let the thing go from start to end. The playback sounds good, but sometimes the audio is cut off at the end. This happens very rarely. The last x seconds (time varies) are not played.
The files im testing with are all PCM wave file of 16 or 24 bit sampling size. Im using the Java sound engine in combination with Java zooms mp3 and ogg spi to support other types of audio files.
So far I have this logged a couple of times and my first thought was that the file might be corrupt, this is not the case. I've tried playing the file on its own and it played fully!
I've tried to find the problem but i just cant find it. I dont think theres anything wrong with my audio player, im running out of ideas.
Here is how i create my audio input stream:
public static AudioInputStream getUnmarkableAudioInputStream(Mixer mixer, File file)
throws UnsupportedAudioFileException
{
if (!file.exists() || !file.canRead()) {
return null;
}
AudioInputStream stream;
try {
stream = getAudioInputStream(file);
} catch (IOException e) {
logger.error("failed to retrieve stream from file", e);
return null;
}
AudioFormat baseFormat = stream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, baseFormat);
boolean supportedDirectly = false;
if (mixer == null) {
supportedDirectly = AudioSystem.isLineSupported(info);
} else {
supportedDirectly = mixer.isLineSupported(info);
}
// compare the AudioFormat with the desired one
if (baseFormat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED || !supportedDirectly) {
AudioFormat decodedFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(), 16, baseFormat.getChannels(),
baseFormat.getChannels() * 2, baseFormat.getSampleRate(),
false);
// convert the audio format to the supported one
if (AudioSystem.isConversionSupported(decodedFormat, baseFormat)) {
stream = AudioSystem.getAudioInputStream(decodedFormat, stream);
} else {
logger.debug(
"Audio format {} is not supported "
+ "and can not be converted to default format",
baseFormat.toString());
return null;
}
}
return stream;
}
And this is my audio player thread:
final class PlayerThread extends Thread
{
private byte[] buffer;
/**
* Initialize the buffer
*/
public void initBuffer()
{
linelock.lock();
try {
buffer = new byte[line.getBufferSize() / 5];
} finally {
linelock.unlock();
}
}
public void run()
{
initBuffer();
while (!isInterrupted()) {
checkState();
// if the line is just cleared go to the start of the loop
if (line == null || isInterrupted()) {
continue;
}
write();
}
// clean up all resources
close();
// change the state
state = Player.State.STOPPED;
}
private void checkState()
{
if (state != Player.State.PLAYING) {
if (line != null) {
line.flush();
}
try {
synchronized (this) {
this.wait();
}
} catch (InterruptedException e) {
// reset the interupt status
interrupt();
}
}
}
private void write()
{
// how much bytes could be written on the line
int available = line.available();
// is the space on the line big enough to write the buffer to
if (available >= buffer.length) {
// fill the buffer array
int read = 0;
try {
read = audioStream.read(buffer, 0, buffer.length);
} catch (Throwable ball) {
logger.error("Error in audio engine (read)", ball);
}
// if there was something to read, write it to the line
// otherwise stop the player
if (read >= 0) {
try {
linelock.lock();
line.write(buffer, 0, read);
} catch (Throwable ball) {
logger.error("Error in audio engine (write)", ball);
} finally {
linelock.unlock();
}
bytesRead += read;
} else {
line.drain();
MoreDefaultPlayer.this.stop();
}
}
}
private void close()
{
// invoke close on listeners
invokePlayerClosedOnListeners();
// destroy the volume chain
vc.removeVolumeListener(MoreDefaultPlayer.this);
// close the stream
try {
audioStream.close();
} catch (IOException e) {
logger.error("failed to close audio stream");
}
clearAllListeners();
linelock.lock();
try {
// quit the line
line.stop();
line.close();
line = null;
} finally {
linelock.unlock();
}
}
}
As you can see I drain the line after, so i dont think the problem is the line being closed before everything from the stream is played.
Can anyone see what might be wrong with this code?
I don't see an obvious answer, but there are a couple things that raise yellow flags for me. The common practise is to put the line.write() method in a while loop, not to invoke it repeatedly. There is usually no need to test for line.available() or to handle locking the line. The method line.write() will handle the necessary blocking if there is no space on the line available. I've always been cautioned not to lock or block audio lines unnecessarily.
Is the locking logic an integral part of the handling of the sequence of queues? The error you are describing could be in that handling. (Maybe there is an interaction with the test of available() compared to the buffer size? Is the amount of cutoff roughly equal to the buffer size?)
I would consider implementing a LineListener to announce when a cue is finished, and making that event the trigger of the playback of the next cue. An LineEvent of type STOP can be issued when the given file is done, notifying whatever handles the queue to proceed to the next file.
Using Java is it possible to capture the speaker output? This output is not being generated by my program but rather by other running applications. Can this be done with Java or will I need to resort to C/C++?
I had a Java based app. that used Java Sound to tap into the sound flowing through the system to make a trace of it. It worked well on my own (Windows based) machine, but failed completely on some others.
It was determined that in order to get it working on those machines, would take nothing short of an audio loop-back in either software or hardware (e.g. connect a lead from the speaker 'out' jack to the microphone 'in' jack).
Since all I really wanted to do was plot the trace for music, and I figured how to play the target format (MP3) in Java, it became unnecessary to pursue the other option further.
(And I also heard that Java Sound on Mac. was horribly broken, but I never looked closely into it.)
Java is not the best tool when dealing with the OS. If you need/want to use it for this task, probably you will end using Java Native Interface (JNI), linking to libraries compiled in other languages (probably c/c++).
Take an AUX cable, connect to HEADPHONE JACK and other end to MICROPHONE JACK and run this code
https://www.codejava.net/coding/capture-and-record-sound-into-wav-file-with-java-sound-api
import javax.sound.sampled.*;
import java.io.*;
public class JavaSoundRecorder {
// record duration, in milliseconds
static final long RECORD_TIME = 60000; // 1 minute
// path of the wav file
File wavFile = new File("E:/Test/RecordAudio.wav");
// format of audio file
AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
// the line from which audio data is captured
TargetDataLine line;
/**
* Defines an audio format
*/
AudioFormat getAudioFormat() {
float sampleRate = 16000;
int sampleSizeInBits = 8;
int channels = 2;
boolean signed = true;
boolean bigEndian = true;
AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits,
channels, signed, bigEndian);
return format;
}
/**
* Captures the sound and record into a WAV file
*/
void start() {
try {
AudioFormat format = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
// checks if system supports the data line
if (!AudioSystem.isLineSupported(info)) {
System.out.println("Line not supported");
System.exit(0);
}
line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
line.start(); // start capturing
System.out.println("Start capturing...");
AudioInputStream ais = new AudioInputStream(line);
System.out.println("Start recording...");
// start recording
AudioSystem.write(ais, fileType, wavFile);
} catch (LineUnavailableException ex) {
ex.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
/**
* Closes the target data line to finish capturing and recording
*/
void finish() {
line.stop();
line.close();
System.out.println("Finished");
}
/**
* Entry to run the program
*/
public static void main(String[] args) {
final JavaSoundRecorder recorder = new JavaSoundRecorder();
// creates a new thread that waits for a specified
// of time before stopping
Thread stopper = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(RECORD_TIME);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
recorder.finish();
}
});
stopper.start();
// start recording
recorder.start();
}
}
I'm working on a system of applications for processing sound data. The first application simply reads from a microphone jack and sends the data to the next application. The main loop repeatedly performs this code:
0 : Globals.mySleep(waitTime); // tells the thread to sleep for the proper amount of time for a given data format
1 : inputLine.read(buffer, 0, bufferSize); // reads sound data from the microphone jack into buffer
2 : if(connections.get(REGISTER) != null) { // if the next application is connected
3 : DataSlice slice = new DataSlice(buffer, serialIDCounter++, getDeviceName()); // create a slice of data to send, containing the sound data
4 : try{
5 : connections.get(REGISTER).sendDataSlice(slice); // send the data to the next application. supposed to block until next application receives the data
6 : connections.get(REGISTER).flush(); // make sure data gets sent
7 : } catch (IOException e) {
8 : // Stream has been broken. Shut Down
9 : close();
10: }
11: }
When I start the system, it is always several seconds behind. If I pause the system (GUI application tells the application following the input application to stop receiving data from the input application, so the input application should block at line 5 when paused), wait, then play again, the system lags additionally by however long I had just paused for. For example, if it started out with a 10-second lag, then paused for 5 seconds, and played again, it would then be lagging by 15 seconds.
This occurs when I run the program as a runnable jar file. It does not occur when I run it from Eclipse.
I've tested this on two computers, both running Ubuntu Linux 10.04 LTS. It occurs on one, not the other. Although on the other, I do get a whole different problem when I try to run it from Eclipse. Not sure what to make of this. If you would like some specs on the computers, I'd be happy to give them to you. Just tell me what specs you want and how to get them.
Could anyone tell me what might be causing the lag? Thanks.
--EDIT--
Per Andrew's suggestion, I created what I believe to be a SSCCE:
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.sound.sampled.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main implements MouseListener{
// Class that reads a signal from Line-in source and sends that signal
// to either a recorder module or the signal-viewing pipeline
public class PlayThread extends Thread {
byte[] buffer = new byte[bufferSize];
boolean playing = false;
boolean connected = false;
PlayThread() {}
public void run() {
while(true) {
try {
sleep(waitTime);
inputLine.read(buffer, 0, bufferSize);
if(connected) {
while(!playing)
sleep(100);
int max = 0;
for(int i = 0; i < buffer.length; i++) {
if(Math.abs(buffer[i]) > max)
max = Math.abs(buffer[i]);
}
System.out.println("Max: " + max);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void setPlaying(boolean playing) {
this.playing = playing;
}
public void setConnected(boolean connected) {
this.connected = connected;
}
}
TargetDataLine inputLine;
AudioFormat format;
float sampleRate;
int sampleSizeBits;
int channels;
int waitTime;
int bufferSize;
int slicesPerSecond;
int windowSize = 512;
PlayThread pThread;
JFrame gui = new JFrame("Sound Lag");
JPanel panel = new JPanel();
JButton play = new JButton("Play"), pause = new JButton("Pause"),
connect = new JButton("Connect"), disconnect = new JButton("Disconnect");
Main() {
sampleRate = 44100;
sampleSizeBits = 16;
channels = 2;
bufferSize = (sampleSizeBits/8)*channels*windowSize;
slicesPerSecond = (int) ((sampleRate/(float)channels)/(float)windowSize);
waitTime = (int)((((1000f/sampleRate)/(float)sampleSizeBits)/2f)*8f*(float)bufferSize);
play.addMouseListener(this);
pause.addMouseListener(this);
connect.addMouseListener(this);
disconnect.addMouseListener(this);
panel.add(play);
panel.add(pause);
panel.add(connect);
panel.add(disconnect);
gui.add(panel);
gui.setVisible(true);
gui.pack();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void read() {
// Open line from line-in
format = new AudioFormat(sampleRate, sampleSizeBits, channels, true, true);
// Obtain and open the lines.
inputLine = getTargetDataLine();
pThread = new PlayThread();
pThread.start();
}
private TargetDataLine getTargetDataLine() {
try {
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
for (Mixer.Info mi : AudioSystem.getMixerInfo()) {
TargetDataLine dataline = null;
try {
Mixer mixer = AudioSystem.getMixer(mi);
dataline = (TargetDataLine)mixer.getLine(info);
dataline.open(format);
dataline.start();
return dataline;
}
catch (Exception e) {}
if (dataline != null)
try {
dataline.close();
}
catch (Exception e) {}
}
}
catch (Exception e) {}
return null;
}
public static void main(String[] args) {
Main main = new Main();
main.read();
}
#Override
public void mouseClicked(MouseEvent arg0) {
if(arg0.getSource() == play) {
System.out.println("Playing");
pThread.setPlaying(true);
}
else if(arg0.getSource() == pause) {
System.out.println("Paused");
pThread.setPlaying(false);
}
else if(arg0.getSource() == connect) {
System.out.println("Connected");
pThread.setConnected(true);
}
else if(arg0.getSource() == disconnect) {
System.out.println("Disconnected");
pThread.setConnected(false);
}
}
#Override public void mouseEntered(MouseEvent arg0) {}
#Override public void mouseExited(MouseEvent arg0) {}
#Override public void mousePressed(MouseEvent arg0) {}
#Override public void mouseReleased(MouseEvent arg0) {}
}
This code produces a window with four buttons in it: play, pause, connect, and disconnect. If you press play, it is as if the program were in "play" mode. If you click connect, it is as if the sound input application were connected to the next module.
To test, do the following:
Connect a sound device to your microphone jack (but don't play anything).
Create the runnable jar file from this code.
Run the file from a terminal.
Click "play".
Click "connect".
At this point, you should see a bunch of smaller numbers going down the terminal.
On your sound device, start playing sounds.
You should instantly start seeing bigger numbers in the terminal.
Stop playing sounds on sound device (should go back to smaller numbers in terminal).
Click "pause".
Wait 5 seconds.
Click "Play".
Start playing sound with audio device.
This is where the bug comes in. If I am running this code in Eclipse, I instantly get bigger numbers again. If I am just running the jar file, there is a 5-second delay, then I get the bigger numbers.
Any new thoughts?
It's fixed. Whenever I want to get the sound stream going (whenever I press play), I close the current stream and open a new one.
I didn't realize the TargetDataLine actually held a buffer of sound data that just gets picked from whenever the read method is called.
It looks like when I ran the application from Eclipse, it was using a different type of TargetDataLine than when I ran it as a runnable jar file. This was evidenced by a difference in size between the buffers. Although the size difference was only about a factor of 2, so I think the problem wasn't in the size of the buffer, but in something else having to do with the TargetDataLines that were fetched.
Oddly enough, removing Globals.mySleep(waitTime) worked in fixing the SSCCE, but not the real program it was supposed to represent.
I tried both draining and flushing the Line, instead of replacing it, but neither of these seemed to work, though I may have been using them wrong.
So the problem was: The DataLine's buffer was getting filled up and while the program was not playing, the buffer was not being emptied, so when it did start playing, it continued fetching data from the buffer at the usual play rate, causing it to lag behind.
The solution is: When the program starts playing, replace the DataLine.
--EDIT--
Further observation shows that when I ran from Eclipse, it seemed to be using a different JRE than when I ran as a jar file. I set the default java program to be java-6-sun instead of java-6-openjdk and it works fine from the jar file.
Also, I tried running the method of replacing the DataLine on a different computer. On this computer, I was getting a nasty break in the signal. It seemed to be taking longer to pull a new DataLine, so I decided that wasn't going to work. Now, I simply read from the DataLine at all times. I just don't send the signal anywhere if the system is paused.
I find the best thing to do in situations like this, where your code is slow but you dont know why is to use a profiler, http://www.quest.com/jprobe/software_download.aspx you can get a free trail of this java profiler and it will tell you line by line how much time is spent and how many times it is executed, you should be able to pinpoint exactly what is slowing you code down with this.
Hope this helps,
Eamonn
Globals.mySleep(waitTime); // tells the thread to sleep for the proper amount of time for a given data format
I suspect the 'proper' waitTime here is '0'.
If you want something more than suspicions, I recommend you post an SSCCE (without the line numbers).