How can I add sound to my basic 'Sound Adventure' game?
I am a beginner and I want to make a basic sound adventure game. (Yes you heard it right, Sound Adventure.)
I know basics of Java and I can code text adventures, but I don't know how Sound works in Java quite yet. I've seen tutorials over the internet and they don't seem to work.
I am ready to change the format of my sound. (It's currently .mp3)
Also, I am using JDK 7 with Eclipse Kepler. (If that helps.)
Here's my code so far:
package everything;
import java.util.Scanner;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
public class Main {
public static void main(String[] args) {
// Declarations
System.out.println("Please Enter Your Name To Start...");
Scanner temp = new Scanner(System.in);
String name = temp.nextLine();
System.out.println("Okay " + name + ", Let's Get Started!");
System.out.println("Press N To Start The Game...");
while(!"N".equals(temp.nextLine())){
System.out.println("I Asked For The Letter N, Was It So Hard? Try Again!");
}
}
}
There's literally tons of resources with a simple Google Search.
Using JavaFX Framework
Simply use an instance of AudioClip. This one is very suitable for just playing single short sounds.
AudioClip plonkSound = new AudioClip("http://somehost/path/plonk.aiff");
plonkSound.play();
Using Standard Java API
Standard Java API is a little more painful, I don't have any experience with it but this piece of code has 60+ Upvotes on this related question.
public static synchronized void playSound(final String url) {
new Thread(new Runnable() {
// The wrapper thread is unnecessary, unless it blocks on the
// Clip finishing; see comments.
public void run() {
try {
Clip clip = AudioSystem.getClip();
AudioInputStream inputStream = AudioSystem.getAudioInputStream(
Main.class.getResourceAsStream("/path/to/sounds/" + url));
clip.open(inputStream);
clip.start();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}).start();
}
Related
I am trying to stop an intro song from playing when pressing the start button. I tried doing so using this code. Note that this code does not entail all my code. The GUI looks fine, the Actionlisteners work fine too. Only the music does not stop playing when the start button is pressed.
File introPath = new File("src/BattleshipGUI/423499__soundflakes__epic-heroic-orchestral-
dramatic.wav");
File buttonPressedPath = new File("src/BattleshipGUI/sfx_patcher_button_launch.wav");
static Clip introWAV;
Menu() {
super("BattleBoard");
this.setContentPane(this.panelMain);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.setLocationRelativeTo(null);
this.pack();
play(introPath); // playing when launching
// when the game starts, the sound should stop
ButtonStartGame.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
play(buttonPressedPath);
try {
if (random) {
currentCols = (Integer) spinnerColumns.getValue();
currentRows = (Integer) spinnerRows.getValue();
if (currentCols < 5 || currentRows < 5) {
throw (new IllegalArgumentException());
} else {
BoardFrame b = new BoardFrame(currentRows, currentCols);
b.SetFrame(currentRows, currentCols);
b.AddRandomShips(currentRows, currentCols);
b.ScoreMethod(adjustedScoreMethod);
introWAV.stop();
introWAV.flush();
introWAV.close();
dispose();
public static void SetIntroWAV(Clip clip){
introWAV=clip;
}
public static void play(File file) {
try {
Clip sound = AudioSystem.getClip();
sound.open(AudioSystem.getAudioInputStream(file));
SetIntroWAV(sound);
sound.start();
} catch (Exception e) {
System.out.println(e);
}
}
I tried other ways, like using while loops in the Play-class, 'if-else'-statements,... Does someone know how to fix this? Thanks in advance!
The culprit is part of your play method.
Whenever you want to play any sound you also call SetIntroWAV internally. This results in your introWAV variable being set.
Here's why that's a problem:
The first time you call play, your intro sound is played back and introWAV has the correct value.
However, once you start your game and play a different sound (namely using buttonPressedPath) your introWAV variable is set to a different value: the sound that was most recently started.
When you then try to stop your sound from playing, you're using introWAV which doesn't actually contain a reference to your intro sound anymore. Instead, this will result in your most recently played sound to be stopped since this is what introWAV is holding now.
To fix this, it's simply a case of only setting your introWAV variable once and not every time play is called. There are multiple ways of doing this, including these:
You could let your play method return the resulting Clip that will be played afterwards:
public static Clip play(File file) {
Clip sound = null;
try {
sound = AudioSystem.getClip();
sound.open(AudioSystem.getAudioInputStream(file));
sound.start();
} catch (Exception e) {
System.out.println(e);
} finally {
return sound;
}
}
You can then use this returned value to call SetIntroWAV once: SetIntroWAV(play(introPath));
You could also use this return value for other purposes like keeping local references to your sounds. However, you don't have to use it every time and can still ignore it whenever you don't need that reference.
You could rewrite your play method to also contain a parameter telling the method whether the sound you're trying to play is the intro sound:
public static void play(File file, boolean intro) {
try {
Clip sound = AudioSystem.getClip();
sound.open(AudioSystem.getAudioInputStream(file));
if(intro) {
SetIntroWAV(sound);
}
sound.start();
} catch (Exception e) {
System.out.println(e);
}
}
This will also result in SetIntroWAV only being called once.
I'd also recommend you use more of an object-oriented style of programming for this as it can make things like these much more obvious and easier to fix.
For example, you could create separate classes for audio playback and your gameplay.
IMHO the best practice with Clip variables is to load and open, and then hold them in memory. This can be done in a class that manages your sound effects. In that class, have a Clip as an instance variable and preload and open it in the constructor.
This class can also have two methods that are called from your game.
public void play() {
clip.setFramePosition(0); // ensures Clip will start from the beginning
clip.start();
}
public void stop() {
clip.stop();
}
With this sort of structure, it also become easier to manage multiple sounds. For example, you can have two instances of this sound-managing class, and set each to a different sound source. Then, you can readily stop one and start another.
so I am making a birthday present for a programmer friend of mine. I am not that good with code but I made a window + gif + sound. But once I test it on another PC the sound won't work anymore, but the JAR file is big enough to contain the WAV. PLease help me, I really want to make a nice birthday gift. Here is the Sound code + main
public static void play() {
try {
File file = new File("C:/Users/timma/IdeaProjects/BirthdayAshley/1" + ".wav");
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(file));
clip.start();
Thread.sleep(clip.getMicrosecondLength());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
public static void main(String[] args){
JFrame jf = new JFrame ("Happy Birthday");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(617,345);
jf.add(new Birthday());
jf.setVisible(true);
jf.setResizable(false);
play();
}
If the WAV is inside a JAR, it can't be referenced via a file.
But you can open it via Class.getResourceAsStream(). Everything else should stay the same.
InputStream stream =
SomeClassInTheSameJar.class.getResourceAsStream("/BirthdayAshley/1.wav");
use <MyClass>.class().getAsStream("/1.wav") to load the file. So it will loaded from your jar not with an absolut Path that not exists.
clip.open(AudioSystem.getAudioInputStream(<MyClass>.class.getAsStream("/1.wav")));
I'm relatively new to java (I took a 1 semester online class, so I know the basic structure of the language but my knowledge has lots of gaps). I'm trying to write a simple ear training application for a class in microtonal music I'm taking, and I obviously need to be able to play sound with this application. Looking on the web, a lot of the info I've found is out of date and I'm having trouble figuring out the APIs for Clip, Dataline, etc. (again, I'm new!) Is there a simple way to load sounds onto some kind of object (like an AudioClip maybe?) so they can be played back when necessary? If it's more complicated than that, I would appreciate being directed to resources that would help me figure how this process works.
You can use this method to play a audio clip using java application
public static synchronized void playSound(final String url) {
new Thread(new Runnable() {
// The wrapper thread is unnecessary, unless it blocks on the
// Clip finishing; see comments.
public void run() {
try {
Clip clip = AudioSystem.getClip();
AudioInputStream inputStream = AudioSystem.getAudioInputStream(
Main.class.getResourceAsStream("/path/to/sounds/" + url));
clip.open(inputStream);
clip.start();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}).start();
}
Here's another tutorial on java how to add audio clips. You can check this too Tutorial in playing sounds in Java
You will need to import the following:
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import java.io.File;
import java.io.FileNotFoundException;
I created a method for playing the audio clip, as shown below:
public static void myMusic() throws FileNotFoundException {
try {
File wavFile = new File(/*file path*/);
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(wavFile));
clip.start();
} catch (Exception e) {
System.out.println(e);
}
}
Let's say for example, if your audio clip's file name is music.wav, your file path may be:
File wavFile = new File("music.wav");
Finally, to play the audio clip, you will need to call the method.
I am using java and trying to write a simple sudo mouse recorder that will store the mouse position when the space key is pressed. The only key I need to detect is the space key (Although if another key is easier, that will work).
I need the whole mouse recorder to be written in java, but it is OK if the function for the keypress is in another language. And I will be runing this in Windows 7.
What is the simplest way to do what has been described? All of the methods I have found require at minimum 20 lines of code. This is OK, except I don't understand how to implement them. I have an example source below:
import java.awt.MouseInfo;
import javax.swing.JOptionPane;
public class MouseRecorder {
public static void main (String[] args)
{
int slot = 0;
int xLoc[10];
int yLoc[10];
while (slot <= 10)
{
if (keyPressed(KEY_SPACE)) //<<<<This obviously won't work, but I'm looking for the simplest way to code this
{
xLoc[slot] = MouseInfo.getPointerInfo().getLocation().x;
yLoc[slot] = MouseInfo.getPointerInfo().getLocation().y;
slot++;
}
}
//The mouse information can now be utilized
}
}
Again your question is not clear since you have not addressed my comment:
It smells like to me that you might want a system-wide key logger that only responds to one key press, and that doesn't need a GUI. If this is so, then your best solution is to not use Java to create your application but to use a tool that can get closer to the OS. AutoIt comes to mind if this is for a Windows project. Please define your needs better.
and this forces us to guess at the problem and its solution.
If you are interested in creating a Swing GUI, having it take focus, and have it listen to key events, then the solution is to do this:
Create your Swing GUI and display it, leaving it as the active windowed application while your application is running.
Using Key Bindings have it listen for space bar presses
And then log the mouse location when the space bar is pressed.
As noted, this will not be achievable in 5 lines of code, so put that idea to the side.
If on the other hand your desire is to not have a GUI but rather listen for hot-key presses while any and all applications are running, then
The possible platforms used will be critical since your solution will require OS-specific code since creating a hot-key means having to create a keyboard handler routine, often in C, and doing this for each platform, and then linking it in to Java using JNI or JNA.
Or as noted another way is to link your Java program with an OS specific utility program or script such as AutoIt.
If you need more specific help, then please clarify your question.
Edit
You state:
Thank you for the answer, but as I have described above: "Changing languages is out of the question although it seems like that might be easier." and "I dont want a gui, if I can avoid it"
Then my second answer is what you're looking for. How adept are you at C/C++, JNI or JNA, and how good is your knowledge of operating system libraries? If you want a Java only solution, I would consider your requirements far above beginner or intermediate Java and into the realm of advanced -- or at least beyond my abilities at the moment, although I am sure that I could come up with some solutions after several days to a week or two of study.
... or consider getting rid of your "changing languages" requirement and instead allow at least meshing Java together with a scripting utility, like AutoIt. That could allow creation of solutions in a shorter period of time, at least for me. A limitation though is that these would be platform specific solutions. What is your purpose behind all of this? Could this be an XY problem in disguise?
Edit 2
I decided to try to solve this with a small AutoIt utility that I meshed with Java, and this is what I came up with.
My AutoIt program is called CaptureHotKey.au3, and it is compiled to an exe before use:
$key = $CmdLine[1]
HotKeySet($key, "hotKeyFunction")
While 1
Sleep(100)
WEnd
Func hotKeyFunction()
ConsoleWrite(#CRLF)
EndFunc
There's not much to it. All it does is set a hot-key from the first command line parameter, provides an endless while loop so that it will continue to run, and a hotkey function that is quite simple and only sends a carriage-return/line-feed to the console (which will be the standard output).
Then a Java class to help interact with this. It uses SwingPropertyLanguageSupport to allow addition of PropertyChangeListeners that respond on the Swing thread (in case I want to use this with a GUI).
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.swing.event.SwingPropertyChangeSupport;
public class CaptureHotKey implements Runnable {
public static final String HOT_KEY = "hot key";
private String hotKey;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
private Scanner scanner;
private CaptureHotKeyFromAutoIt capture;
public CaptureHotKey(final String hotKey) throws IOException {
this.hotKey = hotKey;
capture = new CaptureHotKeyFromAutoIt(hotKey);
scanner = new Scanner(capture.getReadable());
}
public void startCapturing() {
new Thread(this).start();
}
public void exit() {
if (capture != null) {
capture.exit();
}
if (scanner != null) {
scanner.close();
}
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public String getHotKey() {
return hotKey;
}
#Override
public void run() {
while (scanner != null && scanner.hasNextLine()) {
scanner.nextLine();
pcSupport.firePropertyChange(HOT_KEY, true, false);
}
}
private static class CaptureHotKeyFromAutoIt {
public static final String AUTO_IT_APP_PATH = "CaptureHotKey.exe";
private Process process = null;
private ProcessBuilder pb;
public CaptureHotKeyFromAutoIt(String hotKey) throws IOException {
List<String> cmdList = new ArrayList<>();
cmdList.add(AUTO_IT_APP_PATH);
cmdList.add(hotKey);
pb = new ProcessBuilder(cmdList);
pb.redirectErrorStream(true);
process = pb.start();
}
public void exit() {
if (process != null) {
process.destroy();
}
}
public Readable getReadable() {
if (process != null) {
return new InputStreamReader(process.getInputStream());
}
return null;
}
}
}
Finally a Java class to test this set up:;
This adds a PropertyChangeListener to the class above to allow it to be notified if the hot-key is pressed:
import java.awt.MouseInfo;
import java.awt.PointerInfo;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Scanner;
public class CaptureHotKeyTest {
public static final String CTRL_R = "^r"; // "{SPACE}" works for spacebar
private static final String EXIT = "exit";
private CaptureHotKey capture;
public CaptureHotKeyTest() {
try {
capture = new CaptureHotKey(CTRL_R);
capture.addPropertyChangeListener(new HotKeyPropertyChngListener());
capture.startCapturing();
Scanner scan = new Scanner(System.in);
System.out.println("Press control-r to get mouse position.");
System.out.println("Type \"exit\" to exit program");
while (scan.hasNextLine()) {
String line = scan.nextLine();
if (line.equalsIgnoreCase(EXIT)) {
scan.close();
capture.exit();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private class HotKeyPropertyChngListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(CaptureHotKey.HOT_KEY)) {
System.out.println("hot key pressed");
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
System.out.println("Mouse: " + pointerInfo.getLocation());
}
}
}
public static void main(String[] args) {
new CaptureHotKeyTest();
}
}
You should use KeyListener: http://docs.oracle.com/javase/tutorial/uiswing/events/keylistener.html
It works fine with Swing
I want to add audio to my java game, but I don't know how to put it in practice. By I've read, Java only plays wav files, but this files are too big.
I've read a little about JLayer, but I actually need something like soundpool in android, for handle all in game effects. Do you know how to do it? I've to build a class that does it?
Here is some code for you that I've used in a game a while back using JLayer:
public class MP3 {
public void play(final InputStream in) {
new Thread() {
#Override
public void run() {
try {
new Player(in).play();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}.start();
}
}
private HashMap<String, URL> soundMap = new HashMap<String, URL>();
public void loadSounds() {
String[] filenames = {
"5_seconds_remaining.mp3",
"10_seconds_remaining.mp3",
"button_press_loud.mp3"
};
for (String s : filenames) {
soundMap.put(s.substring(0, s.indexOf('.')), getClass().getResource("sounds/" + s));
}
}
public void playSound(String name) {
try {
new MP3().play(new BufferedInputStream(soundMap.get(name).openStream()));
} catch (IOException ex) {}
}
I recommend TinySound. It supports ogg/vorbis files (a free compression format comparable to mp3, but does not require licensing as mp3 does).
http://www.java-gaming.org/topics/need-a-really-simple-library-for-playing-sounds-and-music-try-tinysound/25974/view.html
A link is provided there to the github source for this library.
It is also possible to use Java as a synthesizer (I've been dabbling with this) but I'm still working on making something 'practical' for use in a game.