我正在编写一个音频可视化工具。要将要显示的数据同步到音乐本身,我需要通过调用clip.getMicrosecondPosition()
/ player.getPosition()
来获取剪辑的/播放器在音频文件中的当前位置。这对于剪辑工作正常。问题是我需要在另一个线程中定义播放器对象,因为调用player.play()
会暂停当前线程中的所有执行,直到文件播放到结束。 Player
是来自MP3SPI库(javazoom.jl.player.Player
)的类。
代码:
public class AudioTools implements Runnable {
public File file;
public boolean isMP3 = false;
public Player player;
public Clip clip;
public AudioTools(File file) {
this.file = file;
determineFilyType();
}
private void determineFileType() {
if (file.getAbsolutePath().endsWith(".mp3")) {
this.isMP3 = true;
} else if (file.getAbsolutePath().endsWith(".wav")) {
this.isMP3 = false;
} else {
System.err.println("Invalid File Type!");
System.exit(0);
}
}
public void play() {
if (isMP3) {
Thread t = new Thread(this);
t.start(); // play MP3 using Player class
} else {
playWav(file); // play WAV using Clip class
}
}
protected void playMP3(File file){
try {
player = new Player(new FileInputStream(file));
player.play();
} catch (Exception e) {
System.out.println("Invalid MP3 File!");
e.printStackTrace();
System.exit(0);
}
}
@Override
public void run() {
playMP3(file);
}
private void playWav(File file) {
try {
AudioInputStream ais = AudioSystem.getAudioInputStream(file);
DataLine.Info dataInfo = new DataLine.Info(Clip.class, null);
clip = (Clip) AudioSystem.getLine(dataInfo);
clip.open(ais);
clip.start();
} catch (Exception e) {
e.printStackTrace();
System.err.println("Invalid .wav file!");
System.exit(0);
}
}
}
主要课程:
public static void main(String[] args) {
File file = new File(/*PATH_TO_FILE_HERE*/);
AudioTools at = new AudioTools(file);
at.play();
// at.clip.getMicrosecondPosition() works here if loaded file is .wav.
// at.player.getPosition() returns null if loaded file is .mp3.
}
从主课程开始,我希望能够获得玩家当前的位置。目前,尝试此操作将返回null。
任何有用的评论表示赞赏。我之前曾问过类似的问题,这次编辑使问题更清晰,更短。
编辑:应该包含运行示例的所有代码necissary。
答案 0 :(得分:1)
我不确定我是否完成了解你的问题,但我会尝试向你解释一些事情。
假设您有一个班级Clip
,其中300毫秒到1000毫秒的随机时间(仅举例)播放剪辑的一秒并设置变量currentLength
这是您想要获得的来自其他主题。
public class Clip implements Runnable {
private int clipLength;
private volatile int currentLength;
public Clip(int clipLength) {
this.clipLength = clipLength;
}
public void run() {
while (currentLength <= clipLength) {
try {
currentLength += 1;
Thread.sleep(ThreadLocalRandom.current().nextInt(300, 1000 + 1));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public int getCurrentLength() {
return currentLength;
}
public void setCurrentLength(int currentLength) {
this.currentLength = currentLength;
}
}
还可以说你有一个类Player
,它的作用是获取剪辑对象,并在一段时间后请求它的当前长度。
public class Player implements Runnable {
private Clip clip;
public Player(Clip clip) {
this.clip = clip;
}
public void run() {
try {
Thread.sleep(1000);
System.out.println(clip.getCurrentLength());
Thread.sleep(2000);
System.out.println(clip.getCurrentLength());
Thread.sleep(1000);
System.out.println(clip.getCurrentLength());
Thread.sleep(3000);
System.out.println(clip.getCurrentLength());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
此外,我们有一个Main类包含程序的开头,我们创建一个Clip对象并将其传递给to runnable类。
public class Main {
public static void main(String[] args) {
Clip clip = new Clip(60);
Thread thread = new Thread(clip);
thread.start();
Thread threadPlayer = new Thread(new Player(clip));
threadPlayer.start();
}
}
我认为这是您要求的内容,但在将其实施到您的计划之前,您应该阅读atomic access and volatile keyword并了解Java memory model.
答案 1 :(得分:0)
使用不同的方法解决,这甚至不是问题的一部分。我已经有一个解密的音频数据数组,我可以将其变成Clip可以播放的AudioInputStream。