所以我试图让Java在这方面以一定的速度播放声音我尝试为SourceDataLine获取一个Controll for Sample rate:
`package com.pap.sound;
import javax.sound.sampled.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.BitSet;
public class Player implements Playable {
private AudioFormat format;
private SourceDataLine sourceDataLine;
private DataLine.Info info;
private final URL soundUrl;
private final boolean[] stopped;
private float playRate;
private boolean playRateChanged;
public Player(URL soundUrl) throws LineUnavailableException, MalformedURLException {
this.format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,44100, 16, 2 , 4, 44100,false);
this.info = new DataLine.Info(SourceDataLine.class, format);
this.sourceDataLine = (SourceDataLine) AudioSystem.getLine(info);
this.soundUrl = soundUrl;
this.stopped = new boolean[1];
this.stopped[0] = false;
this.playRate = 1;
this.playRateChanged = false;
}
@Override
public boolean play() throws LineUnavailableException {
sourceDataLine.open();
Thread playerThread = new Thread(){
@Override
public void run() {
int numberOfBitesRead = 0;
AudioInputStream auis = null;
try {
auis = AudioSystem.getAudioInputStream(soundUrl);
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
byte[] bytes = new byte[4];
sourceDataLine.start();
try {
auis.mark(auis.available());
while(!stopped[0]) {
numberOfBitesRead = auis.read(bytes);
if(numberOfBitesRead == -1) {
auis.reset();
}
sourceDataLine.write(bytes, 0, bytes.length);
FloatControl fc = (FloatControl) sourceDataLine.getControl(FloatControl.Type.SAMPLE_RATE);
if(playRateChanged) {
fc.setValue((int)(44200*playRate));
playRateChanged = false;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
playerThread.start();
return false;
}
@Override
public boolean stop() {
this.stopped[0] = true;
this.sourceDataLine.stop();
this.sourceDataLine.close();
return false;
}
@Override
public boolean setPlayRate(float playRate) {
this.playRate = playRate;
this.playRateChanged = true;
return false;
}
}`
但在运行时我得到:
Exception in thread "Thread-1" java.lang.IllegalArgumentException: Unsupported control type: Sample Rate
at com.sun.media.sound.AbstractLine.getControl(AbstractLine.java:150)
at com.pap.sound.Player$1.run(Player.java:67)
答案 0 :(得分:0)
最后我想出了一个解决方案。因为旧的FloatControl.Type.SAMPLE_RATE
在Java 8中不再可用,我选择通过在播放声音时省略一些字节来增加样本量,解决方案如下所示:
这是界面:
package com.pap.sound;
import javax.sound.sampled.LineUnavailableException;
public interface Playable {
public boolean play() throws LineUnavailableException;
public boolean stop();
public boolean setPlayRate(float playRate);
}
这是玩家类:
package com.pap.sound;
import com.sun.media.sound.AudioFloatFormatConverter;
import com.sun.media.sound.JavaSoundAudioClip;
import com.sun.media.sound.SoftMixingDataLine;
import javax.sound.sampled.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
public class Player implements Playable {
private AudioFormat format;
private SourceDataLine sourceDataLine;
private DataLine.Info info;
private final URL soundUrl;
private final boolean[] stopped;
private float playRate;
private boolean playRateChanged;
private int bytesWritten;
private int bytesIgnorred;
public Player(URL soundUrl) throws LineUnavailableException, MalformedURLException {
this.format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,44100, 16, 2 , 4, 44100,false);
this.info = new DataLine.Info(SourceDataLine.class, format);
this.sourceDataLine = (SourceDataLine) AudioSystem.getLine(info);
TargetDataLine tdl = AudioSystem.getTargetDataLine(format);
this.soundUrl = soundUrl;
this.stopped = new boolean[1];
this.stopped[0] = false;
this.playRate = 1;
this.playRateChanged = false;
this.bytesWritten =0;
this.bytesIgnorred = 0;
}
@Override
public boolean play() throws LineUnavailableException {
sourceDataLine.open();
final Thread playerThread = new Thread(){
@Override
public void run() {
int numberOfBitesRead = 0;
AudioInputStream auis = null;
try {
auis = AudioSystem.getAudioInputStream(soundUrl);
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
byte[] bytes = new byte[4];
sourceDataLine.start();
try {
auis.mark(auis.available());
while(!stopped[0]) {
numberOfBitesRead = auis.read(bytes);
if(numberOfBitesRead == -1) {
auis.reset();
}
if(bytesWritten < (10)) {
sourceDataLine.write(bytes, 0, bytes.length);
bytesWritten+=4;
} else {
if(bytesIgnorred < ((int)(playRate*10-10))) {
bytesIgnorred+=4;
} else {
bytesWritten =0;
bytesIgnorred = 0;
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
playerThread.start();
return false;
}
@Override
public boolean stop() {
this.stopped[0] = true;
this.sourceDataLine.stop();
this.sourceDataLine.close();
return false;
}
@Override
public boolean setPlayRate(float playRate) {
this.playRate = playRate;
this.playRateChanged = true;
return false;
}
}
为了测试它,我使用了以下代码:
package com.pap.main;
import com.pap.sound.Player;
import javax.sound.sampled.LineUnavailableException;
import java.net.MalformedURLException;
import java.net.URL;
public class Main {
public static void main(String[] args) throws MalformedURLException, LineUnavailableException, InterruptedException {
URL url = ClassLoader.getSystemClassLoader().getSystemResource("steam.wav");
Player player = new Player(url);
player.play();
Thread.sleep(2000);
for(int i=0;i<60;i++) {
player.setPlayRate(1f+(float)(i)*0.1f);
System.out.println(1f+(float)(i)*0.1f + "x");
Thread.sleep(1000);
}
player.stop();
}
}