how to include sound in java - java

i have made a jar program that need to run an audio file
this is how i open the audio file(not in jar file)
Thread sound = new Thread(){
public void run(){
MakeSound.playSound("Raef.wav");
}
};
i run it with
sound.start();
and end it with
sound.stop();
when i run it on blue j its worked but the sound isnt play on the jar files
can someone solve this ?
i need to make a program with jar
nb : MakeSound is another class i used to play the sound
public class MakeSound {
private static final int BUFFER_SIZE = 128000;
private static File soundFile;
private static AudioInputStream audioStream;
private static AudioFormat audioFormat;
private static SourceDataLine sourceLine;
/**
* #param filename the name of the file that is going to be played
*/
public static void playSound(String filename){
String strFilename = filename;
// buka file
try {
soundFile = new File(strFilename);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
try {
audioStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e){
e.printStackTrace();
System.exit(1);
}
audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
try {
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
#SuppressWarnings("unused")
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
}

The exact steps to put an audio file in a jar depends on the IDE you are using.
What I normally do is to make a subfolder "audio" and put the audio files there. The subfolder is a subfolder of the code source.
Then, in the code, I create a URL that points to this subfolder.
URL url = this.getClass().getResource("audio/" + fileName);
I don't know about the specifics of MakeSound.playSound(). Hopefully it accepts a URL as a parameter. If it only accepts file names, you might need to rewrite it. Operating Systems generally aren't set up to find files that are packed in jars. URLs, though, are able to point inside of a jar.
Key point: the calling code is in a folder. I used "this" instead of invoking the class name of the calling code which is also possible. If this folder has a subfolder named "audio", the above line of code should find the file.

Related

my program run 100% from compiler put not run 100% from dist

my java progeam run 100% if i run it from the compiler netbeans put if i run it from file manager its will be in dist folder inside the project (the program have a button that run wav file) the button have a catch ioexception if i run it from compiler the sound will run put if i run it from dist folder or move then run it to any path the catch that have the ioexception as a parameter will excecute i used audioSystem and cought it with a Clip class so if any exception occure in the first way the Clip class will try to run the sound file. code:
public void getSoundData(int delay){
ActionListener taskPerformer = new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt){
try{
int random=(int)(Math.random()*12+1);
InputStream input = new FileInputStream("src/azcar/sounds/"+String.valueOf(random)+".wav");
AudioStream audio = new AudioStream(input);
AudioPlayer.player.start(audio);
} catch (Exception exc) {
try {
Clip clip = AudioSystem.getClip();
int random=(int)(Math.random()*12+1);
AudioInputStream input = AudioSystem.getAudioInputStream(new File("src/azcar/sounds/"+String.valueOf(random)+".wav"));
clip.open(input);
clip.start();
} catch (LineUnavailableException ex) {
JOptionPane.showMessageDialog(null, ex);
} catch (UnsupportedAudioFileException ex) {
JOptionPane.showMessageDialog(null, "نوع ملفات الصوت غير مدعوم");
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "لم أتمكن من االوصول لملفات الصوت");
}
}
}
};
Timer timer = new Timer(delay*1000*60,taskPerformer);
timer.setRepeats(true);
timer.start();
}
In the above you are using the relative path to look up you wav file. From the root folder of the project you will read 'src/azcar/sounds/.wav', but from the dist folder you are effectively reading from 'dist/src/azcar/sounds/.wav'.
You can start to test this by entering the absolute path to the folder as a first step. After that you can then move to passing in a sound folder path as a variable to your application.

AudioInputStream from InputStream ( load from resource directory)

