2
* Created on 24-nov-2005
4
* TODO To change the template for this generated file go to
5
* Window - Preferences - Java - Code Style - Code Templates
7
package org.herac.tuxguitar.player.impl;
10
import java.io.IOException;
11
import java.io.OutputStream;
12
import java.util.ArrayList;
13
import java.util.Iterator;
14
import java.util.List;
16
import javax.sound.midi.Instrument;
17
import javax.sound.midi.InvalidMidiDataException;
18
import javax.sound.midi.MidiMessage;
19
import javax.sound.midi.MidiSystem;
20
import javax.sound.midi.MidiUnavailableException;
21
import javax.sound.midi.Receiver;
22
import javax.sound.midi.Sequencer;
23
import javax.sound.midi.Soundbank;
24
import javax.sound.midi.Synthesizer;
25
import javax.sound.midi.Transmitter;
27
import org.eclipse.swt.widgets.Composite;
28
import org.eclipse.swt.widgets.ToolBar;
29
import org.herac.tuxguitar.gui.TuxGuitar;
30
import org.herac.tuxguitar.gui.system.config.ConfigKeys;
31
import org.herac.tuxguitar.gui.system.config.ConfigEditor;
32
import org.herac.tuxguitar.gui.system.config.items.Option;
33
import org.herac.tuxguitar.gui.system.config.items.SoundOption;
34
import org.herac.tuxguitar.gui.util.SystemError;
35
import org.herac.tuxguitar.player.base.MidiControllers;
36
import org.herac.tuxguitar.player.base.MidiPlayer;
37
import org.herac.tuxguitar.player.base.MidiSequenceParser;
38
import org.herac.tuxguitar.song.managers.SongManager;
39
import org.herac.tuxguitar.song.models.Duration;
40
import org.herac.tuxguitar.song.models.InstrumentString;
41
import org.herac.tuxguitar.song.models.Note;
42
import org.herac.tuxguitar.song.models.SongTrack;
47
* TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code Templates
49
public class MidiPlayerImpl implements MidiPlayer {
51
private static final int MAX_CHANNELS = 16;
53
private SongManager songManager;
55
private Sequencer sequencer;
57
private Synthesizer synthesizer;
59
private Receiver receiver;
61
private Soundbank soundbank;
63
private MidiMetaEventListener controller;
65
private boolean running;
67
private boolean paused;
69
private boolean changeTickPosition;
71
private long tickPosition;
73
private boolean metronomeEnabled;
75
private int metronomeTrack;
77
private int infoTrack;
79
private boolean anySolo;
81
private List systemErrors;
83
public MidiPlayerImpl() {
84
this.songManager = TuxGuitar.instance().getSongManager();
85
this.controller = new MidiMetaEventListener();
86
this.systemErrors = new ArrayList();
92
* Inicia el Secuenciador y Sintetizador
93
* @throws MidiUnavailableException
102
boolean loadCustomSoundbank = TuxGuitar.instance().getConfig().getBooleanConfigValue(ConfigKeys.SOUNDBANK_CUSTOM);
103
if(loadCustomSoundbank){
104
if(!loadSoundbank(new File(TuxGuitar.instance().getConfig().getStringConfigValue(ConfigKeys.SOUNDBANK_CUSTOM_PATH)))){
105
this.systemErrors.add(SystemError.getError(TuxGuitar.getProperty("soundbank.error"), TuxGuitar.getProperty("soundbank.error.custom")));
108
} catch (MidiUnavailableException e) {
114
* Retorna el Sequenciador
115
* @throws MidiUnavailableException
117
private Sequencer getSequencer() throws MidiUnavailableException {
118
if (this.sequencer == null) {
119
this.sequencer = MidiSystem.getSequencer(false);
120
this.sequencer.addMetaEventListener(this.controller);
122
if (!this.sequencer.isOpen()) {
123
this.sequencer.open();
125
return this.sequencer;
129
* Retorna el Sintetizador
130
* @throws MidiUnavailableException
132
public Synthesizer getSynthesizer() throws MidiUnavailableException {
133
if (this.synthesizer == null) {
134
setSynthesizer(MidiSystem.getSynthesizer());
136
return this.synthesizer;
140
* Retorna el Soundbank por defecto
141
* @throws MidiUnavailableException
143
public Soundbank getSoundbank(){
144
if (this.soundbank == null) {
146
Synthesizer synthesizer = getSynthesizer();
147
this.soundbank = synthesizer.getDefaultSoundbank();
148
} catch (MidiUnavailableException e) {
152
return this.soundbank;
156
* Asigna un Synthesizer
158
public void setSynthesizer(Synthesizer synthesizer){
160
this.soundbank = null;
161
if(this.synthesizer != null && this.synthesizer.isOpen()){
162
this.synthesizer.close();
164
this.synthesizer = synthesizer;
165
if(this.synthesizer != null){
166
this.synthesizer.open();
167
this.connect(this.synthesizer.getReceiver());
169
} catch (MidiUnavailableException e) {
175
* Conecta el Synthesizer al Sequencer
177
public void connect(Receiver receiver){
178
this.receiver = receiver;
183
* Conecta el Synthesizer al Sequencer
185
public void connect(){
187
Iterator it = getSequencer().getTransmitters().iterator();
189
((Transmitter)it.next()).close();
191
Transmitter transmitter = getSequencer().getTransmitter();
192
transmitter.setReceiver(this.receiver);
193
} catch (MidiUnavailableException e) {
199
* Resetea los valores
203
this.tickPosition = Duration.QUARTER_TIME;
204
this.setChangeTickPosition(false);
205
this.controller.reset();
209
* Cierra el Secuenciador y Sintetizador
210
* @throws MidiUnavailableException
214
this.soundbank = null;
215
if (this.synthesizer != null) {
216
this.synthesizer.close();
217
this.synthesizer = null;
219
if (this.sequencer != null) {
220
this.sequencer.close();
221
this.sequencer = null;
226
* Para la reproduccion
227
* @throws MidiUnavailableException
229
public void stop(boolean paused) {
230
this.setPaused(paused);
232
if(this.isRunning() && this.getSequencer().isOpen()){
235
this.getSequencer().stop();
237
} catch (MidiUnavailableException e) {
240
this.setRunning(false);
244
* Para la reproduccion
245
* @throws MidiUnavailableException
256
* Inicia la reproduccion
257
* @throws MidiUnavailableException
259
public synchronized void play(){
263
this.updatePrograms();
264
this.updateControllers();
265
this.updateDefaultControllers();
266
this.setMetronomeEnabled(isMetronomeEnabled());
267
this.setChangeTickPosition(true);
268
this.setRunning(true);
269
this.getSequencer().start();
270
new Thread(new Runnable() {
271
public synchronized void run() {
273
while (getSequencer().isRunning() && isRunning()) {
274
if (isChangeTickPosition()) {
275
changeTickPosition();
277
tickPosition = getSequencer().getTickPosition();
282
if(tickPosition >= (getSequencer().getTickLength() - 500)){
288
} catch (InterruptedException e) {
290
} catch (MidiUnavailableException e) {
296
}catch (MidiUnavailableException e) {
302
public void send(MidiMessage message){
303
if(this.receiver != null){
304
this.receiver.send(message,-1);
309
* Asigna el valor a running
311
public void setRunning(boolean running) {
312
this.running = running;
316
* Retorna True si esta reproduciendo
318
public boolean isRunning() {
322
public boolean isPaused() {
326
public void setPaused(boolean paused) {
327
this.paused = paused;
331
* Retorna True si hay cambios en la posicion
333
private boolean isChangeTickPosition() {
334
return changeTickPosition;
338
* Asigna los cambios de la posicion
340
private void setChangeTickPosition(boolean changeTickPosition) {
341
this.changeTickPosition = changeTickPosition;
346
* Indica la posicion del secuenciador
347
* @throws MidiUnavailableException
349
public void setTickPosition(long position) {
350
setTickPosition(position,controller.getMove());
354
* Indica la posicion del secuenciador
355
* @throws MidiUnavailableException
357
public void setTickPosition(long position,long move) {
358
this.tickPosition = position;
359
this.controller.setMove(move);
360
this.setChangeTickPosition(true);
362
this.changeTickPosition();
367
* Retorna el tick de la nota que esta reproduciendo
369
public long getTickPosition() {
370
return this.tickPosition - this.controller.getMove();
373
private void changeTickPosition(){
376
this.getSequencer().setTickPosition(tickPosition);
377
//reseteo los volumenes.
378
//this.setMetronomeEnabled(isMetronomeEnabled());
379
//this.updateControllers();
381
} catch (MidiUnavailableException e) {
384
setChangeTickPosition(false);
388
* Agrega la Secuencia
389
* @throws MidiUnavailableException
391
public void addSecuence() {
393
MidiSequenceParser parser = new MidiSequenceParser(songManager,MidiSequenceParser.DEFAULT_PLAY_FLAGS);
394
MidiSequenceImpl sequence = new MidiSequenceImpl(songManager);
395
parser.parse(sequence);
396
this.getSequencer().setSequence(sequence.getSequence());
397
this.infoTrack = sequence.getInfoTrack();
398
this.metronomeTrack = sequence.getMetronomeTrack();
399
} catch (MidiUnavailableException e) {
401
} catch (InvalidMidiDataException e) {
406
private void updateDefaultControllers(){
407
for(int channel = 0; channel < MAX_CHANNELS;channel ++){
408
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.REGISTERED_PARAMETER_FINE,0));
409
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.REGISTERED_PARAMETER_COARSE,0));
410
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.DATA_ENTRY_COARSE,12));
411
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.REGISTERED_PARAMETER_COARSE,0));
412
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.REGISTERED_PARAMETER_FINE,1));
413
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.DATA_ENTRY_COARSE,64));
414
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.REGISTERED_PARAMETER_FINE,127));
418
public void updatePrograms() {
419
Iterator it = this.songManager.getSong().getTracks().iterator();
421
SongTrack track = (SongTrack)it.next();
422
this.send(MidiMessageUtils.programChange(track.getChannel().getChannel(),track.getChannel().getInstrument()));
423
if(track.getChannel().getChannel() != track.getChannel().getEffectChannel()){
424
this.send(MidiMessageUtils.programChange(track.getChannel().getEffectChannel(),track.getChannel().getInstrument()));
429
public void updateControllers() {
431
this.anySolo = false;
432
Iterator it = this.songManager.getSong().getTracks().iterator();
434
SongTrack track = (SongTrack)it.next();
435
this.updateController(track);
436
this.anySolo = ((!this.anySolo)?track.getChannel().isSolo():this.anySolo);
439
} catch (MidiUnavailableException e) {
444
private void updateController(SongTrack track) throws MidiUnavailableException {
445
int volume = (int)(((double)this.songManager.getSong().getVolume() / 10.0) * track.getChannel().getVolume());
446
int balance = track.getChannel().getBalance();
447
updateController(track.getChannel().getChannel(),volume,balance);
448
if(track.getChannel().getChannel() != track.getChannel().getEffectChannel()){
449
updateController(track.getChannel().getEffectChannel(),volume,balance);
451
getSequencer().setTrackMute(track.getNumber(),track.getChannel().isMute());
452
getSequencer().setTrackSolo(track.getNumber(),track.getChannel().isSolo());
455
private void updateController(int channel,int volume,int balance) throws MidiUnavailableException {
456
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.VOLUME,volume));
457
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.BALANCE,balance));
460
private void afterUpdate() throws MidiUnavailableException{
461
getSequencer().setTrackSolo(this.infoTrack,this.anySolo);
462
getSequencer().setTrackSolo(this.metronomeTrack,(isMetronomeEnabled() && this.anySolo));
465
public boolean isMetronomeEnabled() {
466
return metronomeEnabled;
469
public void setMetronomeEnabled(boolean metronomeEnabled) {
471
this.metronomeEnabled = metronomeEnabled;
472
this.getSequencer().setTrackMute(this.metronomeTrack,!isMetronomeEnabled());
473
this.getSequencer().setTrackSolo(this.metronomeTrack,(isMetronomeEnabled() && this.anySolo));
474
} catch (MidiUnavailableException e) {
479
public void allNotesOff(){
480
for(int channel = 0;channel < MAX_CHANNELS;channel ++){
481
this.send(MidiMessageUtils.controlChange(channel, MidiControllers.ALL_NOTES_OFF,0));
485
private void systemReset(){
486
this.send(MidiMessageUtils.systemReset());
489
public void playBeat(final SongTrack track,final List notes) {
490
final int channel = track.getChannel().getChannel();
491
final int program = track.getChannel().getInstrument();
492
final int volume = (int)(((double)this.songManager.getSong().getVolume() / 10.0) * track.getChannel().getVolume());
493
final int balance = track.getChannel().getBalance();
494
this.send(MidiMessageUtils.programChange(channel,program));
495
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.VOLUME,volume));
496
this.send(MidiMessageUtils.controlChange(channel,MidiControllers.BALANCE,balance));
497
Iterator it = notes.iterator();
499
final Note note = (Note)it.next();
500
new Thread(new Runnable() {
503
int key = track.getOffset() + (note.getValue() + ((InstrumentString)track.getStrings().get(note.getString() - 1)).getValue());
504
int velocity = note.getVelocity();
505
send(MidiMessageUtils.noteOn(channel, key, velocity));
507
send(MidiMessageUtils.noteOff(channel, key, velocity));
508
} catch (InterruptedException e) {
516
public boolean loadSoundbank(File file){
518
Soundbank soundbank = MidiSystem.getSoundbank(file);
519
if (soundbank != null && getSynthesizer().isSoundbankSupported(soundbank)){
520
//unload the current soundbank
521
if(getSoundbank() != null){
522
getSynthesizer().unloadAllInstruments(getSoundbank());
524
//load the new soundbank
525
getSynthesizer().loadAllInstruments(soundbank);
527
this.soundbank = soundbank;
530
}catch (MidiUnavailableException e) {
532
} catch (InvalidMidiDataException e) {
534
} catch (IOException e) {
540
public void write(OutputStream out){
542
MidiSequenceParser parser = new MidiSequenceParser(songManager,MidiSequenceParser.DEFAULT_EXPORT_FLAGS);
543
MidiSequenceImpl sequence = new MidiSequenceImpl(songManager);
544
parser.parse(sequence);
545
MidiSystem.write(sequence.getSequence(),1,out);
546
} catch (IOException e) {
551
public String getInstrumentName(int instrument){
553
Soundbank soundBank = getSoundbank();
554
if(soundBank != null){
555
Instrument[] instruments = soundBank.getInstruments();
556
if(instrument >= 0 && instrument < instruments.length){
557
return instruments[instrument].getName();
560
return Integer.toString(instrument);
563
public List getSystemErrors() {
564
return this.systemErrors;
567
public Option getConfigOption(ConfigEditor editor,ToolBar toolBar,Composite parent){
568
return new SoundOption(editor,toolBar,parent);
b'\\ No newline at end of file'