I'm using a sound player and I'm trying to create a while loop that knows when to terminate the JFrame it's playing in. The while loop should loop while the clip (recording) is playing and end when the clip is done. But here's the deal: The while loop only works when it prints something out, which I DON'T want it to do?
import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;
import javax.swing.*;
public class SoundClipTest extends JFrame {
public SoundClipTest() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
// Open an audio input stream.
File soundFile = new File("Testing/recording (2).wav");
AudioInputStream audioIn = AudioSystem.getAudioInputStream(soundFile);
//URL url = new URL("http://maximumdonline.com/miscwavs/pacman.wav");
//AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
// Get a sound clip resource.
Clip clip = AudioSystem.getClip();
// Open audio clip and load samples from the audio input stream.
clip.open(audioIn);
clip.start();
this.setVisible(true);
this.setVisible(false);
boolean run = true;
//problem While Loop
while(clip.isActive()){
//Only works when I print something out during the loop:
//System.out.println(run);
}
//Test While Loop has ended.
run = false;
System.out.println(run);
//Close JFrame
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
Note: Most of this sound code came from
https://www.ntu.edu.sg/home/ehchua/programming/java/J8c_PlayingSound.html
It works. I've tested it, but my while loop is crying!
The correct way to approach this task is to add a LineListener to the Clip. A Clip implements javax.sound.sampled.Line interface, so we can use Line.addLineListener(LineListener)..
Adds a listener to this line. Whenever the line's status changes, the listener's update() method is called with a LineEvent object that describes the change.
Try modifying your code to
while (clip.isActive()) {
if(!clip.isRunning())
clip.stop();
}
This did the trick for me
Related
I have sound effects for a game. Upon the game frame opening, the first sound lags behind. After that sound plays, no more lag is experienced.
Here's my clip player:
public enum SoundEffect
{
WALL("ping_pong_8bit_plop"),
PADDLE("ping_pong_8bit_beeep"),
POINT("ping_pong_8bit_peeeeeep");
public static enum Volume
{
MUTE, UNMUTE
}
public static Volume volume = Volume.MUTE;
private Clip clip;
SoundEffect (String file)
{
try
{
AudioInputStream inputStream = AudioSystem.getAudioInputStream(this.getClass().getResource(file+".wav"));
AudioFormat format = inputStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
clip = (Clip)AudioSystem.getLine(info);
clip.open(inputStream);
}
catch (UnsupportedAudioFileException uae)
{
uae.printStackTrace();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
catch (LineUnavailableException lue)
{
lue.printStackTrace();
}
}
public void play()
{
if (volume != Volume.MUTE)
{
if (clip.isRunning())
clip.stop();
clip.flush();
clip.setFramePosition(0);
clip.start();
}
}
static void init()
{
values();
}
}
So when I call SoundEffect.WALL.play() for example, it plays fine overall, but the very first time it plays there is a huge lag spike. What can I do to solve this, preferably still using Clips?
I had the same bug, the first play of a clip was about 1-2 sec delayed, no matter when the play()-method is called. What I did is I played a clip in the main() method which is a half seccond long and contains nothing (no sound). This means that the play() method of the actual sound isn't called the first time, and for me, it works. Hope it helped.
Use a separate Thread
Thread music = new Thread(new Runnable() {
#Override public void run() { your code }
};
music.start();
I'm Trying to make java game and now I'm implementing music to the game. Problem is if music is playing and sound is starting to play then I want to stop music.
Current Code
Clip clip;
public void playSound(File sound) {
try {
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(sound));
clip.start();
} catch(Exception e) {
System.out.println("Error with playing sound.");
e.printStackTrace();
}
}
public void stopSound() {
if(clip == null) return;
clip.stop();
}
But if I call stopSound method then sound never get's stopped.
Any help is appreciated!
The scope of clip is the problem. The clip object defined in playSound is unknown to stopSound.
If your object contain a clip attribute, try to change the first line of playSound to:
clip = AudioSystem.getClip();
My goal is to make a program that displays a pop up window with a single button called play. I am using an inner class and action listener. The button does in fact play the audio clip. Now what I would like to do is make it so every time I hit the play button it plays it from the beginning and I do not hear more than one instance of the clip being played in it's completion. Here is the code I have for the inner class only:
private class PlaySound implements ActionListener {
public void actionPerformed(ActionEvent e) {
String filename = "/Users/philipgouldman/Desktop/iPhoneRingtones/Dummy_Yeah.wav";
try {
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File(filename)));
clip.setFramePosition(0);
clip.start();
} catch (Exception exc) {
exc.printStackTrace(System.out);
}
}
}
I would appreciate any tips or suggestions to achieve this goal. I read on the Clip Interface javadoc that if the user wants the action to restart to simply invoke stop following setFramePosition(0). I can't say I quite understand what that means. Can someone guide me in the right direction?
Move your Clip Object outside of this handle so that its state can be investigated later.
e.g.
private class PlaySound implements ActionListener {
private Clip clip = null;
public void actionPerformed(ActionEvent e) {
String filename = "/Users/philipgouldman/Desktop/iPhoneRingtones/Dummy_Yeah.wav";
try {
if (clip == null) {
clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File(filename)));
}
clip.setFramePosition(0);
clip.start();
} catch (Exception exc) {
exc.printStackTrace(System.out);
}
}
}
I have a button that plays this code when pressed:
public void music() throws UnsupportedAudioFileException, IOException {
try {
URL url = this.getClass().getResource("/audio/InGame01.mid");
AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
But, not only is the sound delayed (I'm assuming its because it has to read the sound file, and then play it), the button also becomes frozen until it finishes reading the sound clip. Is there a simple way to open the audio clip before the button is actually pressed, so that it already has it loaded? (clip.open(audioIn) is what I'm talking about.)
This is where the method is called(Button Listener):
try {
music();
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
I'm building a drum machine/sequencer application, where the user selects a pattern of checkboxes (that are in a grid format: each column is a different beat, each row is a different instrument), and on clicking "play" an audio sample should hopefully play on each selected beat in the pattern.
Currently, I'm using a java.swing timer to run the note() method in a loop. However, this makes it play on every "beat", whereas I only want it to play on selected beats. I have a feeling I need to use timer.stop() and timer.start() somewhere, so that note() won't execute on the unselected beats but will start again when it encounters the next selected beat.
I created the array int pattern[] = {1,0,1,0}; to hold the pattern I want the sound to play in. I was thinking there might be a way to cycle through the array and execute note() each time the value is 1, but I don't really know how it would be done.
So I guess the main question is: how to I get timer to trigger (or not trigger) an event in a pattern? Are any of my inclinations correct, or am I approaching this in the wrong way?
Grateful for any suggestions/advice :)
Here's what I have so far:
import java.io.*;
import javax.sound.sampled.*;
import javax.swing.Timer;
import java.awt.event.*;
public class PlaySound extends JFrame {
static String folderPath = "folder/path/goes/here/";
public static String fileName = "kick_01.wav";
int pattern[] = {1,0,1,0};
int c = 0;
// Constructor
public PlaySound() {
Timer timer = new Timer(500, new ActionListener() { //500 == 120bpm
public void actionPerformed(ActionEvent e) {
note(fileName); //Play audio file
}
});
timer.start();
}
public static void note(String f) {
try {
try {
// Open an audio input stream.
File soundFile = new File(folderPath + f);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(soundFile);
// Get a soundjava clip resource.
Clip clip = AudioSystem.getClip();
// Open audio clip and load samples from the audio input stream.
clip.open(audioIn);
clip.start();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
} catch (Exception e) {}
}
}
Keep track of where you are in the pattern every time the Timer fires. Something like:
if (pattern[index] == 1)
playSound();
index++;
if (index == pattern.length)
index = 0;