歌曲第一次播放但停止后不播放:Java 中的剪辑

Posted

技术标签:

【中文标题】歌曲第一次播放但停止后不播放:Java 中的剪辑【英文标题】:Song plays first time but does not play once stopped : Clip in Java 【发布时间】:2012-04-03 19:23:07 【问题描述】:

我在java中使用Clip播放歌曲如下:

        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();


问题是当我第一次播放歌曲时,播放和停止按钮工作正常。但是,当我第二次尝试播放这首歌时,我听不到这首歌。对出了什么问题有任何建议吗?

【问题讨论】:

【参考方案1】:

与所有其他 InputStream 一样,AudioInputStream 只能读取一次(除非它可以是 .reset())。在尝试再次播放声音之前,您可以尝试在 AudioInputStream 上调用 .reset(),但 AudioInputStream 可能不支持 .reset()。 InputStreams 不需要支持重置。另见markSupported()。

如果 .reset() 不起作用,请考虑在每次需要开始播放时构造一个新的 AudioInputStream。


更新:我做了一个在内存中缓存声音数据并使用 Clip 播放这些声音的示例。此示例使用 AudioInputStream.reset()。那怎么能行呢?事实上,AudioInputStream确实支持reset()当且仅当它的底层InputStream支持.reset()。因此,我的示例创建了一个由 ByteArrayInputStream 支持的 AudioInputStream。因为ByteArrayInputStream支持reset,所以这些缓存的AudioInputStreams也支持.reset(),可以重复使用。

请注意,如果您要同时播放任何一个缓存的声音,您可能不应该缓存AudioInputStreams,而是缓存byte[]s 并构造一个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();
            
        
    

【讨论】:

是的,不支持重置。考虑构建一个新的 AudioInputStream 是什么意思?你能给我一个使用 CLip 的例子吗 如何创建 AudioInputStreams 开始?只需再次执行初始化 AudioInputStream[] 数组的操作即可。但请在播放剪辑之前执行此操作。 哦!我以为我可以在程序开始时读取 AudioInputStream 并继续重复使用它 是的,这就是我想说的。 “AudioInputStream 只能读取一次”也表示“AudioInputStream 只能使用一次”,也表示“不能重复使用”。 @Programmer 我用可重用缓存 AudioInputStreams 的工作示例更新了我的答案【参考方案2】:

诀窍是将剪辑的当前位置重置为开始。

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

使用这种方法,不需要多次加载同一个资源。剪辑应该只加载一次并存储为实例变量或其他东西。

【讨论】:

【参考方案3】:

在您的代码示例中,使用 Clip,您应该使用 stop() 方法而不是 close() 方法。然后,当您重新启动时,它将从上次中断的地方继续。如果你想从头开始,那么你可以使用 setMicrosecondPosition() 或 setFramePosition() 为 0,然后使用 start()。

有关详细信息,请参阅以下教程中的“使用剪辑”!

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

SourceDataLine 只能使用一次,不能重置。是吗?

【讨论】:

【参考方案4】:

我在 OS X 上遇到过类似的问题,如果您在播放时尝试停止剪辑,然后从头开始重新启动,有时无法播放剪辑。它是通过在stop() 之后调用flush() 修复的:

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

绝对不要使用close(),如果您想再次播放您的剪辑,请使用stop()

【讨论】:

以上是关于歌曲第一次播放但停止后不播放:Java 中的剪辑的主要内容,如果未能解决你的问题,请参考以下文章

如何在 android 的 mediaplayer 中停止和播放新歌曲?

如何在 AVAudioplayer 中播放多个文件

在播放 iOS 中的下一首歌曲之前,我是不是需要先停止 MusicPlayerController?

如何在 Java 中播放(MIDI)序列中的音频剪辑?

在Adobe Animate ActionScript 3.0中循环

关于重叠歌曲的问题?