Simple GUI application for playing sound clips after user selects one with a radio button and pushes the play button. After clean and build, execution from the JAR file results in no sound being played when a clip is selected and the play button is pushed.
Conditions: NetBeans IDE, sounds play successfully in the IDE pathed to the package, path to .wav files in JAR is correct, files are in the executable JAR in the correct directory, uses 2 classes: one for the GUI and a .wav handler class (both work successfully in the IDE. More details in screen shots. I am thinking that there should be a getResource() method call in the Player calss but I don't know how to write it.
The code snippet used to call the resource from within the GUI class. The base is new Player("whateverthefilepathis").start(). (this works fine in the IDE, so no issue there):
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
if (jRadioButton1.isSelected()){
URL file = QuotesButtonUI.class.getResource("/my/sounds/fear_converted.wav");
new Player (file.getFile()).start();
}
else if (jRadioButton2.isSelected()){
URL file = QuotesButtonUI.class.getResource("/my/sounds/initiated_converted.wav");
new Player (file.getFile()).start();
}
This is the Player class used to process the .wav. Within the GUI class, I am using the new Player().start() call. I am thinking that there should be a getResource() call in the Player class but I don't know for sure.
package my.quotesbutton;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
public class Player extends Thread {
private String filename;
private Position curPosition;
private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb
enum Position {
LEFT, RIGHT, NORMAL
};
public Player(String wavfile) {
filename = wavfile;
curPosition = Position.NORMAL;
}
public Player(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();
}
}
}
You can't access anything inside a jar file using the java.io.File API, simply because items inside a jar are not files.
You need indeed, as you suspected, to use a getResource() method (or getResourceAsStream()): http://docs.oracle.com/javase/tutorial/deployment/webstart/retrievingResources.html
That may look counterintuitive at first, but getResource() works with files as well as jars (or even remote located resources in case of a webapp, as in the linked tutorial), the ClassLoader will deal with the dirty details how the resource is physically accessed. In short: never use the File API for resources - resources should only be accessed using the resource API.
Related
I'm making game extension to play some sounds. The sounds may be triggered at random times, which means that the same sound may be triggered twice with very little time apart. In this case, the sound should start playing even though it is already playing (if that makes sense).
I'm using a Clip to play the sound. This means that I have to "rewind" the clip before playing it. It seems, since it's the same clip, that it stops playing before re-starting. What I want is for it to continue playing, and play the same clip "on top" of the previos one. See this example:
import java.io.File;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class JavaApplication {
public static void main(String[] args) throws Exception {
File file = new File(JavaApplication.class.getResource("1.wav").getPath());
AudioInputStream inputStream = AudioSystem.getAudioInputStream(file);
Clip clip = AudioSystem.getClip();
clip.open(inputStream);
clip.setFramePosition(0);
clip.start(); // The sound is 300 ms long
Thread.sleep(150); // Let it play for 150 ms
clip.setFramePosition(0); // Attempt to start it from the beginning, without stopping it
clip.start();
Thread.sleep(1000);
}
}
Have you tried creating a duplicate object when you need it and destroy it when it's finished? A new Clip object or just copy the original and get it to play along with it.
Clip temp = clip;
temp.start(); // The sound is 300 ms long
Thread.sleep(150); // Let it play for 150 ms
temp = null;
Just a suggestion, you could also try using Clip[] arrays to handle a few clips playing at different times.
You need to create two AudioInputStream instances. No need to use multi thread exlicitly in your code. Hop it will help. Thanks.
import java.io.File;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class JavaApplication {
public static void main(String[] args) throws Exception {
File file = new File(JavaApplication.class.getResource("1.wav").getPath());
AudioInputStream inputStream1 = AudioSystem.getAudioInputStream(file);
AudioInputStream inputStream2 = AudioSystem.getAudioInputStream(file);
Clip clip = AudioSystem.getClip();
clip.open(inputStream1);
clip.setFramePosition(0);
clip.start();
// Clip is 2000 ms long. let it play for 1000 ms
Thread.sleep(1000);
Clip clip2 = AudioSystem.getClip();
clip2.open(inputStream2);
clip2.setFramePosition(0);
clip2.start();
Thread.sleep(2000);
}
}
Found a solution: Read the raw bytes of the sound, and create a inputstream from the data each time I play the sound. This enables me to play the same sound file "on top of itself" without loading it from disk more than once.
package com.mysite.javaapplication;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class JavaApplication {
private static void playSoundBytes(byte[] data) throws Exception {
AudioInputStream inputStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(data));
AudioFormat format = inputStream.getFormat();
Clip clip = AudioSystem.getClip();
clip.open(inputStream);
clip.setFramePosition(0);
clip.start();
}
private static byte[] getResourceAsBytes(String name, int bufferSize) throws IOException {
InputStream stream = JavaApplication.class.getResourceAsStream(name);
byte buffer[] = new byte[bufferSize];
int b, i = 0;
while ((b = stream.read()) != -1) {
try {
buffer[i++] = (byte) b;
} catch (IndexOutOfBoundsException e) {
throw new IOException("Buffer of " + bufferSize + " bytes is too small to read resource \"" + name + "\"");
}
}
byte data[] = new byte[i + 1];
while (i >= 0) {
data[i] = buffer[i];
i--;
}
return data;
}
public static void main(String[] args) throws Exception {
byte[] soundData = getResourceAsBytes("/1.wav", 1000*1000);
playSoundBytes(soundData);
Thread.sleep(1000);
playSoundBytes(soundData);
Thread.sleep(2000);
}
}
I created a gfx folder inside an android project's assets folder. I stored images which i will be using in my game for android. Since i need to pass the image height and image width converting it to the nearest highest powwer of 2 in andEngine, so i create a ImageUtility class to read image inside the gfx folder and get its height and width.
package org.ujjwal.androidGameUtility;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageUtilities {
private static final String ABSOLUTE_PATH = "F:\\Games\\TowerOfHanoi\\assets\\gfx\\";
private String fileName = "";
private File imageFile;
private int imageHeight;
private int imageWidth;
public ImageUtilities(String filename){
this.fileName = filename;
this.imageFile = new File(ABSOLUTE_PATH + this.fileName);
try {
processImage();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* this methods set the doucment relative path for the graphics to be used
* and it is mandotry to call before using ImageUtilties object else it will throw filenotFoundException
*
* #param path
*/
private void processImage() throws FileNotFoundException{
if(imageFile.exists()){
try {
BufferedImage image = ImageIO.read(this.imageFile);
this.imageWidth = image.getWidth();
this.imageHeight = image.getHeight();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else{
throw new FileNotFoundException("Either you missed typed filename or haven't called setAssetBasePathMethod setImageBasePath(String path) method");
}
}
public int getImageHeight(){
return this.imageHeight;
}
public int getImageWidth(){
return this.imageWidth;
}
public String getFileName(){
return this.fileName;
}
public File getImageFile(){
return this.imageFile;
}
}
I always get FileNotFoundException with the error msg above. The weird problem is when i access the image file from other java class i don't get any error. I printed the height and width all went exactly i wanted but i could not access the same image file from my android game project. What kind of error is this. I provided absolute filepath for the image. I also tried to compare the file path they were same. Please tell me what error i got, I spend whole day trying to figure out but ...
What #mittmemo mentioned was right, you cannot access the F drive from your phone or emulator. Your computer and android are two different OS. What you can do is instead of putting your file in /assets, you can put it in /raw under resource directory. You can then access it by using:
try {
Resources res = getResources();
InputStream in_s = res.openRawResource(R.raw.yourfile);
byte[] b = new byte[in_s.available()];
in_s.read(b);
String str = new String(b);
} catch (Exception e) {
Log.e(LOG_TAG, "File Reading Error", e);
}
I'm currently working on my first game in java and i'm trying to implement sounds when the spaceship is getting hit.. this is my code . I get a null pointer exception but my sound is in the right place "workspace/project/src/sounds/"
public class GameSounds
{
public static synchronized void hit()
{
try
{
Clip clip = AudioSystem.getClip();
AudioInputStream inputStream = AudioSystem.getAudioInputStream(GameSounds.class.getResourceAsStream("sounds/8bit_bomb_explosion.wav"));
clip.open(inputStream);
clip.start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
here is the stacktrace
java.lang.NullPointerException
at com.sun.media.sound.SoftMidiAudioFileReader.getAudioInputStream(Unknown Source)
at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
at sound.GameSounds.hit(GameSounds.java:16)
at main.Main.doLogic(Main.java:135)
at main.Main.run(Main.java:101)
at java.lang.Thread.run(Unknown Source)
package sound;
import java.io.InputStream;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class GameSounds
{
public static synchronized void hit()
{
try
{
String resPath = "/sounds/8bit_bomb_explosion.wav"; // *** this is the key ***
InputStream audioInStream = GameSounds.class.getResourceAsStream(resPath);
System.out.println("is audioInStream null?: " + (audioInStream == null)); // test it!
AudioInputStream inputStream = AudioSystem.getAudioInputStream(audioInStream); Clip clip = AudioSystem.getClip();
clip.open(inputStream);
clip.start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
thanks for advices now it works
In all likelihood, you are not getting the resource with the correct path. Understand that resource paths are based on where the class loader looks to load class files and not on where the src or "user.dir" directory is.
Perhaps you want to do:
// almost always better to break up a long code line into smaller lines.
String resPath = "/sounds/8bit_bomb_explosion.wav"; // *** this is the key ***
InputStream audioInStream = GameSounds.class.getResourceAsStream(resPath);
System.out.println("is audioInStream null?: " + (audioInStream == null)); // test it!
AudioInputStream inputStream = AudioSystem.getAudioInputStream(audioInStream);
Again the path String will depend on where your class files are located in relation to your src directory.
I have had the same problems. But after searching for hours I found Javazoom which is a external libery you can import into your project and makes it much more easy to play sounds:
http://www.javazoom.net/index.shtml
You can use it like this:
import javazoom.jl.player.advanced.*;
class SoundJLayer extends PlaybackListener implements Runnable
{
private String filePath;
private AdvancedPlayer player;
private Thread playerThread;
public SoundJLayer(String filePath)
{
this.filePath = filePath;
}
public void play()
{
try
{
String urlAsString =
"file:///"
+ new java.io.File(".").getCanonicalPath()
+ "/"
+ this.filePath;
this.player = new AdvancedPlayer
(
new java.net.URL(urlAsString).openStream(),
javazoom.jl.player.FactoryRegistry.systemRegistry().createAudioDevice()
);
this.player.setPlayBackListener(this);
this.playerThread = new Thread(this, "AudioPlayerThread");
this.playerThread.start();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
public void stop() {
player.stop();
}
// PlaybackListener members
public void playbackStarted(PlaybackEvent playbackEvent)
{
}
public void playbackFinished(PlaybackEvent playbackEvent)
{
}
// Runnable members
public void run()
{
try
{
this.player.play();
}
catch (javazoom.jl.decoder.JavaLayerException ex)
{
ex.printStackTrace();
}
}
}
After that you just have to create a new SoundJLayer-Object and start ir with play()
Hope this is helpful,
Jan
So I'm trying to load a file using a jar. The file is outside of the jar, but in the same folder. When I run the jar form the terminal using java -jar Test.jar it works just fine, but if I run it by double clicking the jar it does not correctly load from the file. I can load external Images just fine with either method, but not a file I have created. This is running on Mac OSX. This problem also seems to exist on Ubuntu. On Windows, however, the File is loaded even more incorrectly.
The Path loaded from seems to be the same for both cases. When running from terminal, the output for numbers is correct. However, when running by double clicking, any number over 127 is loaded improperly. I have researched for hours for a solution, with no avail.
EDIT: This is my manifest
Main-Class: Test
I have created this simple application to demonstrate my problem.
This is what writes the file that will be read.
import java.io.*;
public class TestWriter{
public static void main(String[] args){
try{
// Create the file and FileWriter.
FileWriter out = new FileWriter(new File("test.map"));
// Write some test numbers.
for (int i = 0; i < 481; i += 30)
out.write(i);
// Flush the output (for good measure?)
out.flush();
// Close the output.
out.close();
} catch (IOException e){
e.printStackTrace();
}
}
}
This is what loads the file.
import javax.swing.JComponent;
import java.awt.*;
import java.net.*;
import java.io.*;
import javax.imageio.*;
import java.awt.image.*;
public class Run extends JComponent{
// Image to be drawn on screen
BufferedImage IMAGE;
// Output to be drawn on screen
String string = "";
// Loading a MAP file - includes loading a bmp image and a .map (txt file).
public Run(){
// MAP name
String map = "test";
System.out.println("Loading map: "+map);
// Get path
String path = getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = "";
// Decode path
try{
decodedPath = URLDecoder.decode(path, "UTF-8");
decodedPath = decodedPath.substring(0, decodedPath.lastIndexOf("/") + 1);
} catch (Exception e){
System.out.println("Could not decode path.");
e.printStackTrace();
System.exit(1);
}
// Add decoded path to output string
string += decodedPath;
try{
IMAGE = ImageIO.read(new File(decodedPath+"/"+map+".bmp"));
System.out.println("MAP image loaded.");
} catch (IOException e){
System.out.println("Could not load MAP image.");
e.printStackTrace();
System.exit(1);
}
try{
System.out.println("Loading MAP data.");
// Create a new reader
FileReader in = new FileReader(new File(decodedPath+"/"+map+".map"));
// While there is something left to be read
while (in.ready()){
// add the next input to the output string
string += ", "+in.read();
}
// Close the input (for good measure)
in.close();
System.out.println("Loaded MAP data.");
} catch (Exception e){
System.err.println("Could not load MAP data.");
e.printStackTrace();
System.exit(1);
}
// Repaint the screen to show our newly loaded image and string
repaint();
}
public void paint(Graphics g){
g.drawImage(IMAGE,0,0,null);
g.drawString(string,16,64);
}
}
This is the main method that creates the JFrame and adds the component Run()
import javax.swing.JFrame;
import javax.swing.JComponent;
public class Test{
public static void main(String[] args){
System.out.println("\nInitializing...");
JFrame frame = new JFrame("Test");
int frameWidth = 640;
int frameHeight = 200;
frame.setSize(frameWidth,frameHeight);
frame.setResizable(false);
frame.setLocation(240,60);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Run());
frame.setVisible(true);
System.out.println("Running...");
}
}
While playing an audio file (.wav) I want, if I resort to Ctrl+C, to stop the playback and save part of the audio file in a file called "file2.wav".
Here's the thread I'd like to add to my code.
Unfortunately it doesn't work at all.
class myThread extends Thread{
public void run(){
try {
PipedOutputStream poStream = new PipedOutputStream();
PipedInputStream piStream = new PipedInputStream();
poStream.connect(piStream);
File cutaudioFile = new File ("file2.wav");
AudioInputStream ais =
new AudioInputStream(piStream,
AudioFileFormat.Type.WAVE,
cutaudioFile);
poStream.write(ais,AudioFileFormat.Type.WAVE,cutaudioFile);
}catch (Exception e){
e.printStackTrace();
}
} // end run
} // end myThread
This should be basically what you want. It uses a shutdown hook.
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.sound.sampled.Clip;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class CtrlCAudio
{
public static void main(String[] args) throws LineUnavailableException, UnsupportedAudioFileException, IOException
{
final File inputAudio = new File(args[0]);
final File outputAudio = new File(args[1]);
// First, we get the format of the input file
final AudioFileFormat.Type fileType = AudioSystem.getAudioFileFormat(inputAudio).getType();
// Then, we get a clip for playing the audio.
final Clip c = AudioSystem.getClip();
// We get a stream for playing the input file.
AudioInputStream ais = AudioSystem.getAudioInputStream(inputAudio);
// We use the clip to open (but not start) the input stream
c.open(ais);
// We get the format of the audio codec (not the file format we got above)
final AudioFormat audioFormat = ais.getFormat();
// We add a shutdown hook, an anonymous inner class.
Runtime.getRuntime().addShutdownHook(new Thread()
{
public void run()
{
// We're now in the hook, which means the program is shutting down.
// You would need to use better exception handling in a production application.
try
{
// Stop the audio clip.
c.stop();
// Create a new input stream, with the duration set to the frame count we reached. Note that we use the previously determined audio format
AudioInputStream startStream = new AudioInputStream(new FileInputStream(inputAudio), audioFormat, c.getLongFramePosition());
// Write it out to the output file, using the same file type.
AudioSystem.write(startStream, fileType, outputAudio);
}
catch(IOException e)
{
e.printStackTrace();
}
}
});
// After setting up the hook, we start the clip.
c.start();
}
}