/*
* 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.temporal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.jfugue.midi.MidiDefaults;
/**
* Places musical data into the MIDI sequence.
* Package scope, final class.
*
*@author David Koelle
*/
final class TemporalEventManager
{
private Map<Long, List<TemporalEvent>> timeToEventMap = new TreeMap<Long, List<TemporalEvent>>();
private int tempoBeatsPerMinute = MidiDefaults.DEFAULT_TEMPO_BEATS_PER_MINUTE;
private int beatsPerWhole = MidiDefaults.DEFAULT_TEMPO_BEATS_PER_WHOLE;
private byte currentTrack = 0;
private byte[] currentLayer = new byte[MidiDefaults.TRACKS];
private double beatTime[][] = new double[MidiDefaults.TRACKS][MidiDefaults.LAYERS];
private Map<String, Double> bookmarkedTrackTimeMap;
public TemporalEventManager() { }
public void reset() {
this.bookmarkedTrackTimeMap = new HashMap<String, Double>();
this.tempoBeatsPerMinute = MidiDefaults.DEFAULT_TEMPO_BEATS_PER_MINUTE;
this.currentTrack = 0;
for (int i=0; i < MidiDefaults.TRACKS; i++) {
this.currentLayer[i] = 0;
}
this.timeToEventMap.clear();
}
public void finish() { }
public void setTempo(int tempoBPM) {
this.tempoBeatsPerMinute = tempoBPM;
}
/**
* Sets the current track to which new events will be added.
* @param layer the track to select
*/
public void setCurrentTrack(byte track) {
currentTrack = track;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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);
}
public void addRealTimeEvent(DurationTemporalEvent event) {
addRealTimeEvent((TemporalEvent)event);
advanceTrackBeatTime(event.getDuration());
}
public void addRealTimeEvent(TemporalEvent event) {
List<TemporalEvent> eventList = timeToEventMap.get(convertBeatsToMillis(getTrackBeatTime()));
if (eventList == null) {
eventList = new ArrayList<TemporalEvent>();
timeToEventMap.put(convertBeatsToMillis(getTrackBeatTime()), eventList);
}
eventList.add(event);
}
public Map<Long, List<TemporalEvent>> getTimeToEventMap() {
return this.timeToEventMap;
}
private long convertBeatsToMillis(double beats) {
return (long)((beats * beatsPerWhole * 60000.0D) / tempoBeatsPerMinute);
}
}