Die Antwort auf Ihre Frage dreht sich um das, was Sie letztendlich erreichen wollen, wenn Sie einfach mehr als einen Sound stoppen wollen, dann brauchen Sie eine Art von Bedingung, die Sie überwachen können, wenn Sie ein "bestimmtes" stoppen wollen Sound vom Spielen, dann müssen Sie eine Art von List
Flags, die Sie überprüfen können, pflegen.
Also nehmen wir an, dass Sie, basierend auf Ihrem Code, ein Piano machen, also wollen Sie, dass sich Sounds überlappen. In diesem Fall müssen wir herausfinden, ob ein bestimmter Sound gespielt wurde oder nicht.
Es gibt eine Reihe von Möglichkeiten, um dies zu erreichen, aber lassen Sie sich auf eine Set
, die Sie einzigartige List
von Artikeln (keine Duplikate) pflegen können.
Jedes Mal, wenn playSound
aufgerufen wird, überprüfen wir diese Liste und bestimmen, ob die Sounds bereits gespielt wurden oder nicht, wenn nicht, fügen wir den Sound zur Liste hinzu und spielen ihn ab, wenn der Sound aufhört, entfernen wir es aus der Liste
im Kern ...
ich habe Ihren Code ein wenig verändert, und ich werde es später ausführlich erklären, aber im wesentlichen, das ist der „Kern“ der Idee. ..
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();
}
}
Runnable Beispiel
Okay, ich habe so „aktualisiert“ Ihren Code ein wenig, hier ist, warum ...
- Java hat einige etablierte Kodierungskonventionen alle Entwickler folgen werden ermutigt, sie machen es einfacher für andere Menschen zu lesen Ihr Code und für Sie, um ihre zu lesen, werfen Sie einen Blick auf Code Conventions for the Java TM Programming Language für weitere Details. Nachdem ich gesagt habe, habe ich alle Ihre Variablen mit einem Kleinbuchstaben beginnen
- A erstellt ein benutzerdefiniertes Panel. Okay, das ist nur ich, aber es macht das Leben viel einfacher, da Sie die Logik, die Sie implementieren möchten, leichter einkapseln können.Da Sie die
Action
API verwenden, wäre eine andere Möglichkeit gewesen, eine SoundManager
Klasse zu erstellen, die die Logik zum Verwalten und Abspielen der Sounds enthält und eine Referenz an jede Action
übergibt, persönlich würde ich wahrscheinlich mit beiden enden
- ich habe
EventQueue.invokeLater
verwendet, um sicherzustellen, dass die Benutzeroberfläche im Rahmen der Veranstaltung Dispatching Thema, wodurch jegliches Risiko der Verletzung die Single-Threaded Art von Swing, immer gut eine Idee geschaffen wird;)
Sie
scheinen einen guten Start zu haben, Dinge auszuprobieren, gut gemacht, weiter so!
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();
}
}
}
}
Ok, aber wie mache ich es so, dass nur ein Ton gleichzeitig spielen kann?
Ah, gute Frage ...
Grundsätzlich verwenden wir einen einzelnen Clip und überprüfen Sie es Zustand ist ...
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();
}
}
Nun, mein Hörerlebnis mit Java ziemlich inexistent ist, aber einige Dinge, die ich prüfen könnte versuchen ...
- Machen sie eine
AudioManager
oder SoundManager
-Klasse, die die Klänge verwaltet und bietet eine einfache Schnittstelle für sie zu spielen (wie playC
, playD
). Laden Sie die Clips für jeden Sound vor. Dies wird einige zusätzliche Verwaltung erfordern, denn wenn der Clip endet, müssen Sie es auf den Anfang "zurücksetzen". Dies "sollte" es schneller machen, die Clips abzuspielen, aber es wird wahrscheinlich mehr Ressourcen verbrauchen, was ist für Sie wichtiger? Sie können auch eine Art Cache erstellen, in dem, wenn ein Clip für eine bestimmte Zeit nicht abgespielt wird, er geschlossen und entsorgt wird.
- Halten Sie einen Ton, bis ein Schlüssel zu spielen freigesetzt wird ... für Sie schöne Herausforderung;)
Verwenden Sie clip.is active() oder clip.is running(), wenn es nichts tut! – Gacci
@Gacci Da sie als lokale Variablen erstellt werden, wird es nicht funktionieren - gute Idee, wenn es stattdessen als Instanzfeld verwendet werden könnte – MadProgrammer
Verwenden Sie keinen leeren catch-Block. Vielleicht wird ein Fehler generiert. – camickr