I have an application that plays audio files.
My problem is that only allows me to pause playback from the position that the music is currently in, but what I want is to pause and continuing playing from that point forward. So far, I could not make that change.
I want to move the slider from another position and be able to play the music from that position on the track.
File juntos = new File("C:/juntos.wav");
if(controlPlay){
//Sliderprogreso is bar Slider
Sliprogreso.setEnabled(true);
controlReproducir=true;
Btngrabar.setEnabled(false);
Btnguardar.setEnabled(false);
Btnplay.setText("Pause");
try {
AudioInputStream stream;
AudioFormat format;
DataLine.Info info;
stream = AudioSystem.getAudioInputStream(juntos);
format = stream.getFormat();
frames =stream.getFrameLength();
durationInSeconds = (frames+0.0) / format.getFrameRate();
System.out.println("duracion:"+durationInSeconds);
Sliprogreso.setMaximum((int) durationInSeconds);
info = new DataLine.Info(Clip.class, format);
clip = (Clip) AudioSystem.getLine(info);
clip.open(stream);
clip.start();
controlPlay=false;
TimerTask timerTask=new TimerTask(){
public synchronized void run() {
{
double timeNow=(durationInSeconds*clip.getFramePosition())/frames;
System.out.println("frames:"+frames);
System.out.println("clipframe:"+clip.getFramePosition());
System.out.println("time now");
Sliprogreso.setValue((int)Math.round(timeNow));
if((int)Math.round(timeNow)==(int)durationInSeconds){
System.out.println("se cancelo");
this.cancel();
Btnplay.setText("Play");
Btngrabar.setEnabled(true);
Btnguardar.setEnabled(true);
controlPlay=true;
}
}
}
};
timer.scheduleAtFixedRate(timerTask, 30, 30);
}
catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
else{
clip.stop();
timer.cancel();
Btnplay.setText("Play");
controlPlay=true;
Btngrabar.setEnabled(true);
Btnguardar.setEnabled(true);
}
Have you looked at the Clip API? There are methods for pausing and for setting the "playhead" to any position, using either frames or elapsed time.
From within your TimerTask:
if (positionOnSliderUpdatedByUser)
{
clip.stop();
int desiredMicrosecond = yourConversionFunction( sliprogreso.getValue() );
clip.setMicrosecondPosition(desiredMicrosecond);
clip.start();
positionOnSliderUpdatedByUser = false;
}
I'm not sure if I am reading your code correctly, especially with your lack of formatting. I'm taking it that you are updating the slider regularly with the song position, but that if the user changes the slider, then you want to move to that point in the song. Thus, there should be some sort of process to flag when the user changes the slider (as opposed to the song changing the slider). I'm using the flag name "positionOnSliderUpdatedByUser".
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();
I've found a working Sound class online and am using it to play sound in a game I'm making. However, I wanted to continuously play the file so I decided just to use a Swing Timer and it works, the only problem is my game window freezes and won't even let you exit it out without using task manager.
Can you please take a look at it and tell me where I went wrong? By the way main is just my object variable for my Sound class, and maindelay is just my int for the delay.
public static void loopSound(){
Timer maintime = new Timer(maindelay, new ActionListener(){
public void actionPerformed(ActionEvent e){
main.run();
}
});
maintime.start();
}
The Sound class I've found:
public class Sound extends Thread {
private String filename;
private Position curPosition;
private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb
enum Position {
LEFT, RIGHT, NORMAL
};
public Sound(String wavfile) {
filename = wavfile;
curPosition = Position.NORMAL;
}
public Sound(String wavfile, Position p) {
filename = wavfile;
curPosition = p;
}
public void run() {
File soundFile = new File(filename);
if (!soundFile.exists()) {
System.err.println("Wave file not found: " + filename);
return;
}
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat();
SourceDataLine auline = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (LineUnavailableException e) {
e.printStackTrace();
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
if (auline.isControlSupported(FloatControl.Type.PAN)) {
FloatControl pan = (FloatControl) auline
.getControl(FloatControl.Type.PAN);
if (curPosition == Position.RIGHT)
pan.setValue(1.0f);
else if (curPosition == Position.LEFT)
pan.setValue(-1.0f);
}
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
}
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
auline.drain();
auline.close();
}
}
}
I'm guessing the sound last longer than 1 second. The int you pass to Timer is in milliseconds. It would seem to me that you are creating the sounds quicker than they can be played and this is clogging your application and blocking the UI (hence the "freeze").
I think using a Timer is the wrong way to repeatedly play the sound. You need instead to modify the sound file.
// as Sound
class RepeatSound {
...
public void run() {
// modify this condition to something meaningful
while (true) {
// as original Sound.run() in here
...
}
}
...
}
And call RepeatSound.start(). You must change that while(true) to exit with your application e.g. make it while (myFrame.visible()) to stop playing once the window is closed.
Some hints to solve the problem:
Swing Timer API states that a timer will repeat the notification to its listeners by default. It means you have an endless loop caused by this timer. See isRepeats() javadoc.
Consequently in each iteration a new thread playing a song is created which is not correct at all.
However as you don't have any interaction between swing components and played song you don't need a Swing timer actually. Just run your Song class in a separate thread than the EDT (Event Dispatch Thread) and it should be all right.
However, I wanted to continuously play the file...
As far as I can see in SourceDataLine interface API it extends from Line interface which allows you add LineListeners to listen LineEvents. Having said all this you may add a listener to restart the data line when it stops. I'd say it should look like something like this:
public class Sound extends Thread {
...
public void run()
...
auline.addLineListener(new LineListener() {
#Override
public void update(LineEvent e) {
if(e.getType() == LineEvent.Type.STOP && e.getLine().isOpen()) {
e.getLine().start();
}
}
});
auline.start();
...
}
...
}
Note: I really don't have time enough to play with this API so it's up to you test if it works. However I made an MP3 player for my cellphone using Java Mobile Media API and the approach was quite similar when I wanted to repeat the same song over again when it finishes.
I have faced an error with playing sounds on button click in java. I have a field of buttons and if any button is pressed application plays a sound. But application throws me an exception:
javax.sound.sampled.LineUnavailableException: unable to obtain a line
Method look like this and is called when button was pressed:
public void playSound() {
try {
File file = new File("Sounds/sound.wav");
AudioInputStream hitStream = AudioSystem.getAudioInputStream(file);
AudioFormat format = hitStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(hitStream);
clip.start();
} catch (Exception e) {
e.printStackTrace();
}
}
Sound play at the beginning then it crashes. I googled the exception, found that the clip should be closed after playing sound. I thought I should add lines after clip.start()
if (!clip.isRunning()) {
clip.stop();
clip.close();
}
But then the sounds don't play and whole application start to lag. What is the correct solution for this error?
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;