简体   繁体   中英

java - for loop is executing more times than it should - metronome program

I am creating a metronome program and the for loop is executing +1 times than it should.

public class Tempo {

String file;
int bpm;

public Tempo(int bpm, String file){
    this.bpm=bpm;
    this.file=file;
}

public void tempoPlay () throws InterruptedException{
    new Play(file).start();
    Thread.sleep(60000/bpm); 

}

public static void main(String[] args) throws InterruptedException {
    Tempo t = new Tempo(120, "C:\\Users\\Korisnik\\Desktop\\dome3.wav");

    for(int i=0;i<20;i++){
        t.tempoPlay();
    }
}
}

The first beat is rapidly followed by the second one but later as it goes it is sounding compliant. I've counted it plays 21 beats but it should play 20. Here's the Play class:

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;

class Play extends Thread {

private String filename;
private Position curPosition;
private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb 

enum Position {

    LEFT, RIGHT, NORMAL
};

public Play(String wavfile) {
    filename = wavfile;
    curPosition = Position.NORMAL;
}

public Play(String wavfile, Position p) {
    filename = wavfile;
    curPosition = p;
}

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

}

}

Shot in the dark: It might be worthwhile to read the file into memory completely for testing purposes. A guess as to what might be happening is that the I/O from reading the file is interfering with the timing of the playback.

You might be able to get away with this to test.

Tempo t = new Tempo(120, "C:\\Users\\Korisnik\\Desktop\\dome3.wav");

t.tempoPlay() // ignore this
Thread.sleep(10);

for(int i=0;i<20;i++){
    t.tempoPlay();
} 

Or better yet, have Tempo cache the read in before playing the sound.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM