I have a button which when clicked plays the song but it doesnt stop and also I cant press any other button until the music stops on its own,i.e. the song gets over. Please help!
My code is as follows:
public class Mp3Player {
private String filename;
private Player player;
public Mp3Player(String filename) {
this.filename = filename;
}
public void play() {
try {
BufferedInputStream buffer = new BufferedInputStream(new FileInputStream(filename));
player = new Player(buffer);
player.play();
}
catch (FileNotFoundException | JavaLayerException e) {
System.out.println(e);
}
}
}
And this is in the button:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Mp3Player mp3 = new Mp3Player("C:\\Users\\USER\\Desktop\\Echo.mp3");
mp3.play();
}
Call Player#play on another thread, this will allow your song to play while allowing your GUI to still work (a common approach in Swing).
Once it's running on it's own thread, you can kill that thread to stop it, there are a lot of different ways to do this...which I'll leave for homework =)
Create a thread to play the song without pausing the whole program.
PS. I would have written this as a comment but I don't have enough reputation points.
You are executing a blocking call (Player::play) in the event dispatcher thread, which means that you are blocking the processing of events (buttons clicked &co.) until player.play() returns.
Instead, call it in woker thread. First define a SwingWorker:
class PlayerWorker extends SwingWorker<Void, Void> {
private final Mp3Player mp3;
public PlayerWorker(String filename) {
mp3 = new Mp3Player(filename);
}
#Override
protected Void doInBackground() {
mp3.play();
return null;
}
}
please mind the use of Void (capital V) and return null. Then, call it like:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
(new PlayerWorker("C:\\Users\\USER\\Desktop\\Echo.mp3")).execute();
}
Related
I have implemented a JTextArea which acts like an area that constantly reads the output of a log file from another process and presents it to the user.
Here's a sample of my code:
class CustomOutputStream extends OutputStream {
private JTextArea textArea;
public CustomOutputStream(JTextArea textArea) {
this.textArea = textArea;
}
#Override
public void write(int b) throws IOException {
// redirects data to the text area
textArea.append(String.valueOf((char)b));
// scrolls the text area to the end of data
textArea.setCaretPosition(textArea.getDocument().getLength());
}
}
class TextAreaLogProgram extends JFrame {
/**
* The text area which is used for displaying logging information.
*/
private JTextArea textArea;
public TextAreaLogProgram() {
// the formEnvironment is part of install4j
textArea = ((JTextArea)formEnvironment.getFormComponentById("3341").getConfigurationObject());
PrintStream printStream = new PrintStream(new CustomOutputStream(textArea));
printLog();
}
/**
* Prints log statements in a thread
*/
private void printLog() {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
// A whole lot of regex matching is done here to present the info that we want
// to the user and once we reach the end I break
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
});
thread.start();
}
}
// Start the whole thing by making it visible.It's hidden by default
new TextAreaLogProgram().setVisible(true);
Now the above code adds a small "annoying" popup on the top left corner that has no content and just the usual Maximize and Close buttons attached to it with the Java icon on the left side. Like this:
annoying popup
Is there a way to do everything I'm doing right now without that popup?
Thanks in advance everyone.
I am unclear on how to use wait() and notify() to pause a thread. I read talk about synchronizing, but I'm unsure how to do it in my instance. I have a music player with a progress bar where I want to pause the thread in control of syncing the progress bar with the music. Here is the thread I want to pause:
#FXML private void clickedButton(ActionEvent event){
shuffle.setOnAction(e -> {
artistPane.setText(model.getCurrentSong());
if(firstTime){
//Multithreading with JavaFX. Essentially this other thread will check the slider to make sure its on track.
sliderThread = new Task<Void>() {
#Override
protected Void call() throws Exception {
boolean fxApplicationThread = Platform.isFxApplicationThread();
System.out.println("Is call on FXApplicationThread: " + fxApplicationThread);
//this is an infinite loop because now I only need to make this thread once, pausing and starting it, as opposed to making many threads
for(;;){
Thread.sleep(100);
progressBar.setValue(controller.getPercentageDone());
}
}
};
new Thread(sliderThread).start();
firstTime = false;
}else if(!model.getIsPlaying()){
//I want to start the thread here
}
controller.shuffle(); //this will start the music on the next song
});
Here is the second half where I also want to pause and start the thread:
play.setOnAction(e -> {
controller.play(); //this will pause/start the music
if(!model.getIsPlaying()){
//where I want to pause the thread.
}else{
//I want to start the thread here
}
});
I will try to give you simple example and you try to apply it to your program...
public class TestClass extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private Thread playThread ;
TestClass() {
playThread = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("DO SOME THING HERE");
System.out.println("SONG WILL PLAY.....");
}
});
}
public void startMyPlayer() {
System.out.println("PLAYING NOW...");
playThread.start();
}
public void pauseMyPlayer() throws InterruptedException {
System.out.println("PAUSED NOW...");
playThread.wait();
}
public void resumeMyPlayer() {
System.out.println("RESUMING NOW...");
playThread.notify();
}
}
That's it.I hope this help you.
I am trying to make System.in InputStream read from a JTextField.
What i need it to do, is to allow .read() to proceed once a user presses enter in a JTextField with a String in it.
The issue is that I don't know when .read() will be invoked, and i want it to block without freezing the main thread, until enter is pressed by the user in the JTextField where it will notify the thread waiting.
So far i tried the following:
public class InputStreamHandlerThread extends Thread {
private JTextField txt;
public InputStreamHandlerThread(JTextField txt) {
this.txt = txt;
start();
}
#Override
public void run() {
System.setIn(new FakeInputStream());
}
class FakeInputStream extends InputStream {
private int indx = 0;
#Override
public int read() throws IOException {
if (indx == txt.getText().length()) {
indx = 0;
try {
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int byt = txt.getText().getBytes()[indx];
indx++;
return byt;
}
}
}
which is initialized and started by the GUI thread.
So once the GUI loads, it creates an instance of this class and keeps a pointer so that when the enter key is pressed on the keyboard within the JTextField, it is notified to read from it.
in = new JTextField();
in.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent a) {
if (a.getKeyChar() == '\n') {
inputStreamHandler.notify();
}
}
});
So currently there are three threads:
1. The main thread on what the GUI runs on
2. The InputStream handler thread (See above ^)
3. The thread that reads from System.in
The problem is that once i invoke inputStreamHandler.notify(); it throws a java.lang.IllegalMonitorStateException which according to the docs, is thrown if the thread is not the holder of the lock.
How do i resolve this?
Thank you :-)
String text;
...
in.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
text = in.getText();
}
});
Make sure you make text and in both fields.
I'm working at an Audio Player, which is written in Java with GUI. For playing the mp3 files, I've chosen JLayer library from javazoom because I saw it's very popular and used. I made the GUI, managed to play the selected mp3 file from the playlist.
My problem is that if I press many times on the play button or on the file from the playlist it will start playing the song as many times as I press it and I want to play it one the same thread ; if I press again play button I want to play again not to start the same song while the current one is playing .
Here is my code which play the mp3 file:
public class Playing implements Runnable{
private Player mp3Player;
private Thread playerThread;
public void createPlayer(FileInputStream file) throws JavaLayerException{
mp3Player = new Player(file);
playerThread = new Thread(this);
playerThread.start();
}
#Override
public void run(){
try {
mp3Player.play();
}
catch (JavaLayerException ex) {
Logger.getLogger(Playing.class.getName()).log(Level.SEVERE, null, ex);
}
}
This is my method for the play button:
public void createPlayButton(){
play = new JButton();
playButton = new ImageIcon("D:/Audio Player/Images/playButton.png");
play.setBounds(125, 100, 50, 50);
play.setIcon(playButton);
play.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < select.getFilesPath().size(); i++){
if (select.getFilesPath().get(i).toString().contains(playlistBody.getSongName())){
try {
mp3Player.createPlayer(new FileInputStream(new File(select.getFilesPath().get(i).toString())));
} catch (JavaLayerException ex) {
Logger.getLogger(PlayerBody.class.getName()).log(Level.SEVERE, null, ex);
} catch (FileNotFoundException ex) {
Logger.getLogger(PlayerBody.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
});
}
I mention that I'm new to multithreading, so dont be so hard on me. If I cannot do this with JLayer, please recommend me a good library with which I can play mp3 files. Thank you in advance and I'm waiting for your suggestions.
I fixed my issue with the threads; I'll put the solution, maybe will help someone.
static int fileRunning = 0;
public void playMp3(FileInputStream file) throws JavaLayerException{
if (fileRunning == 0){
mp3Player = new Player(file);
playerThread = new Thread(this);
playerThread.start();
fileRunning = 1;
}
}
So the main idea is that when I start playing a song, that int will take value 1, and it won't be 0, so no more threads can be made.
use this after you press you play button and the thread has been started once player start the button will disable and let it enable again once the song is being completed
yourplaybutton.setEnabled(false);
ok so im working on my program which will play a song once a button is clicked, i have the code down, and my audio is playing when the button is clicked,but the only problem now is that my program is going completely bonkers and just playing the audio when the button is clicked!!!! the program just freezes the audio keeps playing but the program will not do it's other functions! What am i doing wrong? and how do i fix it?
heres the code for the action listeners button
in myFrame.java
sound sound = new sound();
private File pokemonBattle = new File(".\\audio\\"+"sound.wav");
private void dualButtonActionPerformed(java.awt.event.ActionEvent evt)
{
// TODO add your handling code here:
for (int i = 0; i<1; i++){
c = deck.getNextCard();
p1hand[i] = c;
p1.setCard(c); //ignore all this
c = deck.getNextCard();
p2hand[i] = c;
p2.setCard(c);
}
pokemon1.setEnabled(true);
pokemon2.setEnabled(true);
pokemon1.setIcon(p1hand[0].getImage()); //ignore all this as well
pokemon2.setIcon(p2hand[0].getImage());
textArea.setText("Pokemon 1:"+p1hand[0].toString()+"\nPokemon 2:
"+p2hand[0].toString());
p1ResultLabel.setText("");
p2ResultLabel.setText("");
//this is where im calling my audio
sound.playAudio(pokemonBattle);//this is where im calling my play audio method
}
sound.java where i have playAudio()
import java.io.File;
import javax.sound.sampled.*;
public class sound {
public void playAudio(File sf){
AudioFormat audioFormat;
AudioInputStream audioInputStream;
SourceDataLine sourceDataLine;
try
{
audioInputStream = AudioSystem.getAudioInputStream(sf);
audioFormat = audioInputStream.getFormat();
System.out.println(audioFormat);
DataLine.Info dataLineInfo = new
DataLine.Info(SourceDataLine.class,audioFormat);
sourceDataLine =(SourceDataLine)AudioSystem.getLine(dataLineInfo);
byte tempBuffer[]=new byte[100000];
int cnt;
sourceDataLine.open(audioFormat);
sourceDataLine.start();
while((cnt=audioInputStream.read
(tempBuffer,0,tempBuffer.length))!=-1){
if(cnt>0){
sourceDataLine.write(tempBuffer,0,cnt);
}
}
}
catch (Exception e)
{
e.printStackTrace();
System.exit(0);
}
}
}
You need to play the audio in a separate thread. The program becomes unresponsive because it is playing your audio on the event dispatch thread instead of drawing the UI and responding to user interaction.
instead of:
sound.playAudio(pokemonBattle);
do:
Thread t = new Thread( new SoundPlayer( sound, pokemonBattle );
t.start();
and also:
public class SoundPlayer implements Runnable
{
private final sound sound;
private final File soundFile;
public SoundPlayer( sound sound, File soundFile )
{
this.sound = sound;
this.soundFile = soundFile;
}
public void run()
{
sound.playAudio( soundFile );
}
}
Joseph is right. But in this instance the problem is
while((cnt=audioInputStream.read
(tempBuffer,0,tempBuffer.length))!=-1){
if(cnt>0){
sourceDataLine.write(tempBuffer,0,cnt);
}
}
You while loop will run infinitely hence freezing up your application. Since you are reading and writing the entire buffer at once there is no need for the while loop. Do this outside of a loop and you will be fine.