package org.herac.tuxguitar.player.base; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.herac.tuxguitar.song.managers.TGSongManager; import org.herac.tuxguitar.song.models.TGBeat; import org.herac.tuxguitar.song.models.TGChannel; import org.herac.tuxguitar.song.models.TGChannelParameter; import org.herac.tuxguitar.song.models.TGDuration; import org.herac.tuxguitar.song.models.TGMeasureHeader; import org.herac.tuxguitar.song.models.TGNote; import org.herac.tuxguitar.song.models.TGString; import org.herac.tuxguitar.song.models.TGTrack; import org.herac.tuxguitar.util.TGLock; public class MidiPlayer{ public static final int MAX_VOLUME = 10; private static final int TIMER_DELAY = 10; private static MidiPlayer instance; private TGSongManager songManager; private MidiSequencer sequencer; private MidiSynthesizerProxy synthesizerProxy; private MidiChannelRouter channelRouter; private MidiTransmitter outputTransmitter; private MidiOutputPort outputPort; private MidiPlayerMode mode; private MidiPlayerCountDown countDown; private String sequencerKey; private String outputPortKey; private List outputPortProviders; private List sequencerProviders; private List listeners; private int volume; private boolean running; private boolean paused; private boolean changeTickPosition; private boolean metronomeEnabled; private int metronomeTrack; private int infoTrack; private int loopSHeader; private int loopEHeader; private long loopSPosition; private boolean anySolo; protected long tickLength; protected long tickPosition; private boolean tryOpenFistDevice; protected TGLock lock = new TGLock(); private MidiPlayer() { this.lock = new TGLock(); this.volume = MAX_VOLUME; } public static MidiPlayer getInstance(){ synchronized (MidiPlayer.class) { if( instance == null ){ instance = new MidiPlayer(); } return instance; } } public void init(TGSongManager songManager) { this.songManager = songManager; this.outputPortProviders = new ArrayList(); this.sequencerProviders = new ArrayList(); this.listeners = new ArrayList(); this.tryOpenFistDevice = false; this.getSequencer(); this.getMode(); this.reset(); } public MidiInstrument[] getInstruments(){ return MidiInstrument.INSTRUMENT_LIST; } public MidiPercussion[] getPercussions(){ return MidiPercussion.PERCUSSION_LIST; } public void reset(){ this.stop(); this.lock.lock(); this.tickPosition = TGDuration.QUARTER_TIME; this.setChangeTickPosition(false); this.lock.unlock(); } public void close(){ try { this.closeSequencer(); this.closeOutputPort(); } catch (MidiPlayerException e) { e.printStackTrace(); } } public void stopSequencer() { try{ if( this.getSequencer().isRunning() ){ this.getSequencer().stop(); } }catch (MidiPlayerException e) { e.printStackTrace(); } } public void stop(boolean paused) { this.setPaused(paused); this.stopSequencer(); this.setRunning(false); } public void stop() { this.stop(false); } public void pause(){ this.stop(true); } public synchronized void play() throws MidiPlayerException{ try { this.lock.lock(); final boolean notifyStarted = (!this.isRunning()); this.setRunning(true); this.stopSequencer(); this.checkDevices(); this.updateLoop(true); this.addSequence(); this.updateTracks(); this.updateChannels(); this.updatePrograms(); this.updateControllers(); this.updateDefaultControllers(); this.setMetronomeEnabled(isMetronomeEnabled()); this.getCountDown().setTempoPercent(getMode().getCurrentPercent()); this.changeTickPosition(); new Thread(new Runnable() { @Override public synchronized void run() { try { MidiPlayer.this.lock.lock(); if( notifyStarted ){ MidiPlayer.this.notifyStarted(); } if( MidiPlayer.this.getCountDown().isEnabled() ){ MidiPlayer.this.notifyCountDownStarted(); MidiPlayer.this.getCountDown().start(); MidiPlayer.this.notifyCountDownStopped(); } if( MidiPlayer.this.isRunning() ){ if( MidiPlayer.this.isChangeTickPosition() ){ MidiPlayer.this.changeTickPosition(); } MidiPlayer.this.getSequencer().start(); } MidiPlayer.this.tickLength = getSequencer().getTickLength(); MidiPlayer.this.tickPosition = getSequencer().getTickPosition(); Object sequencerLock = new Object(); while (getSequencer().isRunning() && isRunning()) { synchronized(sequencerLock) { if (isChangeTickPosition()) { changeTickPosition(); } MidiPlayer.this.tickPosition = getSequencer().getTickPosition(); sequencerLock.wait( TIMER_DELAY ); } } //FINISH if(isRunning()){ if(MidiPlayer.this.tickPosition >= (MidiPlayer.this.tickLength - (TGDuration.QUARTER_TIME / 2) )){ finish(); }else { stop(isPaused()); } } if( !isRunning() ){ MidiPlayer.this.notifyStopped(); } }catch (Throwable throwable) { reset(); throwable.printStackTrace(); }finally{ MidiPlayer.this.lock.unlock(); } } }).start(); }catch (Throwable throwable) { this.reset(); throw new MidiPlayerException(throwable.getMessage(),throwable); }finally{ this.lock.unlock(); } } protected void finish(){ try { if(this.getMode().isLoop()){ this.stopSequencer(); this.setTickPosition(TGDuration.QUARTER_TIME); this.getMode().notifyLoop(); this.notifyLoop(); this.play(); return; } this.reset(); } catch (MidiPlayerException e) { e.printStackTrace(); } } public void updateLoop( boolean force ){ if( force || !this.isRunning() ){ this.loopSHeader = -1; this.loopEHeader = -1; this.loopSPosition = TGDuration.QUARTER_TIME; if( getMode().isLoop() ){ int hCount = this.songManager.getSong().countMeasureHeaders(); this.loopSHeader = ( getMode().getLoopSHeader() <= hCount ? getMode().getLoopSHeader() : -1 ) ; this.loopEHeader = ( getMode().getLoopEHeader() <= hCount ? getMode().getLoopEHeader() : -1 ) ; if( this.loopSHeader > 0 && this.loopSHeader <= hCount ){ TGMeasureHeader header = this.songManager.getMeasureHeader( this.loopSHeader ); if( header != null ){ this.loopSPosition = header.getStart(); } } } } } public int getLoopSHeader() { return this.loopSHeader; } public int getLoopEHeader() { return this.loopEHeader; } public long getLoopSPosition() { return this.loopSPosition; } public boolean isTryOpenFistDevice() { return tryOpenFistDevice; } public void setTryOpenFistDevice(boolean tryOpenFistDevice) { this.tryOpenFistDevice = tryOpenFistDevice; } public void checkDevices() throws Throwable { this.getSequencer().check(); if( this.getOutputPort() != null ){ this.getOutputPort().check(); } } public int getVolume() { return this.volume; } public void setVolume(int volume) { this.volume = volume; if (this.isRunning()) { this.updateControllers(); } } public void setRunning(boolean running) { this.running = running; } public boolean isRunning() { try { return (this.running || this.getSequencer().isRunning()); } catch (MidiPlayerException e) { e.printStackTrace(); } return false; } public boolean isPaused() { return this.paused; } public void setPaused(boolean paused) { this.paused = paused; } protected boolean isChangeTickPosition() { return this.changeTickPosition; } private void setChangeTickPosition(boolean changeTickPosition) { this.changeTickPosition = changeTickPosition; } public void setTickPosition(long position) { this.tickPosition = position; this.setChangeTickPosition(true); } public long getTickPosition() { return this.tickPosition; } protected void changeTickPosition(){ try{ if(isRunning()){ if( this.tickPosition < this.getLoopSPosition() ){ this.tickPosition = this.getLoopSPosition(); } this.getSequencer().setTickPosition(this.tickPosition); } setChangeTickPosition(false); } catch (MidiPlayerException e) { e.printStackTrace(); } } public void addSequence() { try{ MidiSequenceParser midiSequenceParser = new MidiSequenceParser(this.songManager,MidiSequenceParser.DEFAULT_PLAY_FLAGS); midiSequenceParser.setTempoPercent(getMode().getCurrentPercent()); midiSequenceParser.setSHeader( getLoopSHeader() ); midiSequenceParser.setEHeader( getLoopEHeader() ); midiSequenceParser.setMetronomeChannelId(getPercussionChannelId()); midiSequenceParser.parse(getSequencer().createSequence(this.songManager.getSong().countTracks() + 2)); this.infoTrack = midiSequenceParser.getInfoTrack(); this.metronomeTrack = midiSequenceParser.getMetronomeTrack(); } catch (MidiPlayerException e) { e.printStackTrace(); } } public void resetChannels() { try{ this.closeChannels(); this.updateChannels(); } catch (MidiPlayerException e) { e.printStackTrace(); } } public void closeChannels() throws MidiPlayerException{ // Remove all channels. Iterator iterator = getChannelRouter().getMidiChannelIds().iterator(); while( iterator.hasNext() ){ int channelId = ((Integer) iterator.next()).intValue(); this.getSynthesizerProxy().closeChannel(getChannelRouter().getMidiChannel(channelId)); this.getChannelRouter().removeMidiChannel(channelId); } } public void updateChannels() throws MidiPlayerException{ // Remove unused channels. List oldChannelIds = getChannelRouter().getMidiChannelIds(); Iterator iterator = oldChannelIds.iterator(); while( iterator.hasNext() ){ int channelId = ((Integer) iterator.next()).intValue(); boolean removableChannel = ( this.songManager.getChannel(channelId) == null ); if(!removableChannel ){ MidiChannel midiChannel = getChannelRouter().getMidiChannel(channelId); if( midiChannel != null ){ removableChannel = (!this.getSynthesizerProxy().isChannelOpen(midiChannel)); } } if( removableChannel ){ this.getSynthesizerProxy().closeChannel(getChannelRouter().getMidiChannel(channelId)); this.getChannelRouter().removeMidiChannel(channelId); } } // Add channels List newChannelIds = getChannelRouter().getMidiChannelIds(); Iterator tgChannels = this.songManager.getSong().getChannels(); while( tgChannels.hasNext() ){ TGChannel tgChannel = (TGChannel) tgChannels.next(); if(!newChannelIds.contains(new Integer(tgChannel.getChannelId())) ){ MidiChannel midiChannel = this.getSynthesizerProxy().openChannel(tgChannel.getChannelId()); if( midiChannel != null ){ this.getChannelRouter().addMidiChannel(tgChannel.getChannelId(), midiChannel); } } } this.updateParameters(); } public void updateParameters(){ Iterator tgChannels = this.songManager.getSong().getChannels(); while( tgChannels.hasNext() ){ TGChannel tgChannel = (TGChannel) tgChannels.next(); this.updateParameters(tgChannel); } } public void updateParameters(TGChannel tgChannel){ Iterator parameters = tgChannel.getParameters(); while( parameters.hasNext() ){ TGChannelParameter tgChannelParameter = (TGChannelParameter) parameters.next(); this.updateParameters(tgChannel, tgChannelParameter); } } public void updateParameters(TGChannel tgChannel, TGChannelParameter tgChannelParameter){ try { getOutputTransmitter().sendParameter(tgChannel.getChannelId(), tgChannelParameter.getKey(), tgChannelParameter.getValue()); } catch (MidiPlayerException e) { e.printStackTrace(); } } private void updateDefaultControllers(){ try{ Iterator tgChannels = this.songManager.getSong().getChannels(); while( tgChannels.hasNext() ){ TGChannel tgChannel = (TGChannel) tgChannels.next(); getOutputTransmitter().sendControlChange(tgChannel.getChannelId(),MidiControllers.RPN_MSB,0); getOutputTransmitter().sendControlChange(tgChannel.getChannelId(),MidiControllers.RPN_LSB,0); getOutputTransmitter().sendControlChange(tgChannel.getChannelId(),MidiControllers.DATA_ENTRY_MSB,12); getOutputTransmitter().sendControlChange(tgChannel.getChannelId(),MidiControllers.DATA_ENTRY_LSB, 0); } } catch (MidiPlayerException e) { e.printStackTrace(); } } public void updatePrograms() { Iterator it = this.songManager.getSong().getChannels(); while(it.hasNext()){ updateProgram((TGChannel)it.next()); } } private void updateProgram(TGChannel channel) { this.updateProgram(channel.getChannelId(), channel.getBank(), channel.getProgram()); } private void updateProgram(int channelId, int bank, int program) { try{ if( bank >= 0 && bank <= 128 ){ getOutputTransmitter().sendControlChange(channelId, MidiControllers.BANK_SELECT, bank); } if( program >= 0 && program <= 127 ){ getOutputTransmitter().sendProgramChange(channelId, program); } }catch (MidiPlayerException e) { e.printStackTrace(); } } public void updateControllers() { Iterator channelsIt = this.songManager.getSong().getChannels(); while( channelsIt.hasNext() ){ this.updateController( (TGChannel)channelsIt.next() ); } this.afterUpdate(); } private void updateController(TGChannel channel) { int volume = (int)((this.getVolume() / 10.00) * channel.getVolume()); int balance = channel.getBalance(); int chorus = channel.getChorus(); int reverb = channel.getReverb(); int phaser = channel.getPhaser(); int tremolo = channel.getTremolo(); updateController(channel.getChannelId(),volume,balance,chorus,reverb,phaser,tremolo,127); } private void updateController(int channelId,int volume,int balance,int chorus, int reverb,int phaser, int tremolo, int expression) { try{ getOutputTransmitter().sendControlChange(channelId,MidiControllers.VOLUME,volume); getOutputTransmitter().sendControlChange(channelId,MidiControllers.BALANCE,balance); getOutputTransmitter().sendControlChange(channelId,MidiControllers.CHORUS,chorus); getOutputTransmitter().sendControlChange(channelId,MidiControllers.REVERB,reverb); getOutputTransmitter().sendControlChange(channelId,MidiControllers.PHASER,phaser); getOutputTransmitter().sendControlChange(channelId,MidiControllers.TREMOLO,tremolo); getOutputTransmitter().sendControlChange(channelId,MidiControllers.EXPRESSION,expression); }catch (MidiPlayerException e) { e.printStackTrace(); } } public void updateTracks() { this.anySolo = false; Iterator tracksIt = this.songManager.getSong().getTracks(); while( tracksIt.hasNext() ){ TGTrack track = (TGTrack)tracksIt.next(); this.updateTrack(track); this.anySolo = ((!this.anySolo)?track.isSolo():this.anySolo); } this.afterUpdate(); } private void updateTrack(TGTrack track) { try{ getSequencer().setMute(track.getNumber(),track.isMute()); getSequencer().setSolo(track.getNumber(),track.isSolo()); }catch (MidiPlayerException e) { e.printStackTrace(); } } private void afterUpdate(){ try{ getSequencer().setSolo(this.infoTrack,this.anySolo); getSequencer().setSolo(this.metronomeTrack,(isMetronomeEnabled() && this.anySolo)); }catch (MidiPlayerException e) { e.printStackTrace(); } } public boolean isMetronomeEnabled() { return this.metronomeEnabled; } public void setMetronomeEnabled(boolean metronomeEnabled) { try{ this.metronomeEnabled = metronomeEnabled; this.getSequencer().setMute(this.metronomeTrack,!isMetronomeEnabled()); this.getSequencer().setSolo(this.metronomeTrack,(isMetronomeEnabled() && this.anySolo)); }catch (MidiPlayerException e) { e.printStackTrace(); } } public void playBeat(TGBeat beat) { List notes = new ArrayList(); for( int v = 0; v < beat.countVoices(); v ++){ notes.addAll( beat.getVoice(v).getNotes() ); } playBeat(beat.getMeasure().getTrack(), notes); } public void playBeat(TGTrack track,final List notes) { TGChannel tgChannel = this.songManager.getChannel(track.getChannelId()); if( tgChannel != null ){ int channelId = tgChannel.getChannelId(); int bank = tgChannel.getBank(); int program = tgChannel.getProgram(); int volume = (int)((this.getVolume() / 10.00) * tgChannel.getVolume()); int balance = tgChannel.getBalance(); int chorus = tgChannel.getChorus(); int reverb = tgChannel.getReverb(); int phaser = tgChannel.getPhaser(); int tremolo = tgChannel.getTremolo(); int size = notes.size(); int[][] beat = new int[size][2]; for(int i = 0; i < size; i ++){ TGNote note = (TGNote)notes.get(i); beat[i][0] = track.getOffset() + (note.getValue() + ((TGString)track.getStrings().get(note.getString() - 1)).getValue()); beat[i][1] = note.getVelocity(); } playBeat(channelId,bank,program,volume,balance,chorus,reverb,phaser,tremolo,beat); } } public void playBeat(int channelId,int bank,int program,int volume,int balance,int chorus, int reverb,int phaser,int tremolo,int[][] beat) { playBeat(channelId, bank, program, volume, balance, chorus, reverb, phaser, tremolo, beat,500,0); } public void playBeat(int channelId,int bank,int program,int volume,int balance,int chorus, int reverb,int phaser,int tremolo,int[][] beat,long duration,int interval) { try { updateChannels(); getOutputTransmitter().sendControlChange(channelId,MidiControllers.BANK_SELECT,bank); getOutputTransmitter().sendControlChange(channelId,MidiControllers.VOLUME,volume); getOutputTransmitter().sendControlChange(channelId,MidiControllers.BALANCE,balance); getOutputTransmitter().sendControlChange(channelId,MidiControllers.CHORUS,chorus); getOutputTransmitter().sendControlChange(channelId,MidiControllers.REVERB,reverb); getOutputTransmitter().sendControlChange(channelId,MidiControllers.PHASER,phaser); getOutputTransmitter().sendControlChange(channelId,MidiControllers.TREMOLO,tremolo); getOutputTransmitter().sendProgramChange(channelId,program); for(int i = 0; i < beat.length; i ++){ getOutputTransmitter().sendNoteOn(channelId,beat[i][0], beat[i][1], -1, false); if(interval > 0){ Thread.sleep(interval); } } Thread.sleep(duration); for(int i = 0; i < beat.length; i ++){ getOutputTransmitter().sendNoteOff(channelId,beat[i][0], beat[i][1], -1, false); } } catch (Throwable throwable) { throwable.printStackTrace(); } } public TGSongManager getSongManager(){ return this.songManager; } public MidiPlayerMode getMode(){ if(this.mode == null){ this.mode = new MidiPlayerMode(); } return this.mode; } public MidiPlayerCountDown getCountDown(){ if( this.countDown == null ){ this.countDown = new MidiPlayerCountDown(this); } return this.countDown; } public MidiTransmitter getOutputTransmitter(){ if (this.outputTransmitter == null) { this.outputTransmitter = new MidiTransmitter(); this.outputTransmitter.addReceiver(getChannelRouter().getId(), getChannelRouter()); } return this.outputTransmitter; } public MidiOutputPort getOutputPort(){ return this.outputPort; } public MidiChannelRouter getChannelRouter(){ if (this.channelRouter == null) { this.channelRouter = new MidiChannelRouter(); } return this.channelRouter; } public MidiSynthesizerProxy getSynthesizerProxy(){ if (this.synthesizerProxy == null) { this.synthesizerProxy = new MidiSynthesizerProxy(); } return this.synthesizerProxy; } public MidiSequencer getSequencer(){ if (this.sequencer == null) { this.sequencer = new MidiSequencerEmpty(); } return this.sequencer; } public int getPercussionChannelId(){ Iterator tgChannels = this.songManager.getSong().getChannels(); while( tgChannels.hasNext() ){ TGChannel tgChannel = (TGChannel) tgChannels.next(); if( tgChannel.isPercussionChannel() ){ return tgChannel.getChannelId(); } } return -1; } public boolean loadSequencer(MidiSequencer sequencer){ try{ this.closeSequencer(); this.sequencer = sequencer; this.sequencer.open(); this.sequencer.setTransmitter( getOutputTransmitter() ); }catch(Throwable throwable){ this.sequencer = null; return false; } return true; } public boolean loadOutputPort(MidiOutputPort port){ try{ this.closeOutputPort(); this.outputPort = port; this.outputPort.open(); this.getSynthesizerProxy().setMidiSynthesizer(this.outputPort.getSynthesizer()); }catch(Throwable throwable){ this.outputPort = null; return false; } return true; } public void openOutputPort(String key) { this.openOutputPort(key, false); } public void openOutputPort(String key, boolean tryFirst) { this.outputPortKey = key; this.openOutputPort(listOutputPorts(),tryFirst); } public void openOutputPort(List ports, boolean tryFirst) { try{ if(this.outputPortKey != null && !this.isOutputPortOpen(this.outputPortKey)){ this.closeOutputPort(); for(int i = 0; i < ports.size(); i ++){ MidiOutputPort port = (MidiOutputPort)ports.get(i); if(port.getKey().equals(this.outputPortKey)){ if(this.loadOutputPort(port)){ return; } } } } if(getOutputPort() == null && !ports.isEmpty() && tryFirst){ this.loadOutputPort( (MidiOutputPort)ports.get(0) ); } }catch(Throwable throwable){ throwable.printStackTrace(); } } public void openSequencer(String key) { this.openSequencer(key, false); } public void openSequencer(String key, boolean tryFirst) { try{ this.sequencerKey = key; this.openSequencer(listSequencers(),tryFirst); }catch(Throwable throwable){ throwable.printStackTrace(); } } public void openSequencer(List sequencers ,boolean tryFirst) throws MidiPlayerException { try{ if(this.sequencerKey != null && !this.isSequencerOpen(this.sequencerKey)){ this.closeSequencer(); for(int i = 0; i < sequencers.size(); i ++){ MidiSequencer sequencer = (MidiSequencer)sequencers.get(i); if(sequencer.getKey().equals(this.sequencerKey)){ if(this.loadSequencer(sequencer)){ return; } } } } if(getSequencer() instanceof MidiSequencerEmpty && !sequencers.isEmpty() && tryFirst){ this.loadSequencer( (MidiSequencer) sequencers.get(0)); } }catch(Throwable throwable){ throw new MidiPlayerException(throwable.getMessage(),throwable); } } public List listOutputPorts() { List ports = new ArrayList(); Iterator it = this.outputPortProviders.iterator(); while(it.hasNext()){ try{ MidiOutputPortProvider provider = (MidiOutputPortProvider)it.next(); ports.addAll(provider.listPorts()); }catch(Throwable throwable){ throwable.printStackTrace(); } } return ports; } public List listSequencers(){ List sequencers = new ArrayList(); Iterator it = this.sequencerProviders.iterator(); while(it.hasNext()){ try{ MidiSequencerProvider provider = (MidiSequencerProvider)it.next(); sequencers.addAll(provider.listSequencers()); }catch(Throwable throwable){ throwable.printStackTrace(); } } return sequencers; } public void closeSequencer() throws MidiPlayerException{ try{ if(this.isRunning()){ this.stop(); } this.lock.lock(); if (this.sequencer != null) { this.sequencer.close(); this.sequencer = null; } this.lock.unlock(); }catch(Throwable throwable){ throw new MidiPlayerException(throwable.getMessage(),throwable); } } public void closeOutputPort(){ try{ if(this.isRunning()){ this.stop(); } this.lock.lock(); if (this.outputPort != null) { this.closeChannels(); this.getSynthesizerProxy().setMidiSynthesizer(null); this.getOutputTransmitter().removeReceiver(this.outputPort.getKey()); this.outputPort.close(); this.outputPort = null; } this.lock.unlock(); }catch(Throwable throwable){ throwable.printStackTrace(); } } public boolean isSequencerOpen(String key){ if(key != null){ String currentKey = getSequencer().getKey(); if(currentKey == null){ return false; } return currentKey.equals(key); } return false; } public boolean isOutputPortOpen(String key){ if(key != null && getOutputPort() != null ){ String currentKey = getOutputPort().getKey(); if(currentKey == null){ return false; } return currentKey.equals(key); } return false; } public void addOutputPortProvider(MidiOutputPortProvider provider) throws MidiPlayerException { this.addOutputPortProvider(provider, this.isTryOpenFistDevice()); } public void addOutputPortProvider(MidiOutputPortProvider provider, boolean tryFirst) throws MidiPlayerException { this.outputPortProviders.add(provider); this.openOutputPort(provider.listPorts(),tryFirst); } public void addSequencerProvider(MidiSequencerProvider provider) throws MidiPlayerException { this.addSequencerProvider(provider, this.isTryOpenFistDevice()); } public void addSequencerProvider(MidiSequencerProvider provider, boolean tryFirst) throws MidiPlayerException { this.sequencerProviders.add(provider); this.openSequencer(provider.listSequencers(), tryFirst); } public void removeOutputPortProvider(MidiOutputPortProvider provider) throws MidiPlayerException { this.outputPortProviders.remove(provider); MidiOutputPort current = getOutputPort(); if( current != null ){ Iterator it = provider.listPorts().iterator(); while(it.hasNext()){ MidiOutputPort port = (MidiOutputPort)it.next(); if(port.getKey().equals(current.getKey())){ closeOutputPort(); break; } } } } public void removeSequencerProvider(MidiSequencerProvider provider) throws MidiPlayerException { this.sequencerProviders.remove(provider); MidiSequencer current = getSequencer(); if(!(current instanceof MidiSequencerEmpty) && current != null){ Iterator it = provider.listSequencers().iterator(); while(it.hasNext()){ MidiSequencer sequencer = (MidiSequencer)it.next(); if(current.getKey().equals(sequencer.getKey())){ closeSequencer(); break; } } } } public void addListener( MidiPlayerListener listener ){ if( !this.listeners.contains( listener ) ){ this.listeners.add( listener ); } } public void removeListener( MidiPlayerListener listener ){ if( this.listeners.contains( listener ) ){ this.listeners.remove( listener ); } } public void notifyStarted(){ Iterator it = this.listeners.iterator(); while( it.hasNext() ){ MidiPlayerListener listener = (MidiPlayerListener) it.next(); listener.notifyStarted(); } } public void notifyStopped(){ Iterator it = this.listeners.iterator(); while( it.hasNext() ){ MidiPlayerListener listener = (MidiPlayerListener) it.next(); listener.notifyStopped(); } } public void notifyCountDownStarted(){ Iterator it = this.listeners.iterator(); while( it.hasNext() ){ MidiPlayerListener listener = (MidiPlayerListener) it.next(); listener.notifyCountDownStarted(); } } public void notifyCountDownStopped(){ Iterator it = this.listeners.iterator(); while( it.hasNext() ){ MidiPlayerListener listener = (MidiPlayerListener) it.next(); listener.notifyCountDownStopped(); } } public void notifyLoop(){ Iterator it = this.listeners.iterator(); while( it.hasNext() ){ MidiPlayerListener listener = (MidiPlayerListener) it.next(); listener.notifyLoop(); } } }