您的问题的答案围绕您最终想要实现的目标,如果您只是想停止多个声音播放,那么您需要某种可以监控的条件,如果您想停止“特定”声音从玩,那么你需要维护某种List 的标志,你可以检查。
因此,根据您的代码,假设您正在制作钢琴,因此您希望声音重叠,在这种情况下,我们需要某种方法来确定是否播放了特定的声音。
有很多方法可以实现这一点,但让我们选择Set,它允许您维护唯一的List 项目(无重复项)。
每次调用playSound,我们检查这个列表并确定声音是否已经播放过,如果没有,我们将声音添加到列表中并播放它,当声音停止时,我们从列表中删除它
核心...
我对你的代码做了一些改动,稍后我会详细解释它,但本质上,这是这个想法的“核心”......
private Set<File> playing = new HashSet<File>(25);
public void playsound(File sound) {
try {
// Is the been played or not?
if (!playing.contains(sound)) {
// And the sound to prevent it from been played again
playing.add(sound);
// Set up a new clip
Clip clip = AudioSystem.getClip();
// Monitor the clip's status, we want to know when it ends
clip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
// Clip has stopped
if (event.getType() == LineEvent.Type.STOP) {
// Release the resources
clip.close();
// Remove the sound from our list
// so it can be played again
playing.remove(sound);
}
}
});
// Play it again Sam
clip.open(AudioSystem.getAudioInputStream(sound));
clip.start();
}
} catch (Exception e) {
// Remove the sound if something goes wrong
playing.remove(sound);
e.printStackTrace();
}
}
可运行示例
好的,所以我已经“更新”了你的代码,这就是为什么...
- Java 有一些既定的编码约定,鼓励所有开发人员遵循,它们使其他人更容易阅读您的代码,而您也可以阅读他们的代码,请查看Code Conventions for the Java TM Programming Language 了解更多详细信息。话虽如此,我让你所有的变量都以小写字符开头
- A 创建了一个自定义面板。好的,这只是我,但它让生活变得更轻松,因为您可以更轻松地封装您尝试实现的逻辑。因为您正在使用
Action API,所以另一种选择是创建一个SoundManager 类,其中包含管理和播放声音的逻辑并传递对每个Action 的引用,就我个人而言,我' d 可能最终都得到了
- 我使用
EventQueue.invokeLater 来确保在事件调度线程的上下文中创建 UI,从而降低违反 Swing 单线程特性的任何可能风险,这总是一个好主意 ;)
您的尝试似乎有了一个良好的开端,做得很好,继续努力!
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
File c7 = new File("res/res39191__jobro__piano-ff-044.wav");
File d7 = new File("res/39194__jobro__piano-ff-046.wav");
add(new JLabel("Hello"));
AbstractAction keyBindingReactorC7 = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
playsound(c7);
}
};
AbstractAction keyBindingReactorD7 = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
playsound(d7);
}
};
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("C"),
"cPressed");
getActionMap().put("cPressed", keyBindingReactorC7);
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"),
"dPressed");
getActionMap().put("dPressed", keyBindingReactorD7);
}
private Set<File> playing = new HashSet<File>(25);
public void playsound(File sound) {
try {
if (!playing.contains(sound)) {
playing.add(sound);
Clip clip = AudioSystem.getClip();
clip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
clip.close();
playing.remove(sound);
}
}
});
clip.open(AudioSystem.getAudioInputStream(sound));
clip.start();
}
} catch (Exception e) {
playing.remove(sound);
e.printStackTrace();
}
}
}
}
好的,但是我怎样才能让它一次只能播放一种声音呢?
啊,好问题……
基本上,我们使用单个剪辑并检查它的状态...
private Clip clip;
public void playsound(File sound) {
try {
if (clip == null) {
clip = AudioSystem.getClip();
clip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
clip.close();
}
}
});
}
// Is the clip active or running?
if (!clip.isActive() && !clip.isRunning()) {
if (clip.isOpen()) {
clip.close();
}
clip.open(AudioSystem.getAudioInputStream(sound));
clip.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
现在,我几乎没有使用 Java 的音频体验,但有些事情我可能会考虑尝试...
- 创建一个
AudioManager 或SoundManager 类,用于管理声音并提供简单的播放界面(如playC、playD)。为每个声音预加载剪辑。这将需要一些额外的管理,因为当剪辑结束时,您需要将其“重置”回开始。这个“应该”让播放剪辑更快,但它可能会消耗更多资源,哪个权衡对你来说更重要?您还可以创建某种缓存,如果某个剪辑在一段时间内没有播放,它就会被关闭并丢弃。
- 继续播放声音,直到松开按键...对你来说是个不错的挑战;)