Class: HeadMusic::Notation::MusicXML::Divisions

Inherits:
Object
  • Object
show all
Defined in:
lib/head_music/notation/music_xml/divisions.rb

Overview

Computes the smallest MusicXML value (subdivisions of a quarter note) that lets every note, rest, and whole-measure duration in a composition be expressed as an exact integer.

Class Method Summary collapse

Class Method Details

.chain_denominators(rhythmic_value) ⇒ Object (private)



35
36
37
38
39
40
# File 'lib/head_music/notation/music_xml/divisions.rb', line 35

def self.chain_denominators(rhythmic_value)
  denominators = [DurationWriter.single_quarter_fraction(rhythmic_value).denominator]
  tied_value = rhythmic_value.tied_value
  denominators += chain_denominators(tied_value) if tied_value
  denominators
end

.denominators(composition) ⇒ Object (private)



11
12
13
# File 'lib/head_music/notation/music_xml/divisions.rb', line 11

def self.denominators(composition)
  meter_denominators(composition) + note_denominators(composition)
end

.for(composition) ⇒ Object



7
8
9
# File 'lib/head_music/notation/music_xml/divisions.rb', line 7

def self.for(composition)
  denominators(composition).reduce(1) { |lcm, denominator| lcm.lcm(denominator) }
end

.meter_denominators(composition) ⇒ Object (private)

A whole measure of rest must also be expressible as an integer, so the base meter and every meter change’s quarter-note-equivalent duration contributes a denominator too (e.g. 3/8 needs divisions divisible by 2). Bar#meter is a plain attr_accessor, so a bar’s meter is normalized through Meter.get here in case a caller assigned it a bare string.



21
22
23
24
25
# File 'lib/head_music/notation/music_xml/divisions.rb', line 21

def self.meter_denominators(composition)
  meters = [composition.meter] + composition.bars.map(&:meter).compact
  meters.map { |meter| HeadMusic::Rudiment::Meter.get(meter) }
    .map { |meter| Rational(4 * meter.top_number, meter.bottom_number).denominator }
end

.note_denominators(composition) ⇒ Object (private)



28
29
30
31
32
# File 'lib/head_music/notation/music_xml/divisions.rb', line 28

def self.note_denominators(composition)
  composition.voices.flat_map do |voice|
    voice.placements.flat_map { |placement| chain_denominators(placement.rhythmic_value) }
  end
end