Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 312
  • Last Modified:

GUI goes blank while an mp3 file is being played

I am building a little Java program that will play mp3s. With my current coding, the mp3s play just fine, the only thing is that while an mp3 is playing, the GUI goes completely blank until the mp3 is finished playing. Why would this happen and what do i do to fix it?  I have pasted the code to play the mp3s below.  Thank you!

public void testPlay(String filename)
{
System.out.println("testPlay started");
  try {
    File file = new File(filename);
    AudioInputStream in= AudioSystem.getAudioInputStream(file);
    AudioInputStream din = null;
    AudioFormat baseFormat = in.getFormat();
    AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                                                                                  baseFormat.getSampleRate(),
                                                                                  16,
                                                                                  baseFormat.getChannels(),
                                                                                  baseFormat.getChannels() * 2,
                                                                                  baseFormat.getSampleRate(),
                                                                                  false);
    din = AudioSystem.getAudioInputStream(decodedFormat, in);
    // Play now.
    rawplay(decodedFormat, din);
    in.close();
  } catch (Exception e)
    {
        System.out.println("exception encountered!");
    }
}

private void rawplay(AudioFormat targetFormat, AudioInputStream din) throws IOException,                                                                                                LineUnavailableException
{
  byte[] data = new byte[4096];
  SourceDataLine line = getLine(targetFormat);
  if (line != null)
  {
    // Start
    line.start();
    int nBytesRead = 0, nBytesWritten = 0;
    while (nBytesRead != -1)
    {
        nBytesRead = din.read(data, 0, data.length);
        if (nBytesRead != -1) nBytesWritten = line.write(data, 0, nBytesRead);
    }
    // Stop
    line.drain();
    line.stop();
    line.close();
    din.close();
stopBtn.setEnabled(false);
      playBtn.setEnabled(true);
  }
}

private SourceDataLine getLine(AudioFormat audioFormat) throws LineUnavailableException
{
  SourceDataLine res = null;
  DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
  res = (SourceDataLine) AudioSystem.getLine(info);
  res.open(audioFormat);
  return res;
}
0
SmileMagician
Asked:
SmileMagician
  • 5
  • 3
  • 2
1 Solution
 
NetworkArchitekCommented:
The reason this happens is because it all occurs in the same thread. I haven't done multithreading in Java as I am just starting to learn it but I think it is probably quite simple. I just perused this link and I think this should give you what you need to know. Again, so what's happening is your UI can't update because your mp3 is playing in the same thread. What you should do is setup a new thread for the mp3, basically your UI just stops responding because program flow has been passed to the "mp3 player" function. Here's an IBM article on multithreading with Java.

http://www-128.ibm.com/developerworks/java/library/j-thread.html
0
 
SmileMagicianAuthor Commented:
Oh okay. Would that be something simple like nesting my "testPlay" function inside a "new thread" class or something similar?  (I still get the classes, methods, etc mixed up)

Thank you!
0
 
NetworkArchitekCommented:
Well, that last link I gave was a little sparse on actually explaining how to do threads. Try this one. I've done threading in other languages but not Java. I would defnitely put the mp3 player in another class and you need to implement a run() method. Check this link, I think it goes through step by step creating a simple threading app, the classic example is with timers.

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

I really shouldn't be very complicated in Java, you want to take to the places where they use the "synchronized" keyword. Also, if you want to return information from your thread you will probably want to look into how Java does "callbacks" unless it does it in some other sort of way. As I said I have only done simle single threaded apps in Java. Hope this helps though, that is definitely the problem though.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
InteractiveMindCommented:
try something like this:


class TestPlay {
 
 private String filename;
 
 public TestPlay(String filename)
 {
    this.filename = filename;
 }
 
 public void run()
 {
  System.out.println("testPlay started");
  try {
    File file = new File(filename);
    AudioInputStream in= AudioSystem.getAudioInputStream(file);
    AudioInputStream din = null;
    AudioFormat baseFormat = in.getFormat();
    AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                                                                                  baseFormat.getSampleRate(),
                                                                                  16,
                                                                                  baseFormat.getChannels(),
                                                                                  baseFormat.getChannels() * 2,
                                                                                  baseFormat.getSampleRate(),
                                                                                  false);
    din = AudioSystem.getAudioInputStream(decodedFormat, in);
    // Play now.
    rawplay(decodedFormat, din);
    in.close();
  } catch (Exception e)
    {
        System.out.println("exception encountered!");
    }
 }
}


You'd then use it something like this:

   Thread tp = new TestPlay( "filename.mp3" );
   tp.start();


Regards;
0
 
InteractiveMindCommented:
Oh, sorry, change this line:

class TestPlay {

to:

class TestPlay extends Thread {
0
 
SmileMagicianAuthor Commented:
I know we are on the right track!  The only problem I am having right now is what to do with my "rawplay" function.  (see " rawplay(decodedFormat, din);")  It is what actually plays the mp3. If I interpret your version correctly, that rawplay function is now the "public void run()" function, correct?  can I use the rawplay parameters (AudioFormat targetFormat, AudioInputStream din) in this run() function?  or do I need to rewrite the parameters usage altogether?
0
 
InteractiveMindCommented:
Use this code instead then:


class TestPlay extends Thread {
 
 private String filename;
 private AudioFormat targetFormat;
 private AudioInputStream din;
 
 public TestPlay(String filename, AudioFormat targetFormat, AudioInputStream din) throws IOException, LineUnavailableException
 {
    this.filename = filename;
    this.targetFormat = targetFormat;
    this.din = din;
    start();
 }
 
 public void run()
 {
  System.out.println("testPlay started");
  try {
    File file = new File(filename);
    AudioInputStream in= AudioSystem.getAudioInputStream(file);
    AudioInputStream din = null;
    AudioFormat baseFormat = in.getFormat();
    AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                                                                                  baseFormat.getSampleRate(),
                                                                                  16,
                                                                                  baseFormat.getChannels(),
                                                                                  baseFormat.getChannels() * 2,
                                                                                  baseFormat.getSampleRate(),
                                                                                  false);
    din = AudioSystem.getAudioInputStream(decodedFormat, in);
    // Play now.
    rawplay(decodedFormat, din);
    in.close();
  } catch (Exception e)
    {
        System.out.println("exception encountered!");
    }
 }
}


You can then use it like so:

    TestPlay tp = new TestPlay( "songFile.mp3", the_targetFormat_parameter, the_din_parameter );

That's all. It will then declare the arguments as class variables, and then auto-initialize itself as an individual thread.


Regards;
0
 
InteractiveMindCommented:
When you instantiate the TestPlay class (which means to 'make a call to the class's custructor'), you must catch any exceptions, as you probably know, so you'd actually use something like this:

try
{
   TestPlay tp = new TestPlay( "songFile.mp3", the_targetFormat_parameter, the_din_parameter );
} catch ( IOException ioe )
{
   ioe.printStackTrace( System.out );
} catch ( LineUnavailableException lue )
{
   lue.printStackTrace( System.out );
}

0
 
SmileMagicianAuthor Commented:
I couldn't possibly have gotten a more complete answer faster. Actually, it was beyond an answer, you pretty much did the work for me.  Works perfectly, man, thank you so much! Your amazing!

SmileMagician  :)
0
 
InteractiveMindCommented:
Thanks, SmileMagician  :-)

If you stick with Java, then sooner than you think, you'll be able to do the same thing just as easy; good luck with it!

Regards;
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 5
  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now