com.frinika.sequencer
Class FrinikaSequencer

java.lang.Object
  extended by com.frinika.sequencer.FrinikaSequencer
All Implemented Interfaces:
javax.sound.midi.MidiDevice, javax.sound.midi.Sequencer

public class FrinikaSequencer
extends java.lang.Object
implements javax.sound.midi.Sequencer

The purpose of the Frinika sequencer implementation is to solve the following issues of the current implementation in Sun J2SE5.0: - Smooth looping - Don't skip notes / events on the first tick when starting to play - Able to insert / remove events from the sequence while playing (not same as recording) - Better abilities for song position monitoring NOTE: The Frinika sequencer is not a complete implementation of the Java sequencer. Its primary goals is to solve the needs of Frinika, and the implementation subset is thereafter. To be able to insert and remove events while playing the sequence has to be reorganized from a vector, to a hashtable structure. In the default sequencer pointers to the next midi event to be played is based on the vector index. When inserting or removing notes before the current index the sequencer pointer will break. By using a hashtable with keyword tick and value set to an array of events occuring at that tick, one is able to lookup notes to be played for a given tick position - thus not vulnerable to changes in the ordering of events. The skipping of notes on the start tick, is caused by a bug in the binary search routine of the default sequencer. This binary search is searching for the first event to play after the given starttick. By using the mentioned hashtable above, this is not an issue anymore. Issues with smooth looping is suspected though not verified, to be caused by chasing of controller values when resetting the loop. The symptom is that the longer out in the song you are, the loop gap is longer and longer.

Author:
Peter Johan Salomonsen TODO PJL repair notification for recording.

Nested Class Summary
 
Nested classes/interfaces inherited from interface javax.sound.midi.Sequencer
javax.sound.midi.Sequencer.SyncMode
 
Nested classes/interfaces inherited from interface javax.sound.midi.MidiDevice
javax.sound.midi.MidiDevice.Info
 
Field Summary
 
Fields inherited from interface javax.sound.midi.Sequencer
LOOP_CONTINUOUSLY
 
