/**
   * Get the probability of the given transition, but do not perform that transition.
   *
   * <p>This must be called before the given transition is actually performed with {@link
   * #doTransition(MidiNote, int, List)}.
   *
   * @param note The {@link MidiNote} whose transition probability we want.
   * @param transition The value of the transition whose probability we want to get, given the
   *     {@link MidiNote} we want to check. A negative value tells us to add the {@link MidiNote} to
   *     a new {@link Voice} at index (-transition - 1). Any non-negative value tells us to add the
   *     {@link MidiNote} into the existing {@link Voice} at that index in newVoices.
   * @param newVoices A List of the {@link Voice}s available to have the given {@link MidiNote}
   *     added to them.
   * @return The probability of the given transition.
   */
  private double getTransitionProb(MidiNote note, int transition, List<Voice> newVoices) {
    double logProb;
    Voice prev, next;

    // For new Voices, we need to add the Voice, and then update the transition value to
    // point to that new Voice so the lower code works.
    if (transition < 0) {
      transition = -transition - 1;
      logProb = Math.log(params.NEW_VOICE_PROBABILITY);
      prev = transition == 0 ? null : newVoices.get(transition - 1);
      next = transition == newVoices.size() ? null : newVoices.get(transition);

    } else {
      logProb = Math.log(newVoices.get(transition).getProbability(note, params));
      prev = transition == 0 ? null : newVoices.get(transition - 1);
      next = transition == newVoices.size() - 1 ? null : newVoices.get(transition + 1);
    }

    // Check if we are in the wrong order with the prev or next Voices (or both)
    if (prev != null && note.getPitch() < prev.getMostRecentNote().getPitch()) {
      logProb -= Math.log(2);
    }

    if (next != null && note.getPitch() > next.getMostRecentNote().getPitch()) {
      logProb -= Math.log(2);
    }

    if (logProb == Double.NEGATIVE_INFINITY) {
      logProb = -Double.MAX_VALUE;
    }

    return logProb;
  }
  /**
   * Get a List of the indices at which an existing {@link Voice} lies in the given List which each
   * of thie given incoming {@link MidiNote}s could be added.
   *
   * @param incoming A List of the {@link MidiNote}s to check for open {@link Voice}s.
   * @param voices A List of the {@link Voice}s we want to check.
   * @return A List of the open voices in newVoices for each incoming note. <code>
   *     return.get(i).get(j)</code> will return the index of the (j+1)th (since it is 0-indexed)
   *     open {@link Voice} in newVoices for the ith {@link MidiNote} from incoming.
   */
  private List<List<Integer>> getOpenVoiceIndices(List<MidiNote> incoming, List<Voice> voices) {
    long onsetTime = incoming.get(0).getOnsetTime();
    List<List<Integer>> openIndices = new ArrayList<List<Integer>>(incoming.size());

    for (MidiNote note : incoming) {
      List<Integer> noteOpen = new ArrayList<Integer>();
      for (int i = 0; i < voices.size(); i++) {
        if (voices.get(i).canAddNoteAtTime(onsetTime, note.getDurationTime(), params)) {
          noteOpen.add(i);
        }
      }
      openIndices.add(noteOpen);
    }

    return openIndices;
  }