我在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();
}
问题在于,当我第一次播放歌曲时,播放和停止按钮工作正常。但是,当我第二次尝试播放这首歌时,我听不到这首歌。关于出了什么问题的任何建议?
答案 0 :(得分:6)
与所有其他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<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();
}
}
}
}
答案 1 :(得分:6)
诀窍是将剪辑的当前位置重置为开始。
clip.stop();
clip.setMicrosecondPosition(0);
clip.start();
使用此方法,无需多次加载相同的资源。剪辑应该只加载一次并存储为实例变量或其他东西。
答案 2 :(得分:3)
在您的代码示例中,使用Clip,您应该使用stop()方法而不是close()方法。然后,当你重新启动时,它将从它停止的地方继续。如果要从头开始重新启动,则可以将setMicrosecondPosition()或setFramePosition()用于0,并使用start()。
请参阅以下教程中的“使用剪辑”以获取更多详细信息!
http://docs.oracle.com/javase/tutorial/sound/playing.html
SourceDataLine只能使用一次,无法重置。是
答案 3 :(得分:1)
我在OS X上遇到了类似的问题,如果您在播放时尝试停止剪辑,则剪辑有时无法播放,然后从头开始重新播放。通过在flush()
:
stop()
来解决问题
if(clip.isActive() || clip.isRunning()) {
clip.stop();
clip.flush();
}
绝对不要使用close()
,如果您希望能够再次播放剪辑,请使用stop()
。