Ответ на ваш вопрос вращается вокруг того, чего вы в конечном итоге хотите достичь, если вы просто хотите остановить более одного воспроизведения звука, тогда вам нужно какое-то условие, которое вы можете контролировать, если вы хотите остановить «конкретный», звук от воспроизведения, тогда вам нужно поддерживать какой-то 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 для более подробной информации. Сказав, я заставил все ваши переменные начинать с символов нижнего регистра.
- Создана пользовательская панель. Хорошо, это только я, но это делает жизнь намного проще, поскольку вы можете более легко инкапсулировать логику, которую вы пытаетесь реализовать.Поскольку вы используете API
Action
, другим вариантом было бы создать класс SoundManager
, который содержал бы логику управления и воспроизведения звуков и передавал ссылку на каждый Action
, лично я, вероятно, в конечном итоге
- Я использовал
EventQueue.invokeLater
, чтобы гарантировать, что пользовательский интерфейс создается в контексте события диспетчерские темы, восстанавливающую любой возможный риск нарушения однопоточного характера Swing, всегда хорошая идея;)
You похоже, с хорошим началом пробовать что-то, молодец, не отставайте!
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
). Предварительно загрузите клипы для каждого звука. Это потребует некоторого дополнительного управления, потому что когда клип заканчивается, вам нужно будет «перезагрузить» его до начала. Это «должно» ускорить воспроизведение клипов, но это, вероятно, будет потреблять больше ресурсов, которые более важны для вас? Вы также можете создать какой-то кеш, где, если клип не воспроизводится в течение определенного периода времени, он закрывается и удаляется.
- Keep воспроизведение звука до отпускания клавиши ... хороший вызов для вас;)
Используйте clip.is active() или clip.is running(), если он ничего не делает! – Gacci
@ Gacci Поскольку они созданы как локальные переменные, это не сработает - хорошая идея, если бы он мог использоваться как поле экземпляра вместо этого, но – MadProgrammer
Не используйте пустой блок catch. Возможно, создается ошибка. – camickr