I try to load my sounds from my resource folder when trying out my Application in the IDE.
For images and other stuff that uses InputStreams I use this method:
#Override
public InputStream readAsset(String fileName) throws IOException {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream is = classloader.getResourceAsStream(fileName);
return is;
}
this lets me open an Inputstream of which I can pull Images.
As soon as I would try to cast this InputStream to an Audio InputStream I get errors. Also if I would try to make a new AudioInputStream passing the above InputStream as the parameter.
This is my current way to load sounds from external paths:
public class JavaSound implements Sound {
private Clip clip;
public JavaSound(String fileName){
try {
File file = new File(fileName);
if (file.exists()) {
//for external storage Path
AudioInputStream sound = AudioSystem.getAudioInputStream(file);
// load the sound into memory (a Clip)
clip = AudioSystem.getClip();
clip.open(sound);
}
else {
throw new RuntimeException("Sound: file not found: " + fileName);
}
}
catch (MalformedURLException e) {
e.printStackTrace();
throw new RuntimeException("Sound: Malformed URL: " + e);
}
catch (UnsupportedAudioFileException e) {
e.printStackTrace();
throw new RuntimeException("Sound: Unsupported Audio File: " + e);
}
catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Sound: Input/Output Error: " + e);
}
catch (LineUnavailableException e) {
e.printStackTrace();
throw new RuntimeException("Sound: Line Unavailable Exception Error: " + e);
}
}
#Override
public void play(float volume) {
// Get the gain control from clip
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
// set the gain (between 0.0 and 1.0)
float gain = volume;
float dB = (float) (Math.log(gain) / Math.log(10.0) * 20.0);
gainControl.setValue(dB);
clip.setFramePosition(0); // Must always rewind!
clip.start();
}
#Override
public void dispose() {
clip.close();
}
}
how can i exchange the AudioInputStream part to work like the first code, pulling the files out of my resource directory?
EDIT :
this way of creating a new AudioInputStream by passing an InputStream
File file = new File(fileName);
if (file.exists()) {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream is = classloader.getResourceAsStream(fileName);
//for external storage Path
AudioInputStream sound = new AudioInputStream(is);
// load the sound into memory (a Clip)
clip = AudioSystem.getClip();
clip.open(sound);
}
also throws errors before even running it
this made it work in my above code:
public JavaSound(String fileName){
try {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream is = classloader.getResourceAsStream(fileName);
AudioInputStream sound = AudioSystem.getAudioInputStream(new BufferedInputStream(is));
// load the sound into memory (a Clip)
clip = AudioSystem.getClip();
clip.open(sound);
}
catch (MalformedURLException e) {
e.printStackTrace();
throw new RuntimeException("Sound: Malformed URL: " + e);
}
catch (UnsupportedAudioFileException e) {
e.printStackTrace();
throw new RuntimeException("Sound: Unsupported Audio File: " + e);
}
catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Sound: Input/Output Error: " + e);
}
catch (LineUnavailableException e) {
e.printStackTrace();
throw new RuntimeException("Sound: Line Unavailable Exception Error: " + e);
}
}
just had to start a new bufferedInputStream with my inputStream to have the AudioInputStream... :D still thanks a lot ;)
You cannot cast InputStream to AudioInputStream (you could do the inverse). The Clip.open() wants an AudioInputStream.
An approach, suggested by this answer here is to use the URL from the .getResource() call, rather than attempting to open the InputStream and then pass that in.
Therefore, try:
URL soundURL = classloader.getResource(fileName);
AudioInputStream ais = AudioSystem.getAudioInputStream(soundURL);

Can't load sound files LibGdx

