1

I am developing a drum metronome. So I have .wav sound files and I need to play them with using minimum computer memory and CPU because it's very important for the metronome to play the sample on the exact time. Currently I use the code from this link How to play .wav files with java

class MakeSound {

    private final int BUFFER_SIZE = 128000;
    private File soundFile;
    private AudioInputStream audioStream;
    private AudioFormat audioFormat;
    private SourceDataLine sourceLine;

    /**
     * @param filename the name of the file that is going to be played
     */
    public void playSound(String filename){

        String strFilename = filename;

        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();
    }
}

This code works but it's too slow for using it in a metronome app. So which is the fastest way of playing wav sound files. Please take into account that sometimes I need to play them simultaneously so the sound should play as a separate thread I think.

Thanks

Community
  • 1
  • 1
samvel1024
  • 1,123
  • 4
  • 15
  • 39
  • 1
    You could try adding this question on `codereview.stackexchange.com`! – Am_I_Helpful Aug 24 '14 at 17:49
  • Yes, there's a lot a code review could say about this code. Such as that you are misusing instance variables as if they were local variables. – Marko Topolnik Aug 24 '14 at 17:53
  • Any solutions relying on a Thread.sleep are, in my experience, going to be unsuitable for any audio playback solution like a microphone due to poor timer resolution. The best solution is going to involve constantly streaming audio, writing zeros for a computed number of samples and then writing out the waveform. – jaket Aug 25 '14 at 22:35
  • Will it be possible to have the same result using Java Timer and threads ? – samvel1024 Aug 26 '14 at 20:40

1 Answers1

1

i am assuming that you have a working method that looks like this:

example #1: (don't do this)

public void startMetronome(){
    boolean abort = false;
    String audoFileName = new String("myAudioFile);
    do{
        playSound(audoFileName );
    while(abort != false);    
}

or maybe you've done some better implementation like this:

exapmle#2: (don't do this either)

Runnable r = new Runnable(){
    boolean abort = false;
    String audoFileName = new String("myAudioFile);
    do{
        playSound(audoFileName );
        try{
            Thread.sleep(500);
        }catch (Exception e);
    while(abort != false);    
}
new Thread(r).start();

in any case you're doing a big mistake: you initialize every time you play a sound the sound line and every time you load the file again and again.

but thats a toally wrong approach, you have to load the file once, open the line once and play the sound repetially on the line!

(cheap) solution #3:

adjust your playSoundmethode like this:

public void playSound(String filename){

    //same as above
    String strFilename = filename;
    soundFile = new File(strFilename); //i've shorened the catch/throws, to make it more readable 
    audioStream = AudioSystem.getAudioInputStream(soundFile);
    audioFormat = audioStream.getFormat();
    DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
    sourceLine = (SourceDataLine) AudioSystem.getLine(info);
    sourceLine.open(audioFormat);

    sourceLine.start();

    //right now, the line is set up and all data is availible
    boolean isRunning = true;

    while(isRunning){ //this is an endless loop!
        int nBytesRead = 0;
        byte[] abData = new byte[BUFFER_SIZE];
        while (nBytesRead != -1) {
        nBytesRead = audioStream.read(abData, 0, abData.length);

        //and your timing here
        try{
            Thread.sleep(500);
        }catch (Exception e);
    }

    sourceLine.drain();
    sourceLine.close();
}

and best practice would be to play the whole thing in an seperate thread... (as example #2)

Martin Frank
  • 3,445
  • 1
  • 27
  • 47
  • But isn't it initializing the sound variable every time ?? I mean the playSound( ) method – samvel1024 Aug 25 '14 at 05:10
  • it will stay within the loop: while(true){ ...} the loop will never be aborted... – Martin Frank Aug 25 '14 at 05:11
  • The problem is that every time it should play different sound file not the same one. At first you have the editor where you tell the program which drum sounds it should play and also you set the duration – samvel1024 Aug 25 '14 at 05:13
  • my answer is not complete - of yourse you must make adjustments to fit your needs... this is only a help to make your sounds play better... – Martin Frank Aug 25 '14 at 05:14
  • let me know if this post helped you or not - i would be really glad to provide more help! – Martin Frank Aug 25 '14 at 05:25
  • I have just tried to store all that needed variables in arrays and then use them every time instead of initializing. Now it's not responding quicker , so the problem remains the same. Moreover I can't play the same sound file twice. – samvel1024 Aug 25 '14 at 05:34
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/59910/discussion-between-martin-frank-and-abrahamyan-samvel). – Martin Frank Aug 25 '14 at 05:40