4

次のように、Clip in Java を使用して曲を再生しています。

        MR.clip= (Clip) AudioSystem.getLine(MR.info[docIdOfSelectedSong]);
        MR.clip.open(MR.sounds[docIdOfSelectedSong]);
        MR.clip.setMicrosecondPosition(5* 1000000);
        MR.clip.start();

ここで、MR.sounds は type の配列でAudioInputStream、MR.info は type の配列ですDataLine.info。ボタンを押すと、上記のコードが呼び出されて曲を再生します。さらに、以下のコードを呼び出す曲を停止する別のボタンがあります

public static void stopSong(){

    MR.clip.close();

}

問題は、曲を初めて再生するとき、再生ボタンと停止ボタンが正常に機能することです。しかし、その曲をもう一度再生しようとすると、その曲を聞くことができません。何がうまくいかないのかについて何か提案はありますか?

4

4 に答える 4

8

他のすべての InputStream と同様に、AudioInputStream は 1 回だけ読み取ることができます(.reset()である場合を除く)。サウンドを再生する前に、AudioInputStream で .reset() を呼び出すこともできますが、AudioInputStream は .reset() をサポートしていない可能性があります。リセットをサポートするために InputStreams は必要ありません。markSupported()も参照してください。

.reset() が機能しない場合は、再生を開始する必要があるたびに新しい AudioInputStream を構築することを検討してください。


更新: サウンド データをメモリにキャッシュし、Clip を使用してそれらのサウンドを再生する例を作成しました。この例では、AudioInputStream.reset() を使用しています。では、それはどのように機能するのでしょうか。実際、AudioInputStream、基になる InputStream が .reset() をサポートしている場合に限り、 reset()をサポートします。したがって、私の例では、ByteArrayInputStream によってサポートされる AudioInputStream を作成します。ByteArrayInputStream はリセットをサポートしているため、これらのキャッシュされた AudioInputStream も .reset() をサポートしており、再利用が可能です。

AudioInputStreamキャッシュされたサウンドを同時に再生する場合は、おそらく をキャッシュするのではなく、 をキャッシュして再生ごとにbyte[]構築する必要があることに注意してください。AudioInputStreamこれは、AudioInputStreamがステートフルであるため、その 1 つのインスタンスを同時に実行中の 2 つのクリップに渡すか、1 つのクリップの再生中にストリームをリセットすると、状態の競合が発生するためです。

public class CachedSoundClipTest
{
    static ArrayList<AudioInputStream> cachedSounds = 
        new ArrayList<AudioInputStream>();

    public static void main(String[] args) throws Exception
    {
        File[] audioFiles = new File("/audio_storage_directory").listFiles();
        for (File file : audioFiles)
        {
            AudioInputStream reusableAudioInputStream = 
                createReusableAudioInputStream(file);
            cachedSounds.add(reusableAudioInputStream);
        }

        while(true)
        {
            System.out.println("Press enter to play next clip");
            BufferedReader br = 
                new BufferedReader(new InputStreamReader(System.in));
            br.readLine();
            playCachedSound(0);
        }
    }

    private static void playCachedSound(int i) 
        throws IOException, LineUnavailableException
    {
        AudioInputStream stream = cachedSounds.get(i);
        stream.reset();
        Clip clip = AudioSystem.getClip();
        clip.open(stream);
        clip.start();
    }

    private static AudioInputStream createReusableAudioInputStream(File file) 
        throws IOException, UnsupportedAudioFileException
    {
        AudioInputStream ais = null;
        try
        {
            ais = AudioSystem.getAudioInputStream(file);
            byte[] buffer = new byte[1024 * 32];
            int read = 0;
            ByteArrayOutputStream baos = 
                new ByteArrayOutputStream(buffer.length);
            while ((read = ais.read(buffer, 0, buffer.length)) != -1)
            {
                baos.write(buffer, 0, read);
            }
            AudioInputStream reusableAis = 
                new AudioInputStream(
                        new ByteArrayInputStream(baos.toByteArray()),
                        ais.getFormat(),
                        AudioSystem.NOT_SPECIFIED);
            return reusableAis;
        }
        finally
        {
            if (ais != null)
            {
                ais.close();
            }
        }
    }
}
于 2012-04-03T19:59:14.947 に答える
7

トリックは、クリップの現在の位置を最初にリセットすることです。

clip.stop();
clip.setMicrosecondPosition(0);
clip.start();

この方法では、同じリソースを複数回ロードする必要はありません。クリップは一度だけロードし、インスタンス変数などとして保存する必要があります。

于 2016-02-07T21:57:42.970 に答える
3

コード例では、Clip を使用して、close() メソッドの代わりに stop() メソッドを使用する必要があります。その後、再起動すると、中断したところから再開されます。最初からやり直したい場合は、setMicrosecondPosition() または setFramePosition() を使用して 0 にし、start() を使用できます。

詳細については、以下のチュートリアルの「クリップの使用」を参照してください。

http://docs.oracle.com/javase/tutorial/sound/playing.html

SourceDataLine は 1 回しか使用できず、リセットできません。はい?

于 2012-04-04T20:16:14.503 に答える
1

OS X でも同様の問題がありました。再生中にクリップを停止しようとすると、クリップが再生されないことがあり、最初から再起動しました。flush()直後に呼び出すことで修正されましたstop()

if(clip.isActive() || clip.isRunning()) {
    clip.stop();
    clip.flush();
}

絶対に使用しないでください。クリップをもう一度再生できるようにしたい場合close()に使用してください。stop()

于 2014-10-21T23:29:28.913 に答える