📄 playbackthread.java
字号:
package abchr.audio;
import guiutils.PositionMarker;
import javax.sound.sampled.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.io.IOException;
import java.util.Vector;
import java.util.Arrays;
public class PlaybackThread implements ChangeListener {
private static final PlaybackThread INSTANCE=new PlaybackThread();
public static PlaybackThread getInstance() {
return INSTANCE;
}
private Mixer mixer;
private int bufferSize;
private Player currentPlayer;
private float start=0.0f;
private float end=-1.0f;
private float startedAt=0;
private boolean fastSwitching=true;
private boolean loop;
private BoundedRangeModel rangeModel;
private PositionMarker posMarker=new PositionMarker();
private class Player implements Runnable {
private Sample sample;
private AudioInputStream stream;
private SourceDataLine line;
private byte[] buffer;
private boolean stop;
private boolean playing;
public Player(Sample sample,SourceDataLine line,float start) {
this.sample=sample;
buffer=new byte[line.getBufferSize()];
initStream(start);
this.line=line;
//System.out.println("end="+end);
}
private void initStream(float start) {
stream=sample.getStream();
AudioFormat format=sample.getFormat();
int offset=SampleOffset.getOffset(sample);
int skip=((int)((start+offset/1000.0f)*format.getFrameRate()))*format.getFrameSize();
try {
int skipped=0;
while(skipped<skip) {
skipped+=stream.skip(skip-skipped);
}
} catch(IOException e) {
e.printStackTrace();
}
}
private void resetStream() {
startedAt=start;
initStream(start);
line.close();
try {
line.open(stream.getFormat(),buffer.length);
} catch(LineUnavailableException e) {
e.printStackTrace();
}
}
public void run() {
line.start();
int n=0;
long linePosition;
long lastPositionUpdate=0;
setPlaying(true);
try {
while(!stopRequested()) {
linePosition=line.getMicrosecondPosition();
//System.out.println("lineposition="+(startedAt+linePosition/1000000.0f)+", end="+end);
if(posMarker!=null && linePosition-lastPositionUpdate>50000l) {
posMarker.setPosition((int)(startedAt*1000+linePosition/1000l));
lastPositionUpdate=linePosition;
}
if(/*end!=-1 && */startedAt+linePosition/1000000.0f+0.01f>end) {
if(isLooping()) {
line.stop();
line.flush();
resetStream();
lastPositionUpdate=0;
line.start();
continue;
}
break;
}
if(line.available()<8192){try{Thread.sleep(20);}catch(InterruptedException e){}continue;}
n=stream.read(buffer,0,line.available());
//System.out.println("read "+n+" bytes");
if(n==-1) {
//System.out.println("n==-1");
/*if(!line.isActive()) {
//System.out.println("line inactive");
if(isLooping()) {
line.flush();
resetStream();
lastPositionUpdate=0;
line.start();
continue;
}
}*/
try{Thread.sleep(20);}catch(InterruptedException e){e.printStackTrace();}
continue;
}
/*if(oldPlayer!=null) {
oldPlayer.stopPlayback();
oldPlayer=null;
}*/
/*if(!oldPlayers.isEmpty()) {
((Player)oldPlayers.get(0)).stopPlayback();
//oldPlayer=null;
}*/
line.write(buffer,0,n);
}
} catch(IOException e) {
e.printStackTrace();
}
setPlaying(false);
if(n!=-1) {
posMarker.setPosition(-1);
}
//line.stop();
line.close();
}
public float getPosition() {
return startedAt+line.getMicrosecondPosition()/1000000.0f;
}
public synchronized void stopPlayback() {
line.stop();
stop=true;
}
public synchronized boolean stopRequested(){return stop;}
public synchronized boolean isPlaying(){return playing;}
private synchronized void setPlaying(boolean playing){this.playing=playing;}
}
private PlaybackThread() {
Mixer.Info[] info=AudioSystem.getMixerInfo();
/*System.out.println(Arrays.deepToString(info));
for(Mixer.Info in : info) {
System.out.println(in.getDescription());
Mixer mixer=AudioSystem.getMixer(in);
Line.Info[] sourceLineInfo=mixer.getSourceLineInfo();
for(int i=0;i<sourceLineInfo.length;i++) {
System.out.println(sourceLineInfo[i].toString());
}
}
mixer=null;
for(int i=0;i<info.length;i++) {
if(info[i].getName().startsWith("Java Sound")) {
mixer=AudioSystem.getMixer(info[i]);
javaAudioMixer=true;
}
}*/
for(Mixer.Info in : info) {
Mixer m=AudioSystem.getMixer(in);
if(m.getSourceLineInfo().length!=0){mixer=m;}
}
//mixer=AudioSystem.getMixer(info[0]);
Control[] controls=mixer.getControls();
for(int i=0;i<controls.length;i++) {
if(controls[i].getType()==EnumControl.Type.REVERB) {
Object[] values=((EnumControl)controls[i]).getValues();
ReverbType rt;
for(int j=0;j<values.length;j++) {
rt=(ReverbType)values[j];
if(rt.getEarlyReflectionIntensity()==0.0f && rt.getLateReflectionIntensity()==0.0f && rt.getDecayTime()==0) {
((EnumControl)controls[i]).setValue(values[j]);
//System.out.println("Set Reverb to "+controls[i]);
}
}
}
}
}
public void shutdown() {
stopPlayback();
}
private Vector oldPlayers=new Vector();
public void play(Sample sample) {
SourceDataLine line=null;
AudioFormat format=sample.getFormat();
DataLine.Info info=new DataLine.Info(SourceDataLine.class,format,format.getFrameSize()*(int)(bufferSize*format.getSampleRate()/1000));
try {
line=(SourceDataLine)mixer.getLine(info);
line.open(format,format.getFrameSize()*(int)(bufferSize*format.getSampleRate()/1000));
if(SampleGain.getGain(sample)!=0.0f) {
FloatControl gainControl=(FloatControl)line.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(SampleGain.getGain(sample));
}
} catch(LineUnavailableException e) {
e.printStackTrace();
}
if(currentPlayer!=null){oldPlayers.add(currentPlayer);}
if(currentPlayer!=null && currentPlayer.isPlaying() && fastSwitching) {
startedAt=currentPlayer.getPosition();
} else {
startedAt=start;
}
currentPlayer=new Player(sample,line,startedAt);
Thread t=new Thread(currentPlayer);
t.start();
Thread.yield();
if(!oldPlayers.isEmpty()) {
synchronized(oldPlayers) {
while(!oldPlayers.isEmpty()) {
((Player)oldPlayers.get(0)).stopPlayback();
oldPlayers.remove(0);
}
}
}
}
public void stopPlayback() {
stopPlayback(false);
}
public void stopPlayback(boolean pause) {
posMarker.setPosition(-1);
//System.out.println("stopPlayback");
if(currentPlayer!=null){currentPlayer.stopPlayback();}
}
public boolean isFastSwitching(){return fastSwitching;}
public void setFastSwitching(boolean fastSwitching){this.fastSwitching=fastSwitching;}
public synchronized boolean isLooping(){return loop;}
public synchronized void setLooping(boolean loop){this.loop=loop;}
public void stateChanged(ChangeEvent e) {
stopPlayback();
start=rangeModel.getValue()/1000.0f;
end=(rangeModel.getValue()+rangeModel.getExtent())/1000.0f;
}
public void setRangeModel(BoundedRangeModel model) {
if(rangeModel!=null){rangeModel.removeChangeListener(this);}
rangeModel=model;
if(rangeModel!=null){rangeModel.addChangeListener(this);}
stateChanged(null);
}
public BoundedRangeModel getRangeModel(){return rangeModel;}
public PositionMarker getPosMarker(){return posMarker;}
public int getBufferSize(){return bufferSize;}
public void setBufferSize(int bufferSize){this.bufferSize=bufferSize;}
public Mixer.Info getMixer(){return mixer.getMixerInfo();}
public void setMixer(Mixer.Info info){stopPlayback();mixer=AudioSystem.getMixer(info);}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -