/*
* JFugue, an Application Programming Interface (API) for Music Programming
* http://www.jfugue.org
*
* Copyright (C) 2003-2014 David Koelle
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jfugue.midi;
import java.util.HashMap;
import java.util.Map;
import org.jfugue.realtime.RealtimeMidiParserListener;
/**
* This class is useful for any applications that plan on keeping track of
* musical events by beat time. It automatically provides beat time, manages
* the current track, and maintains beat time bookmarks. And, this class is
* agnostic to units of time. It is used within JFugue for both track beats
* (as in MidiParserListener) and milliseconds (as in RealtimeMidiParserListener)
*
* @see MidiParserListener
* @see RealtimeMidiParserListener
*
* @author David Koelle
*/
public class TrackTimeManager
{
private double[][] beatTime;
private byte currentTrack;
private byte lastCreatedTrack;
private byte[] currentLayer;
private double initialNoteBeatTimeForHarmonicNotes;
private Map<String, Double> bookmarkedTrackTimeMap;
public TrackTimeManager() {
beatTime = new double[MidiDefaults.TRACKS][MidiDefaults.LAYERS];
currentTrack = 0;
lastCreatedTrack = 0;
currentLayer = new byte[MidiDefaults.TRACKS];
initialNoteBeatTimeForHarmonicNotes = 0.0d;
bookmarkedTrackTimeMap = new HashMap<String, Double>();
}
/**
* Sets the current track, or channel, to which new events will be added.
* @param track the track to select
*/
public void setCurrentTrack(byte track) {
if (track > this.lastCreatedTrack) {
for (int i = this.lastCreatedTrack+1; i < track; i++) {
createTrack((byte)i);
}
this.lastCreatedTrack = track;
}
this.currentTrack = track;
}
public byte getCurrentTrack() {
return this.currentTrack;
}
protected byte getLastCreatedTrack() {
return this.lastCreatedTrack;
}
protected void createTrack(byte track) {
for (byte layer = 0; layer < MidiDefaults.LAYERS; layer++) {
beatTime[track][layer] = 0;
}
currentLayer[track] = 0;
}
/**
* Sets the current layer within the track to which new events will be added.
* @param layer the layer to select
*/
public void setCurrentLayer(byte layer) {
currentLayer[currentTrack] = layer;
}
protected byte getCurrentLayer() {
return this.currentLayer[getCurrentTrack()];
}
public void setInitialNoteBeatTimeForHarmonicNotes(double initialNoteBeatTimeForHarmonicNotes) {
this.initialNoteBeatTimeForHarmonicNotes = initialNoteBeatTimeForHarmonicNotes;
}
public double getInitialNoteBeatTimeForHarmonicNotes() {
return this.initialNoteBeatTimeForHarmonicNotes;
}
/**
* Advances the timer for the current track by the specified duration,
* which is specified in Pulses Per Quarter (PPQ)
* @param duration the duration to increase the track timer
*/
public void advanceTrackBeatTime(double advanceTime) {
beatTime[currentTrack][currentLayer[currentTrack]] += advanceTime;
}
/**
* Sets the timer for the current track by the given time,
* which is specified in Pulses Per Quarter (PPQ)
* @param newTickTime the time at which to set the track timer
*/
public void setTrackBeatTime(double newTime) {
beatTime[currentTrack][currentLayer[currentTrack]] = newTime;
}
/**
* Sets the timer for all tracks to the given time,
* which is specified in Pulses Per Quarter (PPQ)
* @param newTickTime the time at which to set the track timer
*/
public void setAllTrackBeatTime(double newTime) {
for (int track=0; track < MidiDefaults.TRACKS; track++) {
for (int layer=0; layer < MidiDefaults.LAYERS; layer++) {
if (beatTime[track][layer] < newTime) {
beatTime[track][layer] = newTime;
};
}
}
}
/**
* Returns the timer for the current track and current layer.
* @return the timer value for the current track, specified in Pulses Per Quarter (PPQ)
*/
public double getTrackBeatTime() {
return beatTime[currentTrack][currentLayer[currentTrack]];
}
public void addTrackTickTimeBookmark(String timeBookmarkID) {
bookmarkedTrackTimeMap.put(timeBookmarkID, getTrackBeatTime());
}
public double getTrackBeatTimeBookmark(String timeBookmarkID) {
return bookmarkedTrackTimeMap.get(timeBookmarkID);
}
/**
* Returns the latest track time across all layers in the given track
* @param track
*/
public double getLatestTrackBeatTime(byte track) {
double latestTime = 0.0D;
for (byte i=0; i < MidiDefaults.LAYERS; i++) {
if (beatTime[track][i] > latestTime) {
latestTime = beatTime[track][i];
}
}
return latestTime;
}
}