Class: HeadMusic::Rudiment::Note

Inherits:
RhythmicElement show all
Includes:
Named
Defined in:
lib/head_music/rudiment/note.rb

Overview

A Note is a fundamental musical element consisting of a pitch and a duration. This is the rudiment version, representing the abstract concept of a note independent of its placement in a composition.

For notes placed within a composition context, see HeadMusic::Content::Note

Constant Summary collapse

PITCH_PATTERN =

Regex pattern for parsing note strings like "C#4 quarter" or "Eb3 dotted half" Extract the core pattern from Spelling::MATCHER without anchors

/([A-G])(#{HeadMusic::Rudiment::Alteration::PATTERN.source}?)(-?\d+)?/i
MATCHER =
/^\s*(#{PITCH_PATTERN.source})\s+(.+)$/i

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pitch, rhythmic_value) ⇒ Note

Returns a new instance of Note.



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

def initialize(pitch, rhythmic_value)
  super(rhythmic_value)
  @pitch = pitch
end

Instance Attribute Details

#alias_name_keysObject (readonly) Originally defined in module Named

Returns the value of attribute alias_name_keys.

#name_keyObject (readonly) Originally defined in module Named

Returns the value of attribute name_key.

#pitchObject (readonly)

Returns the value of attribute pitch.



12
13
14
# File 'lib/head_music/rudiment/note.rb', line 12

def pitch
  @pitch
end

Class Method Details

.fetch_or_create(pitch, rhythmic_value) ⇒ Object (private)



51
52
53
54
55
# File 'lib/head_music/rudiment/note.rb', line 51

def self.fetch_or_create(pitch, rhythmic_value)
  @notes ||= {}
  hash_key = [pitch.to_s, rhythmic_value.to_s].join("_")
  @notes[hash_key] ||= new(pitch, rhythmic_value)
end

.get(pitch, rhythmic_value = nil) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/head_music/rudiment/note.rb', line 23

def self.get(pitch, rhythmic_value = nil)
  return pitch if pitch.is_a?(HeadMusic::Rudiment::Note)

  if rhythmic_value.nil? && pitch.is_a?(String)
    # Try to parse as "pitch rhythmic_value" format (e.g., "F#4 dotted-quarter")
    match = pitch.match(MATCHER)
    if match
      pitch_str = match[1] # The full pitch part
      rhythmic_value_str = match[5] # The rhythmic value part

      pitch_obj = HeadMusic::Rudiment::Pitch.get(pitch_str)
      rhythmic_value_obj = HeadMusic::Rudiment::RhythmicValue.get(rhythmic_value_str)

      return fetch_or_create(pitch_obj, rhythmic_value_obj) if pitch_obj && rhythmic_value_obj
    end

    # If parsing fails, treat it as just a pitch with default quarter note
    pitch_obj = HeadMusic::Rudiment::Pitch.get(pitch)
    return fetch_or_create(pitch_obj, HeadMusic::Rudiment::RhythmicValue.get(:quarter)) if pitch_obj

    nil
  else
    pitch = HeadMusic::Rudiment::Pitch.get(pitch)
    rhythmic_value = HeadMusic::Rudiment::RhythmicValue.get(rhythmic_value || :quarter)
    fetch_or_create(pitch, rhythmic_value)
  end
end

Instance Method Details

#+(other) ⇒ Object

Transpose the note up by an interval or semitones



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

def +(other)
  new_pitch = pitch + other
  self.class.get(new_pitch, rhythmic_value)
end

#-(other) ⇒ Object

Transpose the note down by an interval or semitones



92
93
94
95
# File 'lib/head_music/rudiment/note.rb', line 92

def -(other)
  new_pitch = pitch - other
  self.class.get(new_pitch, rhythmic_value)
end

#<=>(other) ⇒ Object



78
79
80
81
82
83
# File 'lib/head_music/rudiment/note.rb', line 78

def <=>(other)
  return nil unless other.is_a?(HeadMusic::Rudiment::RhythmicElement)
  return super unless other.is_a?(self.class)

  [rhythmic_value, pitch] <=> [other.rhythmic_value, other.pitch]
end

#==(other) ⇒ Object



73
74
75
76
# File 'lib/head_music/rudiment/note.rb', line 73

def ==(other)
  other = HeadMusic::Rudiment::Note.get(other)
  super && pitch == other.pitch
end

#ensure_localized_name(name:, locale_code: Locale::DEFAULT_CODE, abbreviation: nil) ⇒ Object Originally defined in module Named

#localized_name(locale_code: Locale::DEFAULT_CODE) ⇒ Object Originally defined in module Named

#localized_name_in_default_localeObject (private) Originally defined in module Named

#localized_name_in_locale_matching_language(locale) ⇒ Object (private) Originally defined in module Named

#localized_name_in_matching_locale(locale) ⇒ Object (private) Originally defined in module Named

#localized_namesObject Originally defined in module Named

Returns an array of LocalizedName instances that are synonymous with the name.

#nameObject



65
66
67
# File 'lib/head_music/rudiment/note.rb', line 65

def name
  "#{pitch} #{rhythmic_value}"
end

#name=(name) ⇒ Object Originally defined in module Named

#sounded?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/head_music/rudiment/note.rb', line 107

def sounded?
  true
end

#to_sObject



69
70
71
# File 'lib/head_music/rudiment/note.rb', line 69

def to_s
  name
end

#with_pitch(new_pitch) ⇒ Object

Change the pitch while keeping the same rhythmic value



103
104
105
# File 'lib/head_music/rudiment/note.rb', line 103

def with_pitch(new_pitch)
  self.class.get(new_pitch, rhythmic_value)
end

#with_rhythmic_value(new_rhythmic_value) ⇒ Object

Override to maintain pitch when changing rhythmic value



98
99
100
# File 'lib/head_music/rudiment/note.rb', line 98

def with_rhythmic_value(new_rhythmic_value)
  self.class.get(pitch, new_rhythmic_value)
end