歌曲是第一次播放但是一旦停止播放就不播放:用Java剪辑

我在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(); } 

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

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

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


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

请注意,如果要同时播放任何一种缓存声音,则可能不应缓存AudioInputStream ,而应缓存byte[]并在每次播放时构造一个AudioInputStream 。 这是因为AudioInputStream是有状态的,因此将其单个实例传递给两个同时运行的剪辑,或者在播放一个剪辑时重置流将导致状态冲突。

 public class CachedSoundClipTest { static ArrayList cachedSounds = new ArrayList(); 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(); } } } } 

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

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

使用此方法,不必多次加载相同的资源。 剪辑应仅加载一次并存储为实例变量或其他内容。

在您的代码示例中,使用Clip,您应该使用stop()方法而不是close()方法。 然后,当你重新启动时,它将从它停止的地方继续。 如果要从头开始重新启动,则可以将setMicrosecondPosition()或setFramePosition()用于0,并使用start()。

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

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

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

我在OS X上遇到了类似的问题,如果你试图在播放时停止剪辑,那么剪辑有时候不会播放,然后从头开始重新播放。 它是通过在stop()之后调用flush()修复的:

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

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