I would like to load files directly from expansion OBB file by using AssetManager. I implemented my own FileHandleResolver
public class CustomFileHandleResolver implements FileHandleResolver
{
#Override
public FileHandle resolve(String fileName) {
return new CustomFileHandle(fileName);
}
}
I set it to my AssetManager. I created my own FileHandle and I override read() function
#Override
public InputStream read()
{
InputStream input = null;
try {
input = GameInfo.expansionFile.getInputStream(file.getPath().replace('\\', '/'));
} catch (IOException e) {
e.printStackTrace();
}
return input;
}
It loads all the files like .PNG, .PACK, .FNT, except .OGG files, so I guess that all sound files won't be loaded. I'm getting this error:
com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: SFx/button_click.ogg
And this error:
com.badlogic.gdx.utils.GdxRuntimeException: java.lang.ClassCastException: com.solidgamesstudio.threedefendersn.framework.CustomFileHandle cannot be cast to com.badlogic.gdx.backends.android.AndroidFileHandle
I read that zip can not be compressed. In 7zip I selected compression to "Store" so that it's not compressed at all, but still this problem occurs.
I traversed what is happening when files are being loaded and I found that AssetManager calls my CustomFileHandleResolver which creates CustomFileHandle. For every file that is not .OGG it calls InputStream read(). In this function it loads the file from the zip and it's fine. But as I said when it comes to loading .OGG it doesn't call this function. So it's not even trying yet to get the file from the zip. Question is, why .OGG file doesn't call InputStream read() in CustomFileHandle()?
UPDATE
I traversed more and I found out that it won't call InputStream read() because it can't create a Sound from FileHandle somehow. Clue to this is
CustomFileHandle cannot be cast to AndroidFileHandle
While to create a sound you need to pass fileHandle.
public Sound newSound (FileHandle fileHandle);
This is called from SoundLoader
#Override
public void loadAsync (AssetManager manager, String fileName, FileHandle file, SoundParameter parameter) {
sound = Gdx.audio.newSound(file);
}
And that soundLoader uses my CustomFileHandleResolver. I don't know if Sounds are handled differently then other types of files. But by default AssetManager uses
public class InternalFileHandleResolver implements FileHandleResolver {
#Override
public FileHandle resolve (String fileName) {
return Gdx.files.internal(fileName);
}
}
I can't get into Gdx.files.internal to see if there are any special handling for Sounds.
UPDATE
Further analysis give me clue that the main problem is this as mentioned before.
CustomFileHandle cannot be cast to AndroidFileHandle
I don't know why it's casting my FileHandle to AndroidFileHandle while loading OGG file. If it loads fine other type of files, that probably means it doesn't do casting for them. That means that OGG is special and it needs casting. Any clues?
I have not found a way to load sound files from the zip file. Problem is that AssetManager loads sound files differently than other file types. Problem was that it is casting FileHandle to AndroidFileHandle, and since CustomFileHandle extends FileHandle it's impossible to cast it to AndroidFileHandle. I found no way to go around this, because it's deeply rooted.
CustomFileHandle cannot be cast to AndroidFileHandle
In this situation I had to take out all sound files from the OBB file and put them together with the app. I created another instance of AssetManager just for loading sounds. So, sounds are loaded normally as you would with AssetManager and for any other type of file I used AssetManager that uses my own FileHandlerResolver which uses my own FileHandle class that returns a file from the zip. The only problem with this approach is that you are limited to having sounds files only up to 50 MB.
I solved this problem extracting the zip to a specific folder,
and then reading from that external folder.
The extraction of the zip is done by these methods:
public void extract(){
String packageName = getPackageName();
File root = Environment.getExternalStorageDirectory();
File expPath = new File(root.toString() + "/Android/obb/" + packageName);
if (expPath.exists()) {
String strMainPath = null;
try {
strMainPath = expPath + File.separator + "main."
+ getPackageManager().getPackageInfo(
getPackageName(), 0).versionCode + "."
+ packageName + ".obb";
Log.e("Extract File path", "===>"+strMainPath);
File f=new File(strMainPath);
if(f.exists()){
Log.e("Extract From File path", "===> not exist");
}
else
{
Log.e("Extract From File path", "===> exist");
}
String pathToExtract = Environment.getExternalStorageDirectory()+"/"+Cons.FOLDERNAME;
Log.e("Extract to path", "===>"+pathToExtract);
flag = extractZip(strMainPath,pathToExtract);
Log.e("After Extract Zip", "===>"+flag);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
}
private boolean extractZip(String pathOfZip,String pathToExtract)
{
int BUFFER_SIZE = 1024;
int size;
byte[] buffer = new byte[BUFFER_SIZE];
try {
File f = new File(pathToExtract);
if(!f.isDirectory()) {
f.mkdirs();
}
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(new FileInputStream(pathOfZip), BUFFER_SIZE));
fileNum=0;
try {
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
String path = pathToExtract +"/"+ ze.getName();
if (ze.isDirectory()) {
File unzipFile = new File(path);
if(!unzipFile.isDirectory()) {
unzipFile.mkdirs();
}
}
else {
updateFileNum();
FileOutputStream out = new FileOutputStream(path, false);
BufferedOutputStream fout = new BufferedOutputStream(out, BUFFER_SIZE);
try {
while ( (size = zin.read(buffer, 0, BUFFER_SIZE)) != -1 ) {
fout.write(buffer, 0, size);
}
zin.closeEntry();
}catch (Exception e) {
Log.e("Exception", "Unzip exception 1:" + e.toString());
}
finally {
fout.flush();
fout.close();
}
}
}
}catch (Exception e) {
Log.e("Exception", "Unzip exception2 :" + e.toString());
}
finally {
zin.close();
}
return true;
}
catch (Exception e) {
Log.e("Exception", "Unzip exception :" + e.toString());
}
return false;
}
Note: Extract it to .Android folder, otherwhise users will have direct acces to the assets. For example they will see the images in the Gallery app.
Well, I'm doing this currently. Whenever you need to get a real FileHandle in order for the sound loading mechanism to work (or in any other case were the casting to AndroidFileHandle is bothering you), unzip that file to a local directory and reuse it if needed:
public static FileHandle getRealFileHandle(String zipEntryPath, ZipFile zipFile) {
if (Gdx.files.local(zipEntryPath).exists()) {
return Gdx.files.local(zipEntryPath);
} else {
Gdx.app.log(TAG, "Unzipping file '" + zipEntryPath + "'...");
try {
FileHandle unzippedFile;
ZipEntry entry = zipFile.getEntry(zipEntryPath);
if (entry != null) {
unzippedFile = Gdx.files.local(zipEntryPath);
InputStream is = zipFile.getInputStream(entry);
byte[] buffer = new byte[65536];
int readLength;
while ((readLength = is.read(buffer)) >= 0) {
unzippedFile.writeBytes(buffer, 0, readLength, true);
}
return unzippedFile;
} else {
Gdx.app.error(TAG, "Entry '" + zipEntryPath + "' not found inside zip file.");
}
} catch (IOException ioe) {
Gdx.app.error(TAG, "A problem occurred while writing to the local file.");
}
}
return null;
}