Constructor Summary
FrinikaSequencer()
           
 
Method Summary
 int[] addControllerEventListener(javax.sound.midi.ControllerEventListener listener, int[] controllers)
           
 boolean addMetaEventListener(javax.sound.midi.MetaEventListener listener)
           
 void addMidiMessageListener(MidiMessageListener l)
           
 void addMidiOutDevice(javax.sound.midi.MidiDevice midiDevice)
          Register a MidiOutDevice to this sequencer.
 void addSequencerListener(SequencerListener sequencerListener)
           
 void addSongPositionListener(SongPositionListener songPositionListener)
          Add a song position listener to the sequencer.
 void addTempoChangeListener(TempoChangeListener listener)
          Add a tempo change listener to the sequencer.
 void close()
           
 void deployTake(int[] takeNumbers)
          Deploy one of the takes from the last recording to recording lanes
 javax.sound.midi.MidiDevice.Info getDeviceInfo()
           
 int getLoopCount()
           
 long getLoopEndPoint()
           
 long getLoopStartPoint()
           
 javax.sound.midi.Sequencer.SyncMode getMasterSyncMode()
           
 javax.sound.midi.Sequencer.SyncMode[] getMasterSyncModes()
           
 int getMaxReceivers()
           
 int getMaxTransmitters()
           
 long getMicrosecondLength()
           
 long getMicrosecondPosition()
           
 java.util.Collection<MidiMessageListener> getMidiMessageListeners()
           
 int getNumberOfTakes()
          Get number of takes from the last recording
 MidiPlayOptions getPlayOptions(FrinikaTrackWrapper track)
           
 boolean getRealtime()
          Returns whether to play in realtime or if rendering (e.g.
 long getRealTimeTickPosition()
          PJL added for Recording Manager
 javax.sound.midi.Receiver getReceiver()
           
 java.util.List<javax.sound.midi.Receiver> getReceivers()
           
 java.util.Vector<MultiEvent> getRecordingTake(int takeNo)
          Return the MultiEvents of a recording take
 javax.sound.midi.Sequence getSequence()
           
 javax.sound.midi.Sequencer.SyncMode getSlaveSyncMode()
           
 javax.sound.midi.Sequencer.SyncMode[] getSlaveSyncModes()
           
 java.util.Collection<FrinikaTrackWrapper> getSoloFrinikaTrackWrappers()
           
 float getTempoFactor()
           
 float getTempoInBPM()
           
 float getTempoInMPQ()
           
 long getTickLength()
           
 long getTickPosition()
           
 long getTicksLooped()
           
 boolean getTrackMute(int track)
           
 boolean getTrackSolo(int track)
           
 javax.sound.midi.Transmitter getTransmitter()
           
 java.util.List<javax.sound.midi.Transmitter> getTransmitters()
           
 boolean isOpen()
           
 boolean isRecording()
           
 boolean isRecording(RecordableLane lane)
           
 boolean isRunning()
           
 boolean isSolo(RecordableLane lane)
           
 java.util.List<javax.sound.midi.MidiDevice> listMidiOutDevices()
           
 void nonRealtimeNextTick()
          If the player is not in realtime mode you can manually trigger the next tick here
 void notifySongPositionListeners()
           
 void open()
           
 void panic()
          Send noteOff and reset all controllers to zero
 void recordDisable(RecordableLane lane)
           
 void recordDisable(javax.sound.midi.Track track)
          Deprecated. Use recordEnable on MidiLane instead
 void recordEnable(RecordableLane lane)
           
 void recordEnable(javax.sound.midi.Track track, int channel)
          Deprecated. Use recordEnable on MidiLane instead
 int[] removeControllerEventListener(javax.sound.midi.ControllerEventListener listener, int[] controllers)
           
 void removeMetaEventListener(javax.sound.midi.MetaEventListener listener)
           
 void removeMidiMessageListener(MidiMessageListener l)
           
 void removeMidiOutDevice(javax.sound.midi.MidiDevice midiDevice)
          Deregister a midi out device from this sequencer.
 void removeSequencerListener(SequencerListener sequencerListener)
           
 void removeSongPositionListener(SongPositionListener songPositionListener)
          Remove a song position listener from the sequencer
 void removeTempoChangeListener(TempoChangeListener listener)
          Remove a tempo change position listener from the sequencer
 void sendMidiMessage(javax.sound.midi.MidiMessage msg, FrinikaTrackWrapper trackWrapper)
          Manually send a midi message using the channel/device settings of a FrinikaTrackWrapper This is also used by wavexport
 void setLoopCount(int count)
           
 void setLoopEndPoint(long tick)
           
 void setLoopEndPointInBeats(double d)
           
 void setLoopStartPoint(long tick)
           
 void setLoopStartPointInBeats(double d)
           
 void setMasterSyncMode(javax.sound.midi.Sequencer.SyncMode sync)
           
 void setMicrosecondPosition(long microseconds)
           
 void setPlayerPriority(int prio)
          set priority of the player
 void setPlayOptions(FrinikaTrackWrapper track, MidiPlayOptions opt)
           
 void setRealtime(boolean realtime)
          Set whether to play in realtime or if rendering (e.g.
 void setRecordingTakeDialog(RecordingDialog dialog)
           
 void setSequence(java.io.InputStream stream)
           
 void setSequence(javax.sound.midi.Sequence sequence)
           
 void setSlaveSyncMode(javax.sound.midi.Sequencer.SyncMode sync)
           
 void setSolo(MidiLane lane, boolean solo)
           
 void setTempoFactor(float factor)
           
 void setTempoInBPM(float bpm)
           
 void setTempoInMPQ(float mpq)
           
 void setTempoList(TempoList tl)
          set the tempolist
 void setTickPosition(long tick)
           
 void setTrackMute(int track, boolean mute)
           
 void setTrackSolo(int track, boolean solo)
           
 void start()
           
 void startRecording()
           
 void stop()
           
 void stopRecording()
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

FrinikaSequencer

public FrinikaSequencer()
Method Detail

getRealTimeTickPosition

public long getRealTimeTickPosition()
PJL added for Recording Manager

Returns:

setLoopEndPointInBeats

public void setLoopEndPointInBeats(double d)

setLoopStartPointInBeats

public void setLoopStartPointInBeats(double d)

setSequence

public void setSequence(javax.sound.midi.Sequence sequence)
                 throws javax.sound.midi.InvalidMidiDataException
Specified by:
setSequence in interface javax.sound.midi.Sequencer
Throws:
javax.sound.midi.InvalidMidiDataException

setSequence

public void setSequence(java.io.InputStream stream)
                 throws java.io.IOException,
                        javax.sound.midi.InvalidMidiDataException
Specified by:
setSequence in interface javax.sound.midi.Sequencer
Throws:
java.io.IOException
javax.sound.midi.InvalidMidiDataException

getSequence

public javax.sound.midi.Sequence getSequence()
Specified by:
getSequence in interface javax.sound.midi.Sequencer

start

public void start()
Specified by:
start in interface javax.sound.midi.Sequencer

stop

public void stop()
Specified by:
stop in interface javax.sound.midi.Sequencer

isRunning

public boolean isRunning()
Specified by:
isRunning in interface javax.sound.midi.Sequencer

getNumberOfTakes

public int getNumberOfTakes()
Get number of takes from the last recording

Returns:

deployTake

public void deployTake(int[] takeNumbers)
Deploy one of the takes from the last recording to recording lanes

Parameters:
takeNo - - the take to deploy

getRecordingTake

public java.util.Vector<MultiEvent> getRecordingTake(int takeNo)
Return the MultiEvents of a recording take

Parameters:
takeNo -
Returns:

startRecording

public void startRecording()
Specified by:
startRecording in interface javax.sound.midi.Sequencer

stopRecording

public void stopRecording()
Specified by:
stopRecording in interface javax.sound.midi.Sequencer

isRecording

public boolean isRecording()
Specified by:
isRecording in interface javax.sound.midi.Sequencer

recordEnable

public void recordEnable(javax.sound.midi.Track track,
                         int channel)
Deprecated. Use recordEnable on MidiLane instead

Specified by:
recordEnable in interface javax.sound.midi.Sequencer

recordEnable

public void recordEnable(RecordableLane lane)

recordDisable

public void recordDisable(javax.sound.midi.Track track)
Deprecated. Use recordEnable on MidiLane instead

Specified by:
recordDisable in interface javax.sound.midi.Sequencer

isRecording

public boolean isRecording(RecordableLane lane)

recordDisable

public void recordDisable(RecordableLane lane)

getTempoInBPM

public float getTempoInBPM()
Specified by:
getTempoInBPM in interface javax.sound.midi.Sequencer

setTempoInBPM

public void setTempoInBPM(float bpm)
Specified by:
setTempoInBPM in interface javax.sound.midi.Sequencer

getTempoInMPQ

public float getTempoInMPQ()
Specified by:
getTempoInMPQ in interface javax.sound.midi.Sequencer

setTempoInMPQ

public void setTempoInMPQ(float mpq)
Specified by:
setTempoInMPQ in interface javax.sound.midi.Sequencer

setTempoFactor

public void setTempoFactor(float factor)
Specified by:
setTempoFactor in interface javax.sound.midi.Sequencer

getTempoFactor

public float getTempoFactor()
Specified by:
getTempoFactor in interface javax.sound.midi.Sequencer

getTickLength

public long getTickLength()
Specified by:
getTickLength in interface javax.sound.midi.Sequencer

getTicksLooped

public long getTicksLooped()

getTickPosition

public long getTickPosition()
Specified by:
getTickPosition in interface javax.sound.midi.Sequencer

setTickPosition

public void setTickPosition(long tick)
Specified by:
setTickPosition in interface javax.sound.midi.Sequencer

getMicrosecondLength

public long getMicrosecondLength()
Specified by:
getMicrosecondLength in interface javax.sound.midi.Sequencer

getMicrosecondPosition

public long getMicrosecondPosition()
Specified by:
getMicrosecondPosition in interface javax.sound.midi.MidiDevice
Specified by:
getMicrosecondPosition in interface javax.sound.midi.Sequencer

setMicrosecondPosition

public void setMicrosecondPosition(long microseconds)
Specified by:
setMicrosecondPosition in interface javax.sound.midi.Sequencer

setMasterSyncMode

public void setMasterSyncMode(javax.sound.midi.Sequencer.SyncMode sync)
Specified by:
setMasterSyncMode in interface javax.sound.midi.Sequencer

getMasterSyncMode

public javax.sound.midi.Sequencer.SyncMode getMasterSyncMode()
Specified by:
getMasterSyncMode in interface javax.sound.midi.Sequencer

getMasterSyncModes

public javax.sound.midi.Sequencer.SyncMode[] getMasterSyncModes()
Specified by:
getMasterSyncModes in interface javax.sound.midi.Sequencer

setSlaveSyncMode

public void setSlaveSyncMode(javax.sound.midi.Sequencer.SyncMode sync)
Specified by:
setSlaveSyncMode in interface javax.sound.midi.Sequencer

getSlaveSyncMode

public javax.sound.midi.Sequencer.SyncMode getSlaveSyncMode()
Specified by:
getSlaveSyncMode in interface javax.sound.midi.Sequencer

getSlaveSyncModes

public javax.sound.midi.Sequencer.SyncMode[] getSlaveSyncModes()
Specified by:
getSlaveSyncModes in interface javax.sound.midi.Sequencer

setTrackMute

public void setTrackMute(int track,
                         boolean mute)
Specified by:
setTrackMute in interface javax.sound.midi.Sequencer

getTrackMute

public boolean getTrackMute(int track)
Specified by:
getTrackMute in interface javax.sound.midi.Sequencer

setTrackSolo

public void setTrackSolo(int track,
                         boolean solo)
Specified by:
setTrackSolo in interface javax.sound.midi.Sequencer

getTrackSolo

public boolean getTrackSolo(int track)
Specified by:
getTrackSolo in interface javax.sound.midi.Sequencer

addMetaEventListener

public boolean addMetaEventListener(javax.sound.midi.MetaEventListener listener)
Specified by:
addMetaEventListener in interface javax.sound.midi.Sequencer

removeMetaEventListener

public void removeMetaEventListener(javax.sound.midi.MetaEventListener listener)
Specified by:
removeMetaEventListener in interface javax.sound.midi.Sequencer

addControllerEventListener

public int[] addControllerEventListener(javax.sound.midi.ControllerEventListener listener,
                                        int[] controllers)
Specified by:
addControllerEventListener in interface javax.sound.midi.Sequencer

removeControllerEventListener

public int[] removeControllerEventListener(javax.sound.midi.ControllerEventListener listener,
                                           int[] controllers)
Specified by:
removeControllerEventListener in interface javax.sound.midi.Sequencer

setLoopStartPoint

public void setLoopStartPoint(long tick)
Specified by:
setLoopStartPoint in interface javax.sound.midi.Sequencer

getLoopStartPoint

public long getLoopStartPoint()
Specified by:
getLoopStartPoint in interface javax.sound.midi.Sequencer

setLoopEndPoint

public void setLoopEndPoint(long tick)
Specified by:
setLoopEndPoint in interface javax.sound.midi.Sequencer

getLoopEndPoint

public long getLoopEndPoint()
Specified by:
getLoopEndPoint in interface javax.sound.midi.Sequencer

setLoopCount

public void setLoopCount(int count)
Specified by:
setLoopCount in interface javax.sound.midi.Sequencer

getLoopCount

public int getLoopCount()
Specified by:
getLoopCount in interface javax.sound.midi.Sequencer

getDeviceInfo

public javax.sound.midi.MidiDevice.Info getDeviceInfo()
Specified by:
getDeviceInfo in interface javax.sound.midi.MidiDevice

open

public void open()
          throws javax.sound.midi.MidiUnavailableException
Specified by:
open in interface javax.sound.midi.MidiDevice
Throws:
javax.sound.midi.MidiUnavailableException

close

public void close()
Specified by:
close in interface javax.sound.midi.MidiDevice

isOpen

public boolean isOpen()
Specified by:
isOpen in interface javax.sound.midi.MidiDevice

getMaxReceivers

public int getMaxReceivers()
Specified by:
getMaxReceivers in interface javax.sound.midi.MidiDevice

getMaxTransmitters

public int getMaxTransmitters()
Specified by:
getMaxTransmitters in interface javax.sound.midi.MidiDevice

getReceiver

public javax.sound.midi.Receiver getReceiver()
                                      throws javax.sound.midi.MidiUnavailableException
Specified by:
getReceiver in interface javax.sound.midi.MidiDevice
Throws:
javax.sound.midi.MidiUnavailableException

getReceivers

public java.util.List<javax.sound.midi.Receiver> getReceivers()
Specified by:
getReceivers in interface javax.sound.midi.MidiDevice

getTransmitter

public javax.sound.midi.Transmitter getTransmitter()
                                            throws javax.sound.midi.MidiUnavailableException
Specified by:
getTransmitter in interface javax.sound.midi.MidiDevice
Throws:
javax.sound.midi.MidiUnavailableException

getTransmitters

public java.util.List<javax.sound.midi.Transmitter> getTransmitters()
Specified by:
getTransmitters in interface javax.sound.midi.MidiDevice

addMidiOutDevice

public void addMidiOutDevice(javax.sound.midi.MidiDevice midiDevice)
                      throws javax.sound.midi.MidiUnavailableException
Register a MidiOutDevice to this sequencer. It's also added to the list of transmitters.

Parameters:
midiDevice -
Throws:
javax.sound.midi.MidiUnavailableException

removeMidiOutDevice

public void removeMidiOutDevice(javax.sound.midi.MidiDevice midiDevice)
Deregister a midi out device from this sequencer. Also removed from the list of transmitters

Parameters:
midiDevice -

listMidiOutDevices

public java.util.List<javax.sound.midi.MidiDevice> listMidiOutDevices()

addSequencerListener

public void addSequencerListener(SequencerListener sequencerListener)

removeSequencerListener

public void removeSequencerListener(SequencerListener sequencerListener)

addSongPositionListener

public void addSongPositionListener(SongPositionListener songPositionListener)
Add a song position listener to the sequencer. See the SongPositionListener javadoc.

Parameters:
songPositionListener -

removeSongPositionListener

public void removeSongPositionListener(SongPositionListener songPositionListener)
Remove a song position listener from the sequencer

Parameters:
songPositionListener -

notifySongPositionListeners

public final void notifySongPositionListeners()

addTempoChangeListener

public void addTempoChangeListener(TempoChangeListener listener)
Add a tempo change listener to the sequencer. This is notified when we play a tempo change event.

Parameters:
listener -

removeTempoChangeListener

public void removeTempoChangeListener(TempoChangeListener listener)
Remove a tempo change position listener from the sequencer

Parameters:
listener -

getSoloFrinikaTrackWrappers

public java.util.Collection<FrinikaTrackWrapper> getSoloFrinikaTrackWrappers()

setSolo

public void setSolo(MidiLane lane,
                    boolean solo)

setRecordingTakeDialog

public void setRecordingTakeDialog(RecordingDialog dialog)

panic

public void panic()
Send noteOff and reset all controllers to zero


isSolo

public boolean isSolo(RecordableLane lane)

getPlayOptions

public MidiPlayOptions getPlayOptions(FrinikaTrackWrapper track)

setPlayOptions

public void setPlayOptions(FrinikaTrackWrapper track,
                           MidiPlayOptions opt)

addMidiMessageListener

public void addMidiMessageListener(MidiMessageListener l)

removeMidiMessageListener

public void removeMidiMessageListener(MidiMessageListener l)

sendMidiMessage

public void sendMidiMessage(javax.sound.midi.MidiMessage msg,
                            FrinikaTrackWrapper trackWrapper)
                     throws javax.sound.midi.InvalidMidiDataException,
                            javax.sound.midi.MidiUnavailableException
Manually send a midi message using the channel/device settings of a FrinikaTrackWrapper This is also used by wavexport

Parameters:
msg -
trackWrapper -
Throws:
javax.sound.midi.InvalidMidiDataException
javax.sound.midi.MidiUnavailableException

setRealtime

public void setRealtime(boolean realtime)
Set whether to play in realtime or if rendering (e.g. export wav)

Parameters:
realtime -

getRealtime

public boolean getRealtime()
Returns whether to play in realtime or if rendering (e.g. export wav)


nonRealtimeNextTick

public void nonRealtimeNextTick()
If the player is not in realtime mode you can manually trigger the next tick here


setTempoList

public void setTempoList(TempoList tl)
set the tempolist

Parameters:
tl -

setPlayerPriority

public void setPlayerPriority(int prio)
set priority of the player


getMidiMessageListeners

public java.util.Collection<MidiMessageListener> getMidiMessageListeners()