Class: HeadMusic::Rudiment::Meter

Inherits:
Base
  • Object
show all
Defined in:
lib/head_music/rudiment/meter.rb

Overview

Meter is the rhythmic size of a measure, such as 4/4 or 6/8

Constant Summary collapse

NAMED =
{
  common_time: "4/4",
  cut_time: "2/2"
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(top_number, bottom_number) ⇒ Meter

Returns a new instance of Meter.



33
34
35
36
# File 'lib/head_music/rudiment/meter.rb', line 33

def initialize(top_number, bottom_number)
  @top_number = top_number.to_i
  @bottom_number = bottom_number.to_i
end

Instance Attribute Details

#bottom_numberObject (readonly)

Returns the value of attribute bottom_number.



6
7
8
# File 'lib/head_music/rudiment/meter.rb', line 6

def bottom_number
  @bottom_number
end

#top_numberObject (readonly)

Returns the value of attribute top_number.



6
7
8
# File 'lib/head_music/rudiment/meter.rb', line 6

def top_number
  @top_number
end

Class Method Details

.common_timeObject



25
26
27
# File 'lib/head_music/rudiment/meter.rb', line 25

def self.common_time
  get(:common_time)
end

.cut_timeObject



29
30
31
# File 'lib/head_music/rudiment/meter.rb', line 29

def self.cut_time
  get(:cut_time)
end

.defaultObject



21
22
23
# File 'lib/head_music/rudiment/meter.rb', line 21

def self.default
  get("4/4")
end

.get(identifier) ⇒ Object



13
14
15
16
17
18
19
# File 'lib/head_music/rudiment/meter.rb', line 13

def self.get(identifier)
  identifier = identifier.to_s
  hash_key = HeadMusic::Utilities::HashKey.for(identifier)
  time_signature_string = NAMED[hash_key] || identifier
  @meters ||= {}
  @meters[hash_key] ||= new(*time_signature_string.split("/"))
end

Instance Method Details

#==(other) ⇒ Object



115
116
117
# File 'lib/head_music/rudiment/meter.rb', line 115

def ==(other)
  to_s == other.to_s
end

#beam_group_unitObject

The span of one default beam group for this meter, as a RhythmicValue. This is a distinct concern from #beat_value: it is the boundary unit used to decide where beams break.



100
101
102
103
104
105
106
107
108
109
# File 'lib/head_music/rudiment/meter.rb', line 100

def beam_group_unit
  @beam_group_unit ||=
    if compound?
      beat_value
    elsif bottom_number >= 8
      whole_bar_beam_group_unit
    else
      count_unit_value
    end
end

#beat?(tick) ⇒ Boolean (private)

Returns:

  • (Boolean)


178
179
180
# File 'lib/head_music/rudiment/meter.rb', line 178

def beat?(tick)
  tick.to_i.zero?
end

#beat_strength(count, tick: 0) ⇒ Object



70
71
72
73
74
75
76
77
# File 'lib/head_music/rudiment/meter.rb', line 70

def beat_strength(count, tick: 0)
  return 100 if downbeat?(count, tick)
  return 80 if strong_beat?(count, tick)
  return 60 if beat?(tick)
  return 40 if strong_ticks.include?(tick)

  20
end

#beat_valueObject Also known as: beat_unit



90
91
92
# File 'lib/head_music/rudiment/meter.rb', line 90

def beat_value
  @beat_value ||= compound? ? dotted_denominator_value(bottom_number / 2) : count_unit_value
end

#beats_per_barObject



58
59
60
# File 'lib/head_music/rudiment/meter.rb', line 58

def beats_per_bar
  compound? ? top_number / 3 : top_number
end

#compound?Boolean

Returns:

  • (Boolean)


42
43
44
# File 'lib/head_music/rudiment/meter.rb', line 42

def compound?
  top_number > 3 && (top_number % 3).zero?
end

#count_unitObject

The rhythmic unit for the count (bottom number). This unit is also used as “beats” in a sequencer context For example, “1:3:000”



86
87
88
# File 'lib/head_music/rudiment/meter.rb', line 86

def count_unit
  HeadMusic::Rudiment::RhythmicUnit.for_denominator_value(bottom_number)
end

#count_unit_valueObject (private)



144
145
146
# File 'lib/head_music/rudiment/meter.rb', line 144

def count_unit_value
  HeadMusic::Rudiment::RhythmicValue.new(count_unit)
end

#counts_per_barObject



62
63
64
# File 'lib/head_music/rudiment/meter.rb', line 62

def counts_per_bar
  top_number
end

#counts_per_quarter_noteObject



66
67
68
# File 'lib/head_music/rudiment/meter.rb', line 66

def counts_per_quarter_note
  0.25 / count_unit.relative_value
end

#dotted_denominator_value(denominator) ⇒ Object (private)

A dotted value of the rhythmic unit for the given denominator (e.g. the dotted-quarter beat of a 6/8 meter for denominator 4).



150
151
152
153
# File 'lib/head_music/rudiment/meter.rb', line 150

def dotted_denominator_value(denominator)
  unit = HeadMusic::Rudiment::RhythmicUnit.for_denominator_value(denominator)
  HeadMusic::Rudiment::RhythmicValue.new(unit, dots: 1)
end

#downbeat?(count, tick = 0) ⇒ Boolean (private)

Returns:

  • (Boolean)


155
156
157
# File 'lib/head_music/rudiment/meter.rb', line 155

def downbeat?(count, tick = 0)
  beat?(tick) && count == 1
end

#duple?Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/head_music/rudiment/meter.rb', line 46

def duple?
  top_number == 2
end

#quadruple?Boolean

Returns:

  • (Boolean)


54
55
56
# File 'lib/head_music/rudiment/meter.rb', line 54

def quadruple?
  top_number == 4
end

#simple?Boolean

Returns:

  • (Boolean)


38
39
40
# File 'lib/head_music/rudiment/meter.rb', line 38

def simple?
  !compound?
end

#strong_beat?(count, tick = 0) ⇒ Boolean (private)

Returns:

  • (Boolean)


159
160
161
# File 'lib/head_music/rudiment/meter.rb', line 159

def strong_beat?(count, tick = 0)
  beat?(tick) && (strong_beat_in_duple?(count, tick) || strong_beat_in_triple?(count, tick))
end

#strong_beat_in_duple?(count, tick = 0) ⇒ Boolean (private)

Returns:

  • (Boolean)


163
164
165
166
167
168
# File 'lib/head_music/rudiment/meter.rb', line 163

def strong_beat_in_duple?(count, tick = 0)
  return false unless beat?(tick)
  return false unless counts_per_bar.even?

  (count - 1) == counts_per_bar / 2
end

#strong_beat_in_triple?(count, tick = 0) ⇒ Boolean (private)

Returns:

  • (Boolean)


170
171
172
173
174
175
176
# File 'lib/head_music/rudiment/meter.rb', line 170

def strong_beat_in_triple?(count, tick = 0)
  return false unless beat?(tick)
  return false unless (counts_per_bar % 3).zero?
  return false if counts_per_bar < 6

  count % 3 == 1
end

#strong_countsObject



119
120
121
122
123
# File 'lib/head_music/rudiment/meter.rb', line 119

def strong_counts
  @strong_counts ||= (1..counts_per_bar).select do |count|
    downbeat?(count) || strong_beat_in_duple?(count) || strong_beat_in_triple?(count)
  end
end

#strong_ticksObject



125
126
127
# File 'lib/head_music/rudiment/meter.rb', line 125

def strong_ticks
  @strong_ticks ||= [2, 3, 4].map { |sixths| ticks_per_count * (sixths / 6.0) }
end

#ticks_per_countObject



79
80
81
# File 'lib/head_music/rudiment/meter.rb', line 79

def ticks_per_count
  @ticks_per_count ||= count_unit.ticks
end

#to_sObject



111
112
113
# File 'lib/head_music/rudiment/meter.rb', line 111

def to_s
  [top_number, bottom_number].join("/")
end

#triple?Boolean

Returns:

  • (Boolean)


50
51
52
# File 'lib/head_music/rudiment/meter.rb', line 50

def triple?
  (top_number % 3).zero?
end

#whole_bar_beam_group_unitObject (private)

For simple meters with an eighth-or-shorter denominator (e.g. 2/8, 3/8), the whole bar is a single beam group. A triple grouping (3/8) is a dotted value of the half-denominator unit; a duple grouping (2/8) spans the bar. Asymmetric meters (5/8, 7/16, …) are out of scope: their bar has no single power-of-two unit, so the group unit falls back to the count unit (each count its own group) rather than raising on a nil unit.



137
138
139
140
141
142
# File 'lib/head_music/rudiment/meter.rb', line 137

def whole_bar_beam_group_unit
  return dotted_denominator_value(bottom_number / 2) if (top_number % 3).zero?

  unit = HeadMusic::Rudiment::RhythmicUnit.for_denominator_value(bottom_number / top_number)
  HeadMusic::Rudiment::RhythmicValue.new(unit || count_unit)
end