/
Player.java
263 lines (220 loc) · 6.94 KB
/
Player.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/*
* _______ _____ _____ _____
* |__ __| | __ \ / ____| __ \
* | | __ _ _ __ ___ ___ ___| | | | (___ | |__) |
* | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/
* | | (_| | | \__ \ (_) \__ \ |__| |____) | |
* |_|\__,_|_| |___/\___/|___/_____/|_____/|_|
*
* -----------------------------------------------------------
*
* TarsosDSP is developed by Joren Six at
* The School of Arts,
* University College Ghent,
* Hoogpoort 64, 9000 Ghent - Belgium
*
* -----------------------------------------------------------
*
* Info: http://tarsos.0110.be/tag/TarsosDSP
* Github: https://github.com/JorenSix/TarsosDSP
* Releases: http://tarsos.0110.be/releases/TarsosDSP/
*
* TarsosDSP includes modified source code by various authors,
* for credits and info, see README.
*
*/
package be.hogent.tarsos.dsp.example;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import be.hogent.tarsos.dsp.AudioDispatcher;
import be.hogent.tarsos.dsp.AudioEvent;
import be.hogent.tarsos.dsp.AudioPlayer;
import be.hogent.tarsos.dsp.AudioProcessor;
import be.hogent.tarsos.dsp.GainProcessor;
import be.hogent.tarsos.dsp.WaveformSimilarityBasedOverlapAdd;
import be.hogent.tarsos.dsp.WaveformSimilarityBasedOverlapAdd.Parameters;
import be.hogent.tarsos.dsp.effects.FlangerEffect;
public class Player implements AudioProcessor {
private PropertyChangeSupport support = new PropertyChangeSupport(this);
private PlayerState state;
private File loadedFile;
private GainProcessor gainProcessor;
private AudioPlayer audioPlayer;
private WaveformSimilarityBasedOverlapAdd wsola;
private AudioDispatcher dispatcher;
private double durationInSeconds;
private double currentTime;
private double pauzedAt;
private final AudioProcessor beforeWSOLAProcessor;
private final AudioProcessor afterWSOLAProcessor;
private double gain;
private double tempo;
public Player(AudioProcessor beforeWSOLAProcessor,AudioProcessor afterWSOLAProcessor){
state = PlayerState.NO_FILE_LOADED;
gain = 1.0;
tempo = 1.0;
this.beforeWSOLAProcessor = beforeWSOLAProcessor;
this.afterWSOLAProcessor = afterWSOLAProcessor;
}
public void load(File file) {
if(state != PlayerState.NO_FILE_LOADED){
eject();
}
loadedFile = file;
AudioFileFormat fileFormat;
try {
fileFormat = AudioSystem.getAudioFileFormat(loadedFile);
} catch (UnsupportedAudioFileException e) {
throw new Error(e);
} catch (IOException e) {
throw new Error(e);
}
AudioFormat format = fileFormat.getFormat();
durationInSeconds = fileFormat.getFrameLength() / format.getFrameRate();
pauzedAt = 0;
currentTime = 0;
setState(PlayerState.FILE_LOADED);
}
public void eject(){
loadedFile = null;
stop();
setState(PlayerState.NO_FILE_LOADED);
}
public void play(){
if(state == PlayerState.NO_FILE_LOADED){
throw new IllegalStateException("Can not play when no file is loaded");
} else if(state == PlayerState.PAUZED) {
play(pauzedAt);
} else {
play(0);
}
}
public void play(double startTime) {
if(state == PlayerState.NO_FILE_LOADED){
throw new IllegalStateException("Can not play when no file is loaded");
} else {
try {
AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(loadedFile);
AudioFormat format = fileFormat.getFormat();
gainProcessor = new GainProcessor(gain);
audioPlayer = new AudioPlayer(format);
wsola = new WaveformSimilarityBasedOverlapAdd(Parameters.slowdownDefaults(tempo,format.getSampleRate()));
dispatcher = AudioDispatcher.fromFile(loadedFile,wsola.getInputBufferSize(),wsola.getOverlap());
wsola.setDispatcher(dispatcher);
dispatcher.skip(startTime);
dispatcher.addAudioProcessor(this);
dispatcher.addAudioProcessor(new FlangerEffect(0.05, 0.8, 44100, 1));
dispatcher.addAudioProcessor(beforeWSOLAProcessor);
dispatcher.addAudioProcessor(wsola);
dispatcher.addAudioProcessor(afterWSOLAProcessor);
dispatcher.addAudioProcessor(gainProcessor);
dispatcher.addAudioProcessor(audioPlayer);
Thread t = new Thread(dispatcher,"Audio Player Thread");
t.start();
setState(PlayerState.PLAYING);
} catch (UnsupportedAudioFileException e) {
throw new Error(e);
} catch (IOException e) {
throw new Error(e);
} catch (LineUnavailableException e) {
throw new Error(e);
}
}
}
public void pauze(){
pauze(currentTime);
}
public void pauze(double pauzeAt) {
if(state == PlayerState.PLAYING || state == PlayerState.PAUZED){
setState(PlayerState.PAUZED);
dispatcher.stop();
pauzedAt = pauzeAt;
} else {
throw new IllegalStateException("Can not pauze when nothing is playing");
}
}
public void stop(){
if(state == PlayerState.PLAYING || state == PlayerState.PAUZED){
setState(PlayerState.STOPPED);
dispatcher.stop();
} else if(state != PlayerState.STOPPED){
throw new IllegalStateException("Can not stop when nothing is playing");
}
}
public void setGain(double newGain){
gain = newGain;
if(state == PlayerState.PLAYING ){
gainProcessor.setGain(gain);
}
}
public void setTempo(double newTempo){
tempo = newTempo;
if(state == PlayerState.PLAYING ){
wsola.setParameters(Parameters.slowdownDefaults(tempo,dispatcher.getFormat().getSampleRate()));
}
}
public double getDurationInSeconds() {
if(state == PlayerState.NO_FILE_LOADED){
throw new IllegalStateException("No file loaded, unable to determine the duration in seconds");
}
return durationInSeconds;
}
private void setState(PlayerState newState){
PlayerState oldState = state;
state = newState;
support.firePropertyChange("state", oldState, newState);
}
public PlayerState getState() {
return state;
}
public void addPropertyChangeListener(PropertyChangeListener l) {
support.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
support.removePropertyChangeListener(l);
}
@Override
public boolean process(AudioEvent audioEvent) {
currentTime = audioEvent.getTimeStamp();
return true;
}
@Override
public void processingFinished() {
if(state==PlayerState.PLAYING){
setState(PlayerState.STOPPED);
}
}
/**
* Defines the state of the audio player.
* @author Joren Six
*/
public static enum PlayerState{
/**
* No file is loaded.
*/
NO_FILE_LOADED,
/**
* A file is loaded and ready to be played.
*/
FILE_LOADED,
/**
* The file is playing
*/
PLAYING,
/**
* Audio play back is paused.
*/
PAUZED,
/**
* Audio play back is stopped.
*/
STOPPED
}
}