totalDuration property

double get totalDuration

Real duração que a quiáltera ocupa no compasso, em semibreves.

Soma a duração escrita de cada elemento e aplica a razão normalNotes / actualNotes uma única vez.

A implementação anterior lia apenas a PRIMEIRA nota e multiplicava por actualNotes, o que assumia que toda quiáltera é homogênea. Isso estava errado em três casos comuns:

  • duraçōes mistas — uma tercina de colcheia + semínima + colcheia é perfeitamente legal e era medida como três colcheias;
  • quiálteras só com pausas ou só com acordes — whereType<Note>() não encontrava nada e a duração virava 0.0, colapsando o tempo de tudo que vinha depois;
  • quiálteras aninhadas — o grupo interno não era contado.

Como o onset musical de cada evento é derivado daqui, um erro deste valor desloca tudo o que segue — inclusive o alinhamento entre pautas e a seleção por intervalo de tempo.

Apojaturas não contam. Uma nota de ornamento (Note.isGraceNote) é um ornamento, não parte do valor escrito do grupo: ela é desenhada e ocupa largura, mas o relógio não avança por ela. Essa é exatamente a regra que Measure.musicalValueOf (e o MidiMapper) já aplicam, e as duas implementações discordavam: medido, uma tercina 3:2 contendo uma apojatura devolvia totalDuration = 0.3333 contra musicalValueOf = 0.25. Como o LayoutEngine usa musicalValueOf para o onset e o resto do pacote lê totalDuration, a grade de onsets compartilhada do ADR-002 — a única razão pela qual duas pautas de um grande sistema se alinham — divergia para qualquer quiáltera ornamentada.

Implementation

double get totalDuration {
  if (elements.isEmpty) return 0.0;

  double written = 0.0;
  for (final element in elements) {
    if (element is Note) {
      if (element.isGraceNote) continue;
      written += element.duration.realValue;
    } else if (element is Rest) {
      written += element.duration.realValue;
    } else if (element is Chord) {
      // Um acorde soa uma vez, não uma vez por nota.
      written += element.duration.realValue;
    } else if (element is Tuplet) {
      // Já traz a própria razão aplicada.
      written += element.totalDuration;
    }
  }

  return written * ratio.modifier;
}