Class: RBMusic::Note

Inherits:
Object
  • Object
show all
Defined in:
lib/rb-music/note.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(coord) ⇒ Note

Returns a new instance of Note.



6
7
8
# File 'lib/rb-music/note.rb', line 6

def initialize(coord)
  self.coord = coord
end

Instance Attribute Details

#coordObject

Returns the value of attribute coord.



4
5
6
# File 'lib/rb-music/note.rb', line 4

def coord
  @coord
end

Class Method Details

.from_latin(name) ⇒ Object

Raises:



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/rb-music/note.rb', line 10

def self.from_latin(name)
  raise ArgumentError unless name.is_a?(String)

  note_parts = name.split(/(\d+)/)
  note_name = note_parts.first
  octave = note_parts.last.to_i

  unless NOTES.has_key?(note_name) && note_parts.size < 3
    raise ArgumentError
  end

  coordinate = [NOTES[note_name][0] + octave, NOTES[note_name][1]]

  coordinate[0] -= BASE_OFFSET[0]
  coordinate[1] -= BASE_OFFSET[1]

  Note.new(coordinate)
end

Instance Method Details

#==(other) ⇒ Object



48
49
50
# File 'lib/rb-music/note.rb', line 48

def ==(other)
  other.is_a?(Note) && other.latin == latin && other.octave == octave
end

#accidentalObject



33
34
35
# File 'lib/rb-music/note.rb', line 33

def accidental
  @accidental ||= ((coord[1] + BASE_OFFSET[1]) / 7.0).round
end

#add(that) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rb-music/note.rb', line 68

def add(that)
  # if input is an array return an array
  if that.is_a?(Array)
    notes = that.map { |thing| add(thing) }
    return NoteSet.new(notes)
  end

  # if input is string/symbol try to parse it as interval
  if that.is_a?(String) || that.is_a?(Symbol)
    that = Interval.from_name(that)
  end

  Note.new([coord[0] + that.coord[0], coord[1] + that.coord[1]])
end

#enharmonic?(other) ⇒ Boolean Also known as: enharmonically_equivalent_to?

Returns:

  • (Boolean)

Raises:



52
53
54
55
56
# File 'lib/rb-music/note.rb', line 52

def enharmonic?(other)
  raise ArgumentError unless other.is_a?(Note)

  other.frequency == frequency
end

#frequencyObject



29
30
31
# File 'lib/rb-music/note.rb', line 29

def frequency
  BASE_FREQ * (2.0 ** ((coord[0] * 1200 + coord[1] * 700.0) / 1200.0))
end

#latinObject



42
43
44
45
46
# File 'lib/rb-music/note.rb', line 42

def latin
  return @latin if @latin
  accidentalName = ACCIDENTALS[accidental + 2]
  @latin ||= base_note_name + accidentalName
end

#midi_note_numberObject



59
60
61
62
# File 'lib/rb-music/note.rb', line 59

def midi_note_number
  # see http://www.phys.unsw.edu.au/jw/notes.html
  @note_number ||= (12 * Math.log2(frequency / 440) + 69).round
end

#octaveObject



37
38
39
40
# File 'lib/rb-music/note.rb', line 37

def octave
  # calculate octave of base note without accidentals
  @octave ||= coord[0] + BASE_OFFSET[0] + 4 * accidental + ((coord[1] + BASE_OFFSET[1] - 7 * accidental) / 2).floor
end

#scale(name, octaves = 1) ⇒ Object



64
65
66
# File 'lib/rb-music/note.rb', line 64

def scale(name, octaves = 1)
  NoteSet.from_scale(Scale.new(latin, name), octave, octaves)
end

#subtract(that) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/rb-music/note.rb', line 83

def subtract(that)
  if that.is_a?(Array)
    notes = that.map { |thing| subtract(thing) }
    return NoteSet.new(notes)
  end

  # if input is string try to parse it as interval
  if that.is_a?(String) || that.is_a?(Symbol)
    that = Interval.from_name(that)
  end

  coordinate = [coord[0] - that.coord[0], coord[1] - that.coord[1]]

  # if input is another note return the difference as an Interval
  that.is_a?(Note) ? Interval.new(coordinate) : Note.new(coordinate)
end