簡體   English   中英

無法同時播放聲音

[英]Unable to play sounds simultaneously

我試圖通過單擊j按鈕同時播放六個音頻軌道,但是單擊時會播放第一個軌道,並等待直到完成播放第二個軌道,依此類推。 這是我的代碼

 button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == button) {
                System.out.println("Button Pressed");
                AudioPlayerExample2 player1 = new AudioPlayerExample2();
                AudioPlayerExample2 player2 = new AudioPlayerExample2();
                AudioPlayerExample2 player3 = new AudioPlayerExample2();
                AudioPlayerExample2 player4 = new AudioPlayerExample2();
                AudioPlayerExample2 player5 = new AudioPlayerExample2();
                AudioPlayerExample2 player6 = new AudioPlayerExample2();
                player1.play(track1);
                player2.play(track2);
                player3.play(track3);
                player4.play(track4);
                player5.play(track5);
                player6.play(track6);
            }
        }
    });

和音頻播放器導入

public class AudioPlayerExample2 {

private static final int BUFFER_SIZE = 4096;


public void play(String audioFilePath) {
    File audioFile = new File(audioFilePath);
    try {
        AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile);

        AudioFormat format = audioStream.getFormat();

        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

        SourceDataLine audioLine = (SourceDataLine) AudioSystem.getLine(info);

        audioLine.open(format);

        audioLine.start();

        System.out.println("Playback started.");

        byte[] bytesBuffer = new byte[BUFFER_SIZE];
        int bytesRead = -1;

        while ((bytesRead = audioStream.read(bytesBuffer)) != -1) {
            audioLine.write(bytesBuffer, 0, bytesRead);
        }

        audioLine.drain();
        audioLine.close();
        audioStream.close();

        System.out.println("Playback completed.");

    } catch (UnsupportedAudioFileException ex) {
        System.out.println("The specified audio file is not supported.");
        ex.printStackTrace();
    } catch (LineUnavailableException ex) {
        System.out.println("Audio line for playing back is unavailable.");
        ex.printStackTrace();
    } catch (IOException ex) {
        System.out.println("Error playing the audio file.");
        ex.printStackTrace();
    }
}

public static void main(String[] args) {
    String audioFilePath = "";
    AudioPlayerExample2 player = new AudioPlayerExample2();
    player.play(audioFilePath);
}}

在播放曲目時,該按鈕也保持單擊狀態,因此我也無法使用音量jslider。 謝謝您的幫助!

您編寫play方法的方式將阻塞直到流完全播放為止-這意味着流將一個接一個地播放。 一種選擇是為每個流派生一個新線程。 這樣可以避免阻塞問題,但是會帶來另一個問題,那就是線程都將處於啟動狀態。 這意味着這些流不一定都必須在完全相同的時間開始(盡管您可以使用信號使它們非常接近同步)。

我認為一種更好的方法是使用從所有文件讀取並在單個線程中全部寫入一個 SourceDataLine的方法。 這意味着您必須手動將信號混合在一起。 假設所有文件都具有相同的采樣率和位深度,這並不是很難。 我假設使用16位樣本。 如果您的文件不同,則可以弄清楚如何處理。

public void play(String[] audioFilePath) {
    int numStreams = audioFilePath.length;

    // Open all of the file streams
    AudioInputStream[] audioStream = new AudioInputStream[numStreams];
    for (int i = 0; i < numStreams; i++)
    audioStream[i] = AudioSystem.getAudioInputStream(audioFile);

    // Open the audio line.
    AudioFormat format = audioStream[0].getFormat();
    DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
    SourceDataLine audioLine = (SourceDataLine) AudioSystem.getLine(info);
    audioLine.open(format);
    audioLine.start();

    while (true) {
        // Read a buffer from each stream and mix into an array of
        // doubles.
        byte[] bytesBuffer = new byte[BUFFER_SIZE];
        double[] mixBuffer = new double[BUFFER_SIZE/2];
        int maxSamplesRead = -1;
        for (int i = 0 ; i < numStreams; i++)
        {
            int bytesRead = audioStream.read(bytesBuffer);
            if (bytesRead != -1) {
                int samplesRead = bytesRead/2;
                if (samplesRead > maxSamplesRead) {
                    maxSamplesRead = samplesRead;
                }
                for (int j = 0 ; j < bytesRead/2 ; j++) {
                    double sample = ((bytesBuffer[j*2] << 8) | bytesBuffer[j*2+1]) / 32768.0;
                    mixBuffer[j] += sample;
                }
            }
        }

        // Convert the mixed samples back into a byte array and play.
        if (maxSamplesRead > 0) {
            for (int i = 0; i < maxSamplesRead; i++) {
                // rescale data between -1 and 1
                mixBuffer[i] /= numStreams;

                // and now back to 16-bit
                short sample16 = (short)(mixBuffer * 32768);

                // and back to bytes
                bytesBuffer[i*2]   = (byte)(sample16 >> 8);
                bytesBuffer[i*2+1] = (byte)(sample16);
            }
            audioLine.write(bytesBuffer, 0, maxSamplesRead*2);
        }
        else {
            // All of the streams are empty so cleanup.
            audioLine.drain();
            audioLine.close();
            for (int i = 0 ; i < numStreams; i++)
                audioStream[i].close();
            break;
        }
    }
}

並通過傳遞文件名數組來調用它(我建議將其替換為track1,track2等...)

button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == button) {
                System.out.println("Button Pressed");
                AudioPlayerExample2 player = new AudioPlayerExample2(allTracks);
            }
        }
    });

第三種可能更好的選擇是從InputStream派生一個支持多個文件並在內部進行混合的類。 通過這種方法,您可以使用大多數現有的AudioPlayerExample2類,但只有一個實例。 這比我現在想參與的要復雜得多。

PS我沒有嘗試編譯任何。 我只是想傳達這個想法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM