Class: HeadMusic::Style::Guidelines::NoteCountPerBar

Inherits:
HeadMusic::Style::Guideline show all
Defined in:
lib/head_music/style/guidelines/note_count_per_bar.rb

Overview

Checks that each middle bar (not first or last) contains an exact number of notes of a given rhythmic value. Configurable via the count: and rhythmic_value: options; subclasses may set COUNT and RHYTHMIC_VALUE defaults.

Direct Known Subclasses

FourPerBar, OnePerBar, ThreePerBar, TwoPerBar

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

This class inherits a constructor from HeadMusic::Style::Guideline

Class Method Details

.template_keyObject

One template for all four subclasses: they differ by count and unit, not by sentence. Named explicitly so the subclasses do not each need an entry.



16
# File 'lib/head_music/style/guidelines/note_count_per_bar.rb', line 16

def self.template_key = "note_count_per_bar"

.template_values(config) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/head_music/style/guidelines/note_count_per_bar.rb', line 18

def self.template_values(config)
  count = config.fetch(:count) { self::COUNT }
  unit = config.fetch(:rhythmic_value) { self::RHYTHMIC_VALUE }
  {
    count: count,
    number: HeadMusic::Style::Template.number_word(count),
    # Pluralized because British names the value with a noun and drops the
    # "note" the American sentence carries: four crotchets, not four crotchet
    # notes. English's entries stay scalar, which I18n reads past the count.
    rhythmic_unit: HeadMusic::Style::Template.pluralize(
      "rhythmic_units.#{unit}", count: count, scope: HeadMusic::Style::Template::RUDIMENT_SCOPE
    )
  }
end

Instance Method Details

#check_middle_bar(bar_number) ⇒ Object (private)



47
48
49
50
51
52
# File 'lib/head_music/style/guidelines/note_count_per_bar.rb', line 47

def check_middle_bar(bar_number)
  bar_notes = notes_in_bar(bar_number)
  return if bar_notes.length == count && bar_notes.all? { |note| note.rhythmic_value == rhythmic_value }

  mark_bar(bar_number)
end

#countObject (private)



35
36
37
# File 'lib/head_music/style/guidelines/note_count_per_bar.rb', line 35

def count
  options.fetch(:count) { self.class::COUNT }
end

#mark_bar(bar_number) ⇒ Object (private)



65
66
67
68
69
70
71
72
73
# File 'lib/head_music/style/guidelines/note_count_per_bar.rb', line 65

def mark_bar(bar_number)
  bar_placements = notes_in_bar(bar_number)
  if bar_placements.any?
    HeadMusic::Style::Mark.for_all(bar_placements)
  else
    cf_note = cantus_firmus.notes.detect { |note| note.position.bar_number == bar_number }
    HeadMusic::Style::Mark.for(cf_note) if cf_note
  end
end

#marksObject



8
9
10
11
12
# File 'lib/head_music/style/guidelines/note_count_per_bar.rb', line 8

def marks
  return [] unless cantus_firmus&.notes&.any?

  middle_bars.filter_map { |bar_number| check_middle_bar(bar_number) }
end

#middle_barsObject (private)



54
55
56
57
58
59
# File 'lib/head_music/style/guidelines/note_count_per_bar.rb', line 54

def middle_bars
  cf_notes = cantus_firmus.notes
  return [] if cf_notes.length <= 2

  cf_notes[1..-2].map { |note| note.position.bar_number }
end

#notes_in_bar(bar_number) ⇒ Object (private)



61
62
63
# File 'lib/head_music/style/guidelines/note_count_per_bar.rb', line 61

def notes_in_bar(bar_number)
  notes.select { |note| note.position.bar_number == bar_number }
end

#rhythmic_unitObject (private)



39
40
41
# File 'lib/head_music/style/guidelines/note_count_per_bar.rb', line 39

def rhythmic_unit
  options.fetch(:rhythmic_value) { self.class::RHYTHMIC_VALUE }
end

#rhythmic_valueObject (private)



43
44
45
# File 'lib/head_music/style/guidelines/note_count_per_bar.rb', line 43

def rhythmic_value
  @rhythmic_value ||= HeadMusic::Rudiment::RhythmicValue.get(rhythmic_unit)
end