Playing sound in a Java Desktop application

How do we play sound (a music file of any format like .wma, .mp3 ) in a Java desktop application? (not an applet)
I have used the following code (taken from another question on Stack Overflow) but it throws an Exception.
public class playsound {
public static void main(String[] args) {
s s=new s();
s.start();
}
}
class s extends Thread{
public void run(){
try{
InputStream in = new FileInputStream("C:\\Users\\srgf\\Desktop\\s.wma");
AudioStream as = new AudioStream(in); //line 26
AudioPlayer.player.start(as);
}
catch(Exception e){
e.printStackTrace();
System.exit(1);
}
}
}
The program when run throws the following Exception:
java.io.IOException: could not create audio stream from input stream
at sun.audio.AudioStream.<init>(AudioStream.java:82)
at s.run(delplaysound.java:26)
Use this library:
http://www.javazoom.net/javalayer/javalayer.html
public void play() {
String song = "http://www.ntonyx.com/mp3files/Morning_Flower.mp3";
Player mp3player = null;
BufferedInputStream in = null;
try {
in = new BufferedInputStream(new URL(song).openStream());
mp3player = new Player(in);
mp3player.play();
} catch (MalformedURLException ex) {
} catch (IOException e) {
} catch (JavaLayerException e) {
} catch (NullPointerException ex) {
}
}
Hope that helps everyone with a similar question :-)
Hmmm. This might look like advertisement for my stuff, but you could use my API here:
https://github.com/s4ke/HotSound
playback is quite easy with this one.
Alternative: use Java Clips (prebuffering)
... code ...
// specify the sound to play
File soundFile = new File("pathToYouFile");
//this does the conversion stuff for you if you have the correct SPIs installed
AudioInputStream inputStream =
getSupportedAudioInputStreamFromInputStream(new FileInputStream(soundFile));
// load the sound into memory (a Clip)
DataLine.Info info = new DataLine.Info(Clip.class, inputStream.getFormat());
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(sound);
// due to bug in Java Sound, explicitly exit the VM when
// the sound has stopped.
clip.addLineListener(new LineListener() {
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
event.getLine().close();
System.exit(0);
}
}
});
// play the sound clip
clip.start();
... code ...
Then you need this method:
public static AudioInputStream getSupportedAudioInputStreamFromInputStream(InputStream pInputStream) throws UnsupportedAudioFileException,
IOException {
AudioInputStream sourceAudioInputStream = AudioSystem
.getAudioInputStream(pInputStream);
AudioInputStream ret = sourceAudioInputStream;
AudioFormat sourceAudioFormat = sourceAudioInputStream.getFormat();
DataLine.Info supportInfo = new DataLine.Info(SourceDataLine.class,
sourceAudioFormat,
AudioSystem.NOT_SPECIFIED);
boolean directSupport = AudioSystem.isLineSupported(supportInfo);
if(!directSupport) {
float sampleRate = sourceAudioFormat.getSampleRate();
int channels = sourceAudioFormat.getChannels();
AudioFormat newFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
sampleRate,
16,
channels,
channels * 2,
sampleRate,
false);
AudioInputStream convertedAudioInputStream = AudioSystem
.getAudioInputStream(newFormat, sourceAudioInputStream);
sourceAudioFormat = newFormat;
ret = convertedAudioInputStream;
}
return ret;
}
Source for the Clip example (with little changes by me): http://www.java2s.com/Code/Java/Development-Class/AnexampleofloadingandplayingasoundusingaClip.htm
SPIs are added via adding their .jars to the classpath
for mp3 these are:
http://www.javazoom.net/mp3spi/mp3spi.html
http://www.javazoom.net/javalayer/javalayer.html
http://www.tritonus.org/plugins.html (tritonus_share.jar)
Using JavaFX (which is bundled with your JDK) is pretty simple.
You will need the following imports:
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
import java.nio.file.Paths;
Steps:
Initialize JavaFX:
new JFXPanel();
Create a Media (sound):
Media media = new Media(Paths.get(filename).toUri().toString());
Create a MediaPlayer to play the sound:
MediaPlayer player = new MediaPlayer(media);
And play the Media:
player.play();
You can set the start/stop times as well with MediaPlayer.setStartTime() and MediaPlayer.setStopTime():
player.setStartTime(new Duration(Duration.ZERO)); // Start at the beginning of the sound file
player.setStopTime(1000); // Stop one second (1000 milliseconds) into the playback
Or, you can stop playing with MediaPlayer.stop().
A sample function to play audio:
public static void playAudio(String name, double startMillis, double stopMillis) {
Media media = new Media(Paths.get(name).toUri().toString());
MediaPlayer player = new MediaPlayer(media);
player.setStartTime(new Duration(startMillis));
player.setStopTime(new Duration(stopMillis));
player.play();
}
More info can be found at the JavaFX javadoc.

