Class: Music::Note
Constant Summary collapse
- CHROMATIC_SCALE =
%w[C C/D D D/E E F F/G G G/A A A/B B]- DIATONIC_SCALE =
%w[C D E F G A B]- ACCIDENTALS =
%w[# ♭]- REGEXP =
/ (?<letter> [CDEFGAB] ) (?<accidental> [#♭b]? ) (?<octave> (-?\d+)? ) /x
Instance Attribute Summary collapse
-
#accidental ⇒ String
readonly
# or ♭.
-
#letter ⇒ String
readonly
C, D, E, F, G, A or B.
-
#octave ⇒ Integer
readonly
An integer.
Instance Method Summary collapse
- #-(other) ⇒ Music::Interval
-
#<=>(other) ⇒ Object
Compares notes by their pitch.
-
#initialize(name) ⇒ Note
constructor
A new instance of Note.
- #name ⇒ Object (also: #to_s)
- #transpose_by(interval) ⇒ Music::Note
- #transpose_down(interval) ⇒ Music::Note
- #transpose_up(interval) ⇒ Music::Note
Constructor Details
#initialize(name) ⇒ Note
Returns a new instance of Note.
51 52 53 54 55 56 57 58 59 |
# File 'lib/music/note.rb', line 51 def initialize(name) unless match = name.match(/^#{REGEXP}$/) raise ArgumentError, "invalid note name: #{name} (example: C#1)" end @letter = match[:letter] @accidental = match[:accidental].sub("b", "♭") unless match[:accidental].empty? @octave = match[:octave].to_i unless match[:octave].empty? end |
Instance Attribute Details
#accidental ⇒ String (readonly)
# or ♭.
31 32 33 |
# File 'lib/music/note.rb', line 31 def accidental @accidental end |
#letter ⇒ String (readonly)
C, D, E, F, G, A or B.
25 26 27 |
# File 'lib/music/note.rb', line 25 def letter @letter end |
#octave ⇒ Integer (readonly)
An integer.
37 38 39 |
# File 'lib/music/note.rb', line 37 def octave @octave end |
Instance Method Details
#-(other) ⇒ Music::Interval
130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/music/note.rb', line 130 def -(other) number = (self.diatonic_idx - other.diatonic_idx).abs + 1 number += (self.octave - other.octave).abs * DIATONIC_SCALE.size unless octave.nil? distance = (self.pitch - other.pitch).abs quality = Interval::QUALITIES.find do |quality| begin; Interval.new(number, quality).size == distance; rescue ArgumentError; end end interval = Interval.new(number, quality) self >= other ? interval : -interval end |
#<=>(other) ⇒ Object
Compares notes by their pitch.
75 76 77 |
# File 'lib/music/note.rb', line 75 def <=>(other) self.pitch <=> other.pitch end |
#name ⇒ Object Also known as: to_s
61 62 63 |
# File 'lib/music/note.rb', line 61 def name [letter, accidental, octave].join end |
#transpose_by(interval) ⇒ Music::Note
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/music/note.rb', line 87 def transpose_by(interval) transposed_pitch = pitch + interval.size transposed_pitch %= CHROMATIC_SCALE.size if octave.nil? transposed_diatonic_idx = (diatonic_idx + interval.diff) % DIATONIC_SCALE.size transposed_letter = DIATONIC_SCALE.fetch(transposed_diatonic_idx) transposed_octave = octave + (diatonic_idx + interval.diff) / DIATONIC_SCALE.size if octave transposed_accidental = ACCIDENTALS.find do |accidental| note = Note.new [transposed_letter, accidental, transposed_octave].join note.pitch == transposed_pitch end Note.new [transposed_letter, transposed_accidental, transposed_octave].join end |
#transpose_down(interval) ⇒ Music::Note
120 121 122 |
# File 'lib/music/note.rb', line 120 def transpose_down(interval) transpose_by(-interval) end |
#transpose_up(interval) ⇒ Music::Note
110 111 112 |
# File 'lib/music/note.rb', line 110 def transpose_up(interval) transpose_by(interval) end |