我想一个接一个地播放声音,但让它们等到第一个播放完毕。我该怎么做?
I want to play sounds after each other but make them wait until the first one is done. How do I do it?
我目前正在做一个简单的摩尔斯电码翻译器,我希望我的代码在“-”时发出长嘟嘟声,在“.”时发出短嘟嘟声,当然这是一个接一个地完成的。但是我的程序目前正在同时播放。我做错了什么?
我尝试添加一个 onCompletionListener,但 Netbeans 8.1 出现错误,无法解决问题。
//Play the morse code
public void playButton(ActionEvent event){
String morse = mcTextField.getText();
char[] charArray = morse.toCharArray();
for(int x = 0; x<charArray.length; x++){
if(charArray[x] == '.'){
playBeep(shortBeep);
}
else if(charArray[x] == '-'){
playBeep(longBeep);
}
else{
sleep(500);
}
sleep(1000);
}
}
private void playBeep(String name){
String musicFile = name;
Media sound = new Media(new File(musicFile).toURI().toString());
MediaPlayer mediaPlayer = new MediaPlayer(sound);
mediaPlayer.play();
sleep(1000);
}
private void sleep(int duration){
try{
Thread.sleep(duration);
}catch(Exception e){
System.out.println("Did not work."+e);
}
}
这个利用了Java Sound API,但基本思路应该对大部分音频库都可行,只要提供"end of play back"通知即可。
这一切所做的就是,将您要播放的序列放入队列中,播放下一个音调,等到它完成并播放下一个,直到队列中没有更多的音调。
因为 AudioClip
在它自己的线程中播放,这使用另一个 Thread
来允许示例 "wait for" 序列完全播放。如果您是从 UI 框架执行此操作,则无需额外开销即可成功。
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class Test {
public static void main(String[] args) throws InterruptedException {
try {
new Test();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
ex.printStackTrace();
}
}
public Test() throws UnsupportedAudioFileException, IOException, LineUnavailableException {
Sound longBeep = new Sound(new File(...));
Sound shortBeep = new Sound(new File(...));
List<Sound> message = new ArrayList<Sound>(9);
message.add(shortBeep);
message.add(shortBeep);
message.add(shortBeep);
message.add(longBeep);
message.add(longBeep);
message.add(longBeep);
message.add(shortBeep);
message.add(shortBeep);
message.add(shortBeep);
play(message);
}
public void play(List<Sound> message) {
try {
List<Sound> queue = new ArrayList<>(message);
Transmit transmit = new Transmit(message);
Thread thread = new Thread(transmit);
thread.start();
transmit.waitFor();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public class Transmit implements Runnable {
private List<Sound> queue;
private ReentrantLock lock;
private Condition playCondition;
public Transmit(List<Sound> message) {
this.queue = new ArrayList<>(message);
lock = new ReentrantLock();
playCondition = lock.newCondition();
}
@Override
public void run() {
playNext();
}
public void waitFor() throws InterruptedException {
lock.lock();
if (!queue.isEmpty()) {
try {
playCondition.await();
} finally {
lock.unlock();
}
} else {
lock.unlock();
}
}
protected void playNext() {
if (queue.size() > 0) {
lock.lock();
try {
System.out.println("Play Next");
Sound sound = queue.remove(0);
sound.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.STOP)) {
sound.removeLineListener(this);
System.out.println("Audio Completed");
playNext();
}
}
});
sound.play();
} finally {
lock.unlock();
}
} else {
lock.lock();
try {
playCondition.signalAll();
} finally {
lock.unlock();
}
}
}
}
public class Sound {
private Clip audio;
public Sound(AudioInputStream audioInputStream) throws LineUnavailableException, IOException {
audio = AudioSystem.getClip();
audio.open(audioInputStream);
}
public Sound(File file) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
this(AudioSystem.getAudioInputStream(file));
}
public Sound(URL url) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
this(AudioSystem.getAudioInputStream(url));
}
public Sound(InputStream stream) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
this(AudioSystem.getAudioInputStream(stream));
}
public void close() {
Objects.requireNonNull(audio, "Audio Clip has not been initalised");
audio.close();
}
public void play() {
Objects.requireNonNull(audio, "Audio Clip has not been initalised");
audio.setFramePosition(0);
audio.start();
}
public void addLineListener(LineListener listener) {
Objects.requireNonNull(audio, "Audio Clip has not been initalised");
audio.addLineListener(listener);
}
public void removeLineListener(LineListener listener) {
Objects.requireNonNull(audio, "Audio Clip has not been initalised");
audio.removeLineListener(listener);
}
}
}
如果您想知道序列何时完成,又不想麻烦使用 waitFor
方法,那么为 Transmit
添加观察者并不是一件难事 class 生成一个 "completed sequence" 事件,但我会把它留给你来实现
我目前正在做一个简单的摩尔斯电码翻译器,我希望我的代码在“-”时发出长嘟嘟声,在“.”时发出短嘟嘟声,当然这是一个接一个地完成的。但是我的程序目前正在同时播放。我做错了什么?
我尝试添加一个 onCompletionListener,但 Netbeans 8.1 出现错误,无法解决问题。
//Play the morse code
public void playButton(ActionEvent event){
String morse = mcTextField.getText();
char[] charArray = morse.toCharArray();
for(int x = 0; x<charArray.length; x++){
if(charArray[x] == '.'){
playBeep(shortBeep);
}
else if(charArray[x] == '-'){
playBeep(longBeep);
}
else{
sleep(500);
}
sleep(1000);
}
}
private void playBeep(String name){
String musicFile = name;
Media sound = new Media(new File(musicFile).toURI().toString());
MediaPlayer mediaPlayer = new MediaPlayer(sound);
mediaPlayer.play();
sleep(1000);
}
private void sleep(int duration){
try{
Thread.sleep(duration);
}catch(Exception e){
System.out.println("Did not work."+e);
}
}
这个利用了Java Sound API,但基本思路应该对大部分音频库都可行,只要提供"end of play back"通知即可。
这一切所做的就是,将您要播放的序列放入队列中,播放下一个音调,等到它完成并播放下一个,直到队列中没有更多的音调。
因为 AudioClip
在它自己的线程中播放,这使用另一个 Thread
来允许示例 "wait for" 序列完全播放。如果您是从 UI 框架执行此操作,则无需额外开销即可成功。
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class Test {
public static void main(String[] args) throws InterruptedException {
try {
new Test();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
ex.printStackTrace();
}
}
public Test() throws UnsupportedAudioFileException, IOException, LineUnavailableException {
Sound longBeep = new Sound(new File(...));
Sound shortBeep = new Sound(new File(...));
List<Sound> message = new ArrayList<Sound>(9);
message.add(shortBeep);
message.add(shortBeep);
message.add(shortBeep);
message.add(longBeep);
message.add(longBeep);
message.add(longBeep);
message.add(shortBeep);
message.add(shortBeep);
message.add(shortBeep);
play(message);
}
public void play(List<Sound> message) {
try {
List<Sound> queue = new ArrayList<>(message);
Transmit transmit = new Transmit(message);
Thread thread = new Thread(transmit);
thread.start();
transmit.waitFor();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public class Transmit implements Runnable {
private List<Sound> queue;
private ReentrantLock lock;
private Condition playCondition;
public Transmit(List<Sound> message) {
this.queue = new ArrayList<>(message);
lock = new ReentrantLock();
playCondition = lock.newCondition();
}
@Override
public void run() {
playNext();
}
public void waitFor() throws InterruptedException {
lock.lock();
if (!queue.isEmpty()) {
try {
playCondition.await();
} finally {
lock.unlock();
}
} else {
lock.unlock();
}
}
protected void playNext() {
if (queue.size() > 0) {
lock.lock();
try {
System.out.println("Play Next");
Sound sound = queue.remove(0);
sound.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.STOP)) {
sound.removeLineListener(this);
System.out.println("Audio Completed");
playNext();
}
}
});
sound.play();
} finally {
lock.unlock();
}
} else {
lock.lock();
try {
playCondition.signalAll();
} finally {
lock.unlock();
}
}
}
}
public class Sound {
private Clip audio;
public Sound(AudioInputStream audioInputStream) throws LineUnavailableException, IOException {
audio = AudioSystem.getClip();
audio.open(audioInputStream);
}
public Sound(File file) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
this(AudioSystem.getAudioInputStream(file));
}
public Sound(URL url) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
this(AudioSystem.getAudioInputStream(url));
}
public Sound(InputStream stream) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
this(AudioSystem.getAudioInputStream(stream));
}
public void close() {
Objects.requireNonNull(audio, "Audio Clip has not been initalised");
audio.close();
}
public void play() {
Objects.requireNonNull(audio, "Audio Clip has not been initalised");
audio.setFramePosition(0);
audio.start();
}
public void addLineListener(LineListener listener) {
Objects.requireNonNull(audio, "Audio Clip has not been initalised");
audio.addLineListener(listener);
}
public void removeLineListener(LineListener listener) {
Objects.requireNonNull(audio, "Audio Clip has not been initalised");
audio.removeLineListener(listener);
}
}
}
如果您想知道序列何时完成,又不想麻烦使用 waitFor
方法,那么为 Transmit
添加观察者并不是一件难事 class 生成一个 "completed sequence" 事件,但我会把它留给你来实现