Class: HeadMusic::Notation::ABC::DurationResolver
- Inherits:
-
Object
- Object
- HeadMusic::Notation::ABC::DurationResolver
- Defined in:
- lib/head_music/notation/abc/duration_resolver.rb
Overview
Converts the tune's unit note length and a per-note multiplier string (e.g. "2", "3/2", "/", "//") into a HeadMusic::Rudiment::RhythmicValue.
Constant Summary collapse
- MAX_FRACTION =
HeadMusic::Notation::DottedDuration::MAX_FRACTION
- MULTIPLIER_PATTERN =
%r{\A(\d+)?(?:(/+)(\d+)?)?\z}
Instance Attribute Summary collapse
-
#unit_note_length ⇒ Object
readonly
Returns the value of attribute unit_note_length.
Instance Method Summary collapse
- #explicit_ratio(numerator, slashes, denominator, source) ⇒ Object private
-
#initialize(unit_note_length) ⇒ DurationResolver
constructor
A new instance of DurationResolver.
-
#length_fraction(multiplier_string) ⇒ Object
The bare fraction a length string denotes (e.g. "2" -> 2, "/2" -> 1/2, "" -> 1), without the unit note length applied.
- #multiplier(multiplier_string) ⇒ Object private
- #raise_error(message, source) ⇒ Object private
-
#rhythmic_value(multiplier_string, scale: Rational(1)) ⇒ Object
scale: an extra multiplier applied outside the note's own length string, used for broken-rhythm pairs (3/2 and 1/2).
- #validate_fraction!(fraction, source) ⇒ Object private
Constructor Details
#initialize(unit_note_length) ⇒ DurationResolver
Returns a new instance of DurationResolver.
12 13 14 |
# File 'lib/head_music/notation/abc/duration_resolver.rb', line 12 def initialize(unit_note_length) @unit_note_length = Rational(unit_note_length) end |
Instance Attribute Details
#unit_note_length ⇒ Object (readonly)
Returns the value of attribute unit_note_length.
10 11 12 |
# File 'lib/head_music/notation/abc/duration_resolver.rb', line 10 def unit_note_length @unit_note_length end |
Instance Method Details
#explicit_ratio(numerator, slashes, denominator, source) ⇒ Object (private)
48 49 50 51 52 53 |
# File 'lib/head_music/notation/abc/duration_resolver.rb', line 48 def explicit_ratio(numerator, slashes, denominator, source) # An explicit denominator pairs with exactly one slash ("3/2", not "3//2"). raise_error("malformed note length multiplier", source) if slashes.length > 1 raise_error("note length denominator cannot be zero", source) if denominator.to_i.zero? Rational(numerator, denominator.to_i) end |
#length_fraction(multiplier_string) ⇒ Object
The bare fraction a length string denotes (e.g. "2" -> 2, "/2" -> 1/2, "" -> 1), without the unit note length applied. Used to compare a chord's per-note lengths for uniformity.
28 29 30 |
# File 'lib/head_music/notation/abc/duration_resolver.rb', line 28 def length_fraction(multiplier_string) multiplier(multiplier_string) end |
#multiplier(multiplier_string) ⇒ Object (private)
34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/head_music/notation/abc/duration_resolver.rb', line 34 def multiplier(multiplier_string) source = multiplier_string.to_s match = MULTIPLIER_PATTERN.match(source) raise_error("malformed note length multiplier", source) unless match numerator = (match[1] || 1).to_i slashes = match[2] denominator = match[3] return Rational(numerator) unless slashes return Rational(numerator, 2**slashes.length) unless denominator explicit_ratio(numerator, slashes, denominator, source) end |
#raise_error(message, source) ⇒ Object (private)
63 64 65 |
# File 'lib/head_music/notation/abc/duration_resolver.rb', line 63 def raise_error(, source) raise HeadMusic::Notation::ABC::ParseError.new(, snippet: source) end |
#rhythmic_value(multiplier_string, scale: Rational(1)) ⇒ Object
scale: an extra multiplier applied outside the note's own length string, used for broken-rhythm pairs (3/2 and 1/2).
18 19 20 21 22 23 |
# File 'lib/head_music/notation/abc/duration_resolver.rb', line 18 def rhythmic_value(multiplier_string, scale: Rational(1)) fraction = unit_note_length * multiplier(multiplier_string) * scale validate_fraction!(fraction, multiplier_string) HeadMusic::Notation::DottedDuration.rhythmic_value_for(fraction) || raise_error("no rhythmic unit for a note length of #{fraction}", multiplier_string) end |
#validate_fraction!(fraction, source) ⇒ Object (private)
55 56 57 58 59 60 61 |
# File 'lib/head_music/notation/abc/duration_resolver.rb', line 55 def validate_fraction!(fraction, source) raise_error("note length must be positive", source) if fraction <= 0 raise_error("note length exceeds #{MAX_FRACTION.to_i} whole notes", source) if fraction > MAX_FRACTION return if HeadMusic::Notation::DottedDuration.power_of_two?(fraction.denominator) raise_error("note length #{fraction} is not expressible in binary note values", source) end |