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 flow be expressed as an exact integer.

Class Method Summary collapse

Class Method Details

.chain_denominators(rhythmic_value) ⇒ Object (private)



32
33
34
35
36
37
# File 'lib/head_music/notation/music_xml/divisions.rb', line 32

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(flow) ⇒ Object (private)



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

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

.for(flow) ⇒ Object



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

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

.meter_denominators(flow) ⇒ 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).



19
20
21
22
# File 'lib/head_music/notation/music_xml/divisions.rb', line 19

def self.meter_denominators(flow)
  ([flow.meter] + flow.meter_changes.values)
    .map { |meter| Rational(4 * meter.top_number, meter.bottom_number).denominator }
end

.note_denominators(flow) ⇒ Object (private)



25
26
27
28
29
# File 'lib/head_music/notation/music_xml/divisions.rb', line 25

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