package com.xenoage.zong.io.midi.out.time; import com.xenoage.utils.annotations.Const; import com.xenoage.utils.collections.IList; import com.xenoage.zong.core.position.Time; import com.xenoage.zong.io.midi.out.repetitions.Repetition; import lombok.AccessLevel; import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; import lombok.val; import static com.xenoage.utils.kernel.Range.range; /** * Constant-time lookup of {@link MidiTime}s by providing one of * its components (MIDI tick, repetition index and time, or MIDI millisecond). * * @author Andreas Wenger */ @Const @RequiredArgsConstructor(access = AccessLevel.PACKAGE) @EqualsAndHashCode public class TimeMap { /** The {@link RepTime}s for each repetition. */ private final IList<RepTimes> repTimes; /** * Gets the number of {@link Repetition}s. */ public int getRepetitionsCount() { return repTimes.size(); } /** * Returns the {@link MidiTime} at the given MIDI tick, or null. */ public MidiTime getByTick(long tick) { for (val repTime : repTimes) if (repTime.containsTick(tick)) return repTime.getByTick(tick); return null; } /** * Returns the {@link MidiTime} at the given {@link RepTime}, or null. */ public MidiTime getByRepTime(RepTime repTime) { return getByRepTime(repTime.repetition, repTime.time); } /** * Returns the {@link MidiTime} at the given repetition index and {@link Time}, or null. */ public MidiTime getByRepTime(int repetition, Time time) { val repTime = repTimes.get(repetition); if (repTime.containsTime(time)) return repTime.getByTime(time); return null; } /** * Returns the {@link MidiTime} at the given {@link Time}, or null. * The first repetition using this time is returned. */ public MidiTime getByTime(Time time) { for (val repTime : repTimes) if (repTime.containsTime(time)) return repTime.getByTime(time); return null; } /** * Returns the {@link MidiTime} at the given MIDI millisecond, or null. */ public MidiTime getByMs(long ms) { for (val repTime : repTimes) if (repTime.containsMs(ms)) return repTime.getByMs(ms); return null; } /** * Gets the sorted {@link Time}s of the given {@link Repetition}. */ public IList<Time> getTimesSorted(int repetition) { return repTimes.get(repetition).timesSorted; } /** * For debugging purposes: Returns the time-to-tick map as a string, sorted * by repetitions and time. The milliseconds are ignored in the output string. */ @Override public String toString() { String s = "TimeMap ( repetitions = [\n"; for (int iRep : range(repTimes)) { s += "repetition " + iRep + " = ["; val rep = repTimes.get(iRep); for (val time : rep.timesSorted) { val midiTime = rep.getByTime(time); s += "{" + time.measure + "," + time.beat + " -> " + midiTime.tick + "}, "; } s += "]\n"; } s += "])"; return s; } }