package org.herac.tuxguitar.jack.sequencer; import org.apache.log4j.Logger; import org.herac.tuxguitar.gui.TuxGuitar; import org.herac.tuxguitar.gui.editors.chord.ChordSelector; import org.herac.tuxguitar.jack.JackClient; import org.herac.tuxguitar.player.base.MidiPlayerException; import org.herac.tuxguitar.player.base.MidiSequenceHandler; import org.herac.tuxguitar.player.base.MidiSequencer; import org.herac.tuxguitar.player.base.MidiTransmitter; public class JackSequencer implements MidiSequencer { /** The Logger for this class. */ public static final transient Logger LOG = Logger .getLogger(JackSequencer.class); private class JackTimer implements Runnable { private static final int TIMER_DELAY = 10; private boolean running; private JackSequencer sequencer; private Object sequencerSync; public JackTimer(JackSequencer sequencer) { this.sequencerSync = new Object(); this.sequencer = sequencer; this.running = false; } public void run() { try { synchronized (this.sequencerSync) { while (this.running) { this.sequencer.process(); this.sequencerSync.wait(TIMER_DELAY); } } } catch (Throwable throwable) { LOG.error(throwable); } } public void setRunning(boolean running) { this.running = running; if (this.running) { new Thread(this).start(); } } } private JackClient jackClient; private JackEventController jackEventController; private JackEventDispacher jackEventDispacher; private JackTickController jackTickController; private JackTimer jackTimer; private JackTrackController jackTrackController; private boolean reset; private boolean running; private boolean stopped; private MidiTransmitter transmitter; private boolean transportLockTick; private boolean transportRunning; private long transportTryCount; private long transportTryNumber; private long transportUID; public JackSequencer(JackClient jackClient) { this.stopped = true; this.running = false; this.transportRunning = false; this.transportUID = -1; this.transportTryCount = 10; this.transportTryNumber = 0; this.jackClient = jackClient; this.jackTickController = new JackTickController(this); this.jackEventController = new JackEventController(this); this.jackEventDispacher = new JackEventDispacher(this); this.jackTrackController = new JackTrackController(this); this.jackTimer = new JackTimer(this); } public void addEvent(JackEvent event) { this.jackEventController.addEvent(event); this.jackTickController.notifyTick(event.getTick()); } public void check() throws MidiPlayerException { if (!this.jackClient.isServerRunning() || !this.jackClient.isTransportOpen()) { this.open(); if (!this.jackClient.isServerRunning() || !this.jackClient.isTransportOpen()) { throw new MidiPlayerException("Jack server not running?"); } } } public void close() throws MidiPlayerException { this.jackTimer.setRunning(false); if (this.isRunning()) { this.stop(); } if (this.jackClient.isTransportOpen()) { this.jackClient.closeTransport(); } } public MidiSequenceHandler createSequence(int tracks) throws MidiPlayerException { return new JackSequenceHandler(this, tracks); } public JackClient getJackClient() { return this.jackClient; } public JackEventController getJackEventController() { return this.jackEventController; } public JackTickController getJackTickController() { return this.jackTickController; } public JackTrackController getJackTrackController() { return this.jackTrackController; } public String getKey() { return "tuxguitar-jack"; } public String getName() { return "Jack Sequencer"; } public long getTickLength() { return this.jackTickController.getTickLength(); } public long getTickPosition() { return Math.round(this.jackTickController.getTick()); } public MidiTransmitter getTransmitter() { return this.transmitter; } public boolean isRunning() { return this.running; } public void open() { if (!this.jackClient.isTransportOpen()) { this.jackClient.openTransport(); } this.jackTimer.setRunning(true); } protected void process() throws MidiPlayerException { boolean transportRunning = this.jackClient.isTransportRunning(); // Check if state was changed if (this.transportRunning != transportRunning) { if (transportRunning && !this.running) { // Transport was started this.startPlayer(); } else if (!transportRunning) { // Transport was stopped. this.running = false; } } else { if (this.running && transportRunning) { long transportUID = this.jackClient.getTransportUID(); if (this.transportUID != transportUID) { this.setTickPosition(0, false); } if (this.reset) { this.reset(false); this.reset = false; this.jackEventController.reset(); } this.stopped = false; this.jackTickController.process(); this.jackEventController.process(); if (this.getTickPosition() > this.getTickLength()) { this.stop(true); } this.transportUID = transportUID; } else if (!this.stopped) { this.stopped = true; this.jackEventController.clearEvents(); this.jackTickController.clearTick(); this.reset(true); } else if (this.running) { if (this.transportTryNumber++ > this.transportTryCount) { this.running = false; this.transportTryNumber = 0; } } } this.transportRunning = transportRunning; } public void reset(boolean systemReset) throws MidiPlayerException { this.getTransmitter().sendAllNotesOff(); for (int channel = 0; channel < 16; channel++) { this.getTransmitter().sendPitchBend(channel, 64); } if (systemReset) { this.getTransmitter().sendSystemReset(); } } public void sendEvent(JackEvent event) throws MidiPlayerException { if (!this.reset) { this.jackEventDispacher.dispatch(event); } } public void setMute(int index, boolean mute) throws MidiPlayerException { this.getJackTrackController().setMute(index, mute); } public void setSolo(int index, boolean solo) throws MidiPlayerException { this.getJackTrackController().setSolo(index, solo); } public void setTempo(int tempo) { this.jackTickController.setTempo(tempo); } public void setTickPosition(long tickPosition) { this.setTickPosition(tickPosition, !this.transportLockTick); this.transportLockTick = false; } public void setTickPosition(long tickPosition, boolean transportUpdate) { this.reset = true; this.jackTickController.setTick(tickPosition, transportUpdate); } public void setTransmitter(MidiTransmitter transmitter) { this.transmitter = transmitter; } public void start() throws MidiPlayerException { this.start(true); } public void start(boolean startTransport) throws MidiPlayerException { if (!this.running) { this.setTempo(120); this.running = true; if (startTransport) { this.jackClient.setTransportStart(); } } } protected void startPlayer() { // Make sure sequencer was already initialized. if (this.transmitter != null) { this.transportLockTick = true; TuxGuitar.instance().getTransport().play(); } } public void stop() throws MidiPlayerException { this.stop(true); } public void stop(boolean stopTransport) throws MidiPlayerException { if (this.running) { this.running = false; if (stopTransport) { this.jackClient.setTransportStop(); } } } }