0

I have a Sons class which load and play sounds. And an adhd class which contain the main and uses this Sons class.

All my classes are in the package "adhd" and my sounds in the jar, are like this : 1.wav is in SoundN which is in the jar. (ADHD.jar/SoundN/1.wav).

When I run the code in Eclipse it works, but when I run the jar it doesn't. It is important for me to keep the sounds "loading" because I need my program to read my sounds quickly, as I am using timers. What do you suggest me to do?

Here is the code of my class Sons which load sounds in instances of singletons.

Sons

package adhd;

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;
import java.applet.Applet;
import java.applet.AudioClip;
import java.net.URL;

public class Sons {
    private static String PATH=null;
    private static Sons instance;
    private final Map<String, Clip> sons;
    private boolean desactive;

    Sons(String path) {
        PATH = path;
        sons = new HashMap<String, Clip>();
    }


    public void load(String nom) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
        Clip clip = AudioSystem.getClip();
        clip.open(AudioSystem.getAudioInputStream(getClass().getResourceAsStream(PATH + nom)));
        sons.put(nom, clip);
    }


    public void play(String son) {
        if(!desactive) try {
            Clip c = getSon(son);
            c.setFramePosition(0);
            c.start();
        } catch(Exception e) {
            System.err.println("Impossible to play the sound " + sound);
            desactive = true;
        }
    }
}

Here is the adhd class which contain the main that uses sounds

Main class : adhd

public static void main(String[] args) {

    Sons sonN= new Sons("/SoundN/");

    try {
        sonN.load("1.wav");
    } catch (UnsupportedAudioFileException | IOException
            | LineUnavailableException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    sonN.play("1.wav");
}

Here is also a picture of the tree

Tree

user3460225
  • 69
  • 1
  • 1
  • 7
  • The path depends on where the sound file is, obviously. How could we know if you don't tell? There is no magical path that finds everything "out of your package", whatever that means. – JB Nizet Apr 13 '14 at 10:41
  • I was just waiting you to give me the beginning of the path of course. Let's say my file is in the main project folder. In the root. – user3460225 Apr 13 '14 at 11:04
  • Maybe I tell you why I am asking. Because when I want to access to a sounds in the folder "sounds" in the package of my classes I have to write "/sounds/1.wav". And I need the jar to read my sounds so I was told to put them in in a source folder. So when I do that I have a folder called "src/sounds" which is itself in the project folder. But I couldn't find how to access it, or even to access a sound located in the project folder, the root of the project. – user3460225 Apr 13 '14 at 11:21
  • Class.getResourceAsStream() uses the classpath to load resources. It can't load anything outside of a directory or jar that is not in the classpath. If the sound is in a directory/jar being in the classpath, then load it using the rules described at http://stackoverflow.com/a/23041578/571407. Otherwise, use file IO. – JB Nizet Apr 13 '14 at 11:24
  • The problem is that I really need to use this method because I wanted to load my sounds in instances to read them in the program (otherwises there is bugs because I use timers that read sounds every 0.5s). Or how can I do for my jar to read the sounds in the package? Is there a solution? (I can read them in Eclipse, but not when I run the jar). – user3460225 Apr 13 '14 at 11:39
  • I gave you a link. Read it. If it doesn't work, ask a GOOD question, showing your code, telling us which class contains the code, and where the sound file is. – JB Nizet Apr 13 '14 at 11:40
  • I read your link. I explain you again. At the beginning, I did like getResource("/bar/bla.txt"). But when I did like this, it was working on Eclipse, but not when I run the jar. And I was told that the jar need the sounds to be in a source folder. And you told me I cannot do that, the sound has to be in the package no? So I guess that I have to use the file IO but I am afraid it is going to bug. So do you have a solution? If it is still not clear I put a picture of my folders and my code, but I think you understood above. – user3460225 Apr 13 '14 at 11:47
  • If it doesn't work, ask a GOOD question, showing your code, telling us which class contains the code, and where the sound file is inside the jar. – JB Nizet Apr 13 '14 at 11:50
  • OK, but what does it mean "where the sound file is inside the jar"? How can I know? – user3460225 Apr 13 '14 at 12:00
  • A jar file is a zip file. Unzip it. Or use `jar tvf thejar.jar` – JB Nizet Apr 13 '14 at 12:04
  • Is it a good question now? – user3460225 Apr 13 '14 at 13:26
  • It's better. But it doesn't tell what the problem is. What does "it doesn't work" mean. Do you get an exception? If so, what's its stack trace? – JB Nizet Apr 13 '14 at 13:27
  • Ha sorry I didn't precise. No, there is no exception no error. In eclipse I hear the sounds, and when I run the jar I just don't hear them. – user3460225 Apr 13 '14 at 13:31
  • Are you sure you don't get any exception? How do you start your program and look for exceptions? What happens when you add println statements displaying tre values of getClass().getResourceAsStream(PATH + nom), or clip, etc.? – JB Nizet Apr 13 '14 at 13:41
  • I start my program from cmd with the command "java -jar ADHD.jar" and I see the errors in the command interface. But there is no errors. I added System.out.println("Clip: " + c); in the play function in Sons class and I get com.sun.media.sound.DirectAudioDevice$DirectClip@1535dd74 . And I added System.out.println("getClass().getResourceAsStream(nom): " + getClass().getResourceAsStream("/SoundN/"+str)); and I get java.io.BufferedInputStream@da3fdb5 – user3460225 Apr 13 '14 at 14:07
  • I am sorry that what is displayed in Eclipse but you're right, in cmd errors are displayed – user3460225 Apr 13 '14 at 14:13
  • These are the errors displayed at the state that the sounds are loads : java.io.IOException: mark/reset not supported at java.util.zip.InflaterInputStream.reset(Unknown Source) at java.io.FilterInputStream.reset(Unknown Source) at com.sun.media.sound.SoftMidiAudioFileReader.getAudioInputStream(Unkno wn Source) at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source) at adhd.Sons.charger(Sons.java:72) at adhd.Adhd$5.run(Adhd.java:648) – user3460225 Apr 13 '14 at 14:16

1 Answers1

0

Now, thanks to the exception message, we know what the problem actually is. The problem is not that the sounds can't be loaded or aren't found in the jar. The problem is that, as the javadoc says:

These parsers must be able to mark the stream, read enough data to determine whether they support the stream, and, if not, reset the stream's read pointer to its original position. If the input stream does not support these operation, this method may fail with an IOException.

And the stream returned by Class.getResourceAsStream(), when the resource is loaded from a jar, doesn't support these operations. So what you could do is to read everything from the input stream into a byte array in memory, create a ByteArrayInputStream from this byte array, and pass that stream to AudioSystem.getAudioInputStream().

If loading everything in memory is not an option because the sound is really long (but then I guess you wouldn't put it in the jar), then you could write it to a temporary file, and then pass a FileInputStream to AudioSystem.getAudioInputStream().

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Do you have an example for these two options please, how to do it? It is actually the first time I manipulate sounds in java. – user3460225 Apr 13 '14 at 15:01
  • That has nothing to do with sounds. You read all the bytes of an input stream, and then create a ByteArrayInputStream. Read the javadoc and the java IO tutorial. – JB Nizet Apr 13 '14 at 15:05
  • I understand much better with examples, that's why I am asking. Is it what I have to do? http://stackoverflow.com/questions/15725871/caching-sounds-using-byte-arrays-from-within-jar-file – user3460225 Apr 13 '14 at 15:28
  • If you're talking about the code in the answer, then yes. – JB Nizet Apr 13 '14 at 15:34