I'm using java to try and make an alarm of sorts. I want to input a time and then when it hits zero, play a specific .mp3. The countdown works fine, but when it hits zero and tries to play the mp3, it can't find the file. Advice? I've already searched the site and can't find anything simple enough for me to use (I'm a beginner). Here's what I got so far:
public static void main(String[] args) {
int timer;
File song = new File("C:/Users/N/Documents/Random/Handies/Proj/Song.mp3");
timer = 1;
timer*=1;
while (timer != 0)
{
try
{
Thread.sleep(1000);
} catch (InterruptedException e) {}
timer -= 1;
System.out.println(timer);
}
if (timer == 0)
Play(song);
}
public static void Play(File song)
{
try
{
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(song));
clip.start();
}
catch (Exception exc)
{
exc.printStackTrace(System.out);
}
}
With JavaFX you can easily play the MP3 like this:
public class Test extends javafx.application.Application {
#Override
public void start(Stage primaryStage) throws Exception {
File file = new File("/path/test.mp3");
Media media = new Media(file.toURI().toString());
MediaPlayer mediaPlayer = new MediaPlayer(media);
mediaPlayer.play();
}
}
I usually find it hard using AudioSystem for this kind of thing.
Related
I'm working on a snake clone project and am having trouble implementing a feature where the background music stops only during my game over screen.
My music plays during the first round of gameplay but won't start up again after I press the reset key for the game. I've debugged as far as to see that the thread I created to loop the music dies at game-over, and I'm not sure how to fix this.
SoundFX backgroundSongLoop = new SoundFX(backgroundSong, true);
public Gameplay() {
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
//the speed of the snake
timer = new Timer(clockSpeed, this);
backgroundSongLoop.start();
timer.start();
}
public void paint(Graphics g){
//region Snake-Snake Collision
for (int b=1; b<lengthOfSnake; b++){
if(snakeXLength[b]==snakeXLength[0] && snakeYLength[b]==snakeYLength[0]){
backgroundSongLoop.setOn(false);
failedSoundFX.playSound(failSound);
failed=true;
timer.stop(); }
//region restart function
if (failed){
if (e.getKeyCode()==KeyEvent.VK_SPACE) {
backgroundSongLoop.setOn(true);
score = 0;
lengthOfSnake = 3;
moves = 0;
repaint();
timer.start();
}
}
//endregion
public class SoundFX extends Thread{
private final String soundName;
public boolean isOn;
public SoundFX(String soundName) {
this.soundName = soundName;
}
public SoundFX(String soundName, boolean isOn) {
this.soundName = soundName;
this.isOn = isOn;
}
public void setOn(boolean on) {
isOn = on;
}
public void playSound(String soundName){
File soundFile = new File(soundName);
try{
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(soundFile));
clip.start();
} catch (Exception e){
e.printStackTrace();
}
}
#Override
public void run() {
//public void loopSong(String soundName, boolean playing){
File soundFile = new File(soundName);
try{
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(soundFile));
while (isOn){
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
while (!isOn){
clip.stop();
}
} catch (Exception e){
e.printStackTrace();
}
}
}
Two things:
Use clip.setFramePosition(0) to position the clip for restarting at the beginning.
Put the clip.open() method in a constructor and make clip an instance variable. That way, when you wish to restart it, only the following is needed:
public void play() {
clip.setFramePosition(0);
clip.loop();
}
By doing this, you avoid reloading from the file location every time you wish to play the cue. The cue won't even start until all the file operations are done, so this method gives you a much quicker start.
I think if you do this, you can also write a method that calls clip.stop() and just call all of these methods directly on your SoundFX class without needing to extend Thread.
I've been trying to play sound1 and sound2 using AudioClips. This is my code:
import javax.sound.sampled.*;
public class Sound {
private Clip clip;
public static final Sound sound1 = new Sound("src/Sounds/Classic_Horror_2.wav");
public static final Sound sound2 = new Sound("src/Sounds/Classic Horror 3.mp3");
public Sound (String fileName) {
try {
AudioInputStream ais = AudioSystem.getAudioInputStream(Sound.class.getResource(fileName));
clip = AudioSystem.getClip();
clip.open(ais);
} catch (Exception e) {
e.printStackTrace();
}
}
public void play() {
try {
if (clip != null) {
new Thread() {
public void run() {
synchronized (clip) {
clip.stop();
clip.setFramePosition(0);
clip.start();
}
}
}.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void stop(){
if(clip == null) return;
clip.stop();
}
public void loop() {
try {
if (clip != null) {
new Thread() {
public void run() {
synchronized (clip) {
clip.stop();
clip.setFramePosition(0);
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
}
}.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean isActive(){
return clip.isActive();
}
}
When I try to do Sound.sound1.loop(); or Sound.sound1.play(); I get a null pointer exception. Same goes for sound2. Here are the exact errors messages:
java.lang.NullPointerException
at com.sun.media.sound.StandardMidiFileReader.getSequence(StandardMidiFileReader.java:207)
at javax.sound.midi.MidiSystem.getSequence(MidiSystem.java:841)
at com.sun.media.sound.SoftMidiAudioFileReader.getAudioInputStream(SoftMidiAudioFileReader.java:178)
at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1147)
at Sound.<init>(Sound.java:12)
at Sound.<clinit>(Sound.java:7)
at IntroductionComponent.<init>(IntroductionComponent.java:54)
at IntroductionGUI.main(IntroductionGUI.java:9)
java.lang.NullPointerException
at com.sun.media.sound.StandardMidiFileReader.getSequence(StandardMidiFileReader.java:207)
at javax.sound.midi.MidiSystem.getSequence(MidiSystem.java:841)
at com.sun.media.sound.SoftMidiAudioFileReader.getAudioInputStream(SoftMidiAudioFileReader.java:178)
at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1147)
at Sound.<init>(Sound.java:12)
at Sound.<clinit>(Sound.java:8)
at IntroductionComponent.<init>(IntroductionComponent.java:54)
at IntroductionGUI.main(IntroductionGUI.java:9)
I have repeatedly browsed stackoverflow to look for possible fixes, however it may be that fileName returns null constantly, or that my URL's are somehow incorrect. That said, for all I know it could be anything. Any suggestions on how to fix this?
The inclusion of src in your paths...
public static final Sound sound1 = new Sound("src/Sounds/Classic_Horror_2.wav");
public static final Sound sound2 = new Sound("src/Sounds/Classic Horror 3.mp3");
is your key problem, src won't exist once the application is build and package, you should never refer to src ever.
You should probably be using something more like...
public static final Sound sound1 = new Sound("/Sounds/Classic_Horror_2.wav");
public static final Sound sound2 = new Sound("/Sounds/Classic Horror 3.mp3");
public Sound (String fileName) {
try {
AudioInputStream ais = AudioSystem.getAudioInputStream(getClass().getResource(fileName));
clip = AudioSystem.getClip();
clip.open(ais);
} catch (Exception e) {
e.printStackTrace();
}
}
Personally, I'd make Sound require a URL...
public Sound (URL url) {
try {
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
clip = AudioSystem.getClip();
clip.open(ais);
} catch (Exception e) {
e.printStackTrace();
}
}
This way there's no confusion over what String means and you can pass a reference from embedded resources, file references or even from the net
Also from memory, clip.start() creates it's own thread, so there's no need to create your own
In the board game I am designing, each user has a grid with 100 cells. The user clicks a cell in the computer's grid, which makes a sound and changes to a different colour. The computer then automatically clicks a cell in the user's grid, which makes a sound and changes to a different colour.
The user's clicks are dealt with via the MouseListener (and the MouseClicked method). Currently, the last thing the method does is call the computerMove() method. This method executes and performs the computer move before giving changing the current player back to human. The game proceeds when the human makes another mouse click.
Ideally, I'd like to have a pause (perhaps a second) between each player move. However, due to the fact the computerMove method is being called inside the MouseClicked method, this is proving troublesome. By using Thread.sleep and even a TimerTask, the best I can do is to slow the human player's move down. However, as soon as the player makes a mouse click, the computer instantaneously responds.
Does anybody have any suggestions as to how I could implement a delay? Do I need to change how I am calling the methods?
ComputerMove method:
public void computerMove() {
if (currentTurn == computer) {
int xPos = randomGenerator.nextInt(10);
int yPos = randomGenerator.nextInt(10);
LogicCell attackedCell = new LogicCell(xPos, yPos);
playerGridLogic.addCellsThatHaveBeenAttacked(attackedCell);
if (playerGridLogic.getCellsWithShips().contains(attackedCell)) {
playerGrid.getCellArray()[xPos][yPos].setBackground(Color.ORANGE);
hitSound();
}
else {
playerGrid.getCellArray()[xPos][yPos].setBackground(Color.MAGENTA);
missSound();
}
nextTurn();
}
}
Corresponding MouseClick method:
#Override
public void mouseClicked(MouseEvent e) {
if (allComputerShipsPlaced && currentTurn == human) {
ViewCell currentCell = (ViewCell) e.getSource();
xPos = currentCell.getXPos();
yPos = currentCell.getYPos();
LogicCell attackedCell = new LogicCell(xPos, yPos);
computerGridLogic.addCellsThatHaveBeenAttacked(attackedCell);
if (computerGridLogic.getCellsWithShips().contains(attackedCell)) {
cellArray[xPos][yPos].setBackground(Color.ORANGE);
hitSound();
}
else {
cellArray[xPos][yPos].setBackground(Color.MAGENTA);
missSound();
}
nextTurn();
computerMove();
}
}
missSound method() (hitSound is very similar):
public static void missSound() {
try {
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File("water-splash.wav")));
clip.start();
}
catch (Exception exc)
{
exc.printStackTrace(System.out);
}
}
Edit: I've tried changing the sound classes to this, but to no avail:
public static void hitSound()
{
try
{
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File("bomb-explosion.wav")));
clip.start();
LineListener listener = new LineListener() {
public void update(LineEvent event) {
if (event.getType() != Type.STOP) {
return;
}
try {
queue.take();
} catch (InterruptedException e) {
//ignore this
}
}
};
clip.addLineListener(listener);
}
catch (Exception exc)
{
exc.printStackTrace(System.out);
}
}
You should be able to add a listener and react to the end of the sound.
See this question: how can I wait for a java sound clip to finish playing back?
This works for me:
public class Test {
public static void main(String[] args) {
final Object foo = new Object();
Clip clip;
try {
clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File("go.wav")));
clip.addLineListener(new LineListener() {
public void update(LineEvent event) {
if(event.getType() == LineEvent.Type.STOP){
System.out.println("done playing");
synchronized(foo) {
foo.notify();
}
}
}
});
clip.start();
} catch (Exception e) {
e.printStackTrace();
}
synchronized(foo) {
try {
foo.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
I would consider calling computerMove inside nextTurn, and do the waiting inside nextTurn.
You could use Thread.sleep in computerMove() to pause the execution. You can use clip.getMicrosecondsLength to get the length of the sound effect in microseconds. Multiply it with 1000 and pass it to sleep to wait for the sound effect to finish.
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File("water-splash.wav")));
clip.start();
int lengthInMilliseconds = clip.getMicrosecondLength() * 1000;
Thread.sleep(lengthInMilliseconds);
I've searched and read another topics but i still can't solve my problems. I had one java main class and one java jframe. I wanna add jslider to change volume in my mp3 player. What should i do?
my_player2_func
class my_player2_func{
static Player player;
static void play() {
try {
FileInputStream fe = new FileInputStream(my_player2_main.str);
player = new Player(fe);
} catch (Exception ex) {
System.out.println(ex);
}
new Thread(new Runnable() {
#Override
public void run() {
try {
player.play();
} catch (Exception ex) {
System.out.println(ex);
}
}
}).start();
}
static void stop() {
if (player != null)
player.close();
} }
my_player2_main
public my_player2_main() {
initComponents();
}
static String str;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
my_player2_func.play();
}
private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {//what should i do here?}
JLayer is a decoder. By its very definition it does not know anything about volume, thats the job of the audio hardware that plays the sound.
Your problem stems from the fact that you are using the Player and defaul JavaSoundAudioDevice classes, which were meant as short, simple examples how to play an MP3, not as building blocks for a full fledged audio player.
You will have to copy or modify the source of JavaSoundAudioDevice (part of JLayer source) and hack it to support volume control. Et voila you can control volume.
I have created a class to play the sound when I click the buttons.
Here is the code :
public void playSound()
{
try
{
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("beep-1.wav"));
Clip clip = AudioSystem.getClip( );
clip.open(audioInputStream);
clip.start( );
}
catch(Exception e)
{
System.out.println("Error with playing sound.");
}
}
When I want to implement it into the the ButtonListener method, it's seem like no sound is played.
Here the ButtonListener code :
private class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (replayButton == e.getSource())
{
playSound();
}
}
}
What's wrong with the code?
EDIT :
Basically I'm trying to create a simple memory game, and I want to add sound to the buttons when clicked.
SOLVED :
Seems like the audio file I downloaded from Soundjay got problem, and hence, the audio file can't be played. #_#
Use
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
playSound();
}
});
This should work:
public class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
public Test() {
JButton button = new JButton("play");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
playSound();
}});
this.getContentPane().add(button);
this.setVisible(true);
}
public void playSound() {
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("beep.wav"));
Clip clip = AudioSystem.getClip( );
clip.open(audioInputStream);
clip.start( );
}
catch(Exception e) {
e.printStackTrace( );
}
}
}
Note that during the play of your file, the GUI will be not responsable. Use the approach from Joop Eggen in your listener to correct this. It will play the file asynchronous.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
playSound();
}
});
Any stacktrace, please??? did you add listener to the button???
Anyway the standart way have some bugs when targeting cross-platform. Use Java Media Framework at http://www.oracle.com/technetwork/java/javase/tech/index-jsp-140239.html.