Class: HeadMusic::Content::Bar

Inherits:
Object
  • Object
show all
Defined in:
lib/head_music/content/bar.rb

Overview

Representation of a bar in a flow Encapsulates meter and key signature changes and repeat structure (repeat barlines and volta brackets) as content semantics

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(flow, number: HeadMusic::Time::MusicalPosition::DEFAULT_FIRST_BAR) ⇒ Bar

Returns a new instance of Bar.



11
12
13
14
15
16
17
# File 'lib/head_music/content/bar.rb', line 11

def initialize(flow, number: HeadMusic::Time::MusicalPosition::DEFAULT_FIRST_BAR)
  @flow = flow
  @number = number
  @starts_repeat = false
  @ends_repeat_after_num_plays = nil
  @plays_on_passes = nil
end

Instance Attribute Details

#ends_repeat_after_num_playsObject

Returns the value of attribute ends_repeat_after_num_plays.



8
9
10
# File 'lib/head_music/content/bar.rb', line 8

def ends_repeat_after_num_plays
  @ends_repeat_after_num_plays
end

#flowObject (readonly)

Returns the value of attribute flow.



8
9
10
# File 'lib/head_music/content/bar.rb', line 8

def flow
  @flow
end

#numberObject (readonly)

Returns the value of attribute number.



8
9
10
# File 'lib/head_music/content/bar.rb', line 8

def number
  @number
end

#plays_on_passesObject

Returns the value of attribute plays_on_passes.



8
9
10
# File 'lib/head_music/content/bar.rb', line 8

def plays_on_passes
  @plays_on_passes
end

#starts_repeat=(value) ⇒ Object (writeonly)

Sets the attribute starts_repeat

Parameters:

  • value

    the value to set the attribute starts_repeat to.



9
10
11
# File 'lib/head_music/content/bar.rb', line 9

def starts_repeat=(value)
  @starts_repeat = value
end

Instance Method Details

#ends_repeat?Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/head_music/content/bar.rb', line 41

def ends_repeat?
  !ends_repeat_after_num_plays.nil?
end

#key_signatureObject

The key signature and meter a bar reports are the changes authored here, read from the flow's timeline rather than stored -- nil where nothing was authored, which is what a writer reads to decide whether to print one.



22
23
24
# File 'lib/head_music/content/bar.rb', line 22

def key_signature
  flow.timeline.key_signature_change_at(number)&.key_signature
end

#meterObject



26
27
28
# File 'lib/head_music/content/bar.rb', line 26

def meter
  flow.timeline.meter_change_at(number)
end

#plays_on_pass?(pass_number) ⇒ Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/head_music/content/bar.rb', line 52

def plays_on_pass?(pass_number)
  plays_on_passes.nil? || plays_on_passes.include?(pass_number)
end

#repeat_summaryObject (private)



88
89
90
91
92
93
94
# File 'lib/head_music/content/bar.rb', line 88

def repeat_summary
  parts = []
  parts << "|:" if starts_repeat?
  parts << ":|x#{ends_repeat_after_num_plays}" if ends_repeat?
  parts << "(passes #{plays_on_passes.join(",")})" if plays_on_passes
  parts.join(" ") unless parts.empty?
end

#starts_repeat?Boolean

Returns:

  • (Boolean)


30
31
32
# File 'lib/head_music/content/bar.rb', line 30

def starts_repeat?
  @starts_repeat
end

#to_hObject

Sparse serialization: only non-default state, so a default bar is {}.

Key and meter changes are not here: they belong to the flow's timeline, and a bar merely reports the ones authored in it.



64
65
66
67
68
69
70
# File 'lib/head_music/content/bar.rb', line 64

def to_h
  hash = {}
  hash["starts_repeat"] = true if starts_repeat?
  hash["ends_repeat_after_num_plays"] = ends_repeat_after_num_plays if ends_repeat?
  hash["plays_on_passes"] = plays_on_passes.dup if plays_on_passes
  hash
end

#to_sObject



56
57
58
# File 'lib/head_music/content/bar.rb', line 56

def to_s
  ["Bar", key_signature, meter, repeat_summary].compact.join(" ")
end

#valid_ends_repeat_after_num_plays?(value) ⇒ Boolean (private)

Returns:

  • (Boolean)


74
75
76
77
78
# File 'lib/head_music/content/bar.rb', line 74

def valid_ends_repeat_after_num_plays?(value)
  return true if value.nil?

  value.is_a?(Integer) && value >= 2
end

#valid_plays_on_passes?(value) ⇒ Boolean (private)

Returns:

  • (Boolean)


80
81
82
83
84
85
86
# File 'lib/head_music/content/bar.rb', line 80

def valid_plays_on_passes?(value)
  return true if value.nil?

  value.is_a?(Array) && !value.empty? &&
    value.all? { |pass| pass.is_a?(Integer) && pass.positive? } &&
    value.uniq.length == value.length
end