Песня воспроизводится в первый раз, но не воспроизводится после остановки: клип на Java - PullRequest
3 голосов
/ 03 апреля 2012

Я использую Clip в 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 - это массив типа AudioInputStream, а MR.info - это массив типа DataLine.info.Когда я нажимаю кнопку, вышеупомянутый код вызывается для воспроизведения песни.Кроме того, у меня есть еще одна кнопка для остановки песни, которая вызывает следующий код:

public static void stopSong(){

    MR.clip.close();

}

. Проблема в том, что при первом воспроизведении песни кнопка воспроизведения и остановки работает нормально.Но когда я пытаюсь воспроизвести песню во второй раз, я не могу ее услышать.Любые предложения о том, что идет не так?

Ответы [ 4 ]

6 голосов
/ 08 февраля 2016

Хитрость в том, чтобы сбросить текущую позицию клипа в начало.

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

При этом методе нет необходимости загружать один и тот же ресурс несколько раз.Клип должен быть загружен только один раз и сохранен как переменная экземпляра или что-то еще.

6 голосов
/ 03 апреля 2012

Как и все другие InputStreams, AudioInputStream может быть прочитан только один раз (если это не может быть .reset () ). Вы можете попробовать вызвать .reset () для AudioInputStream, прежде чем пытаться воспроизвести звук снова, но AudioInputStream может не поддерживать .reset (). InputStreams не требуется для поддержки сброса. Также см. markSupported () .

Если .reset () не работает, рассмотрите возможность создания нового AudioInputStream каждый раз, когда вам нужно начать воспроизведение.


ОБНОВЛЕНИЕ: я сделал пример кэширования звуковых данных в памяти и использования клипа для воспроизведения этих звуков. В этом примере используется AudioInputStream.reset (). Так как это может работать? Фактически, AudioInputStream поддерживает , поддерживает reset () тогда и только тогда, когда его базовый InputStream поддерживает .reset (). Итак, мой пример создает AudioInputStream, который поддерживается ByteArrayInputStream. Поскольку ByteArrayInputStream поддерживает сброс, эти кэшированные AudioInputStreams также поддерживают .reset (), что позволяет использовать их повторно.

Обратите внимание, что если вы собираетесь воспроизводить любой кэшированный звук одновременно, вам, вероятно, не следует кэшировать AudioInputStream с, а скорее кэшировать byte[] с и создать AudioInputStream для воспроизведения. Это связано с тем, что AudioInputStream является состоянием, поэтому передача одного экземпляра в два одновременно работающих клипа или сброс потока во время воспроизведения одного клипа приведет к конфликту состояний.

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();
            }
        }
    }
}
3 голосов
/ 05 апреля 2012

В вашем примере кода, используя Clip, вы должны использовать метод stop () вместо метода close ().Затем, когда вы перезапустите, он подберет то, с чего остановился.Если вы хотите перезапустить с самого начала, вы можете использовать setMicrosecondPosition () или setFramePosition () в 0 и использовать start ().

См. «Использование клипа» в учебнике ниже для получения более подробной информации.!

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

SourceDataLine может использоваться только один раз и не может быть сброшен.Да?

1 голос
/ 22 октября 2014

У меня была похожая проблема в OS X, где клип иногда не воспроизводился, если вы пытались остановить его во время воспроизведения, а затем перезапустить с самого начала. Это было исправлено путем вызова flush() сразу после stop():

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

Определенно не используйте close(), используйте stop(), если хотите снова воспроизвести клип.

...