Cannot do anything while writing to a SourceDataLi

2019-07-30 11:46发布

问题:

I am somewhat new to audio in Java. What I am trying to do is as I am playing audio, I want to repaint my JComponent, but the SourceDataLine blocks all other lines of code including other Threads. Here is my play() method

public void play()
{
    final AudioFormat af =new AudioFormat(Note.SAMPLE_RATE, 8, 1, true, true);
    SourceDataLine line;
    try {
        line = AudioSystem.getSourceDataLine(af);
        line.open(af, Note.SAMPLE_RATE);
        line.start();
        byte[] arr=data;
        for(int position=0;position<arr.length;position++)
        {
            byte[] out={arr[position]};
            line.write(out, 0, 1);        //Blocks all user input (Mouse and Keyboard)
            this.repaint();               //Need to repaint JComponent here
        }
        line.drain();
        line.close();
    } catch (LineUnavailableException e) {
        e.printStackTrace();
    }
}

回答1:

Evidently you're calling play on the Event Dispatch Thread. For example, maybe you call it from an action event generated by a button press. You need to start a new thread for the playback loop, otherwise nothing can happen on the GUI until playback ends.

At the very least, something like:

new Thread(new Runnable() {
    @Override
    public void run() {
        play();
    }
}).start();

However, you should read some concurrency tutorials (like this one) as it seems you will be accessing fields across different threads (such as whatever byte[] arr = data; is).

You may also wish to use SwingWorker which has some integration with Swing. I have a somewhat lengthier code example online that shows an example of a playback loop using SwingWorker: WaveformDemo. The playback loop is around line 310.