Using JarEntry to write sound files is not working as intended

public static void writeFile(String theFileName, String theFilePath)
{
try {
File currentFile = new File("plugins/mcMMO/Resources/"+theFilePath+theFileName);
//System.out.println(theFileName);
#SuppressWarnings("static-access")
JarFile jar = new JarFile(plugin.mcmmo);
JarEntry entry = jar.getJarEntry("resources/"+theFileName);
InputStream is = jar.getInputStream(entry);
byte[] buf = new byte[(int)entry.getSize()];
is.read(buf, 0, buf.length);
FileOutputStream os = new FileOutputStream(currentFile);
os.write(buf);
os.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Alright so in my program I have various resources kept within the Jar of the program, when the program runs it has specific files passed to this function that are written to the HDD of the users computer. Everything gets written, but only the images come out 100% correct. The sound files are not so lucky.
Basically, I CANNOT get the sounds to write correctly, their file sizes are correct but they only contain a split second of audio instead of their full length audio. Am I missing something here? I seem to have done everything right, but if that was true I wouldn't be posting here.
I tried my best at googling this problem but it has failed me.
Any guess as to why this doesn't work would be AMAZING!! :)
As JarEntry extends ZipEntry, I would recommend not to rely on the ZipEntry.getSize() method as it return -1. See the doc.
Moreover, it's in general much more common to take advantage of buffering when reading a stream. In your example, you put everything inside your byte array, so I guess for big files you could end up in an OutOfMemoryError.
Here would be the code I would test:
public static void writeFile(String theFileName, String theFilePath)
{
try {
File currentFile = new File("plugins/mcMMO/Resources/"+theFilePath+theFileName);
#SuppressWarnings("static-access")
JarFile jar = new JarFile(plugin.mcmmo);
JarEntry entry = jar.getJarEntry("resources/"+theFileName);
InputStream is = jar.getInputStream(entry);
byte[] buf = new byte[2048];
int nbRead;
OutputStream os = new BufferedOutputStream(new FileOutputStream(currentFile));
while((nbRead = is.read(buf)) != -1) {
os.write(buf, 0, nbRead);
}
os.flush();
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

Categories