Class: Musicality::Pitch
- Inherits:
-
Object
- Object
- Musicality::Pitch
- Defined in:
- lib/musicality/notation/model/pitch.rb,
lib/musicality/pitch_class.rb,
lib/musicality/printing/lilypond/pitch_engraving.rb,
lib/musicality/notation/parsing/convenience_methods.rb
Overview
Constant Summary collapse
- SEMITONES_PER_OCTAVE =
The default number of semitones per octave is 12, corresponding to the twelve-tone equal temperment tuning system.
PitchClass::MOD
- CENTS_PER_SEMITONE =
100
- CENTS_PER_OCTAVE =
SEMITONES_PER_OCTAVE * CENTS_PER_SEMITONE
- BASE_FREQ =
The base ferquency is C0
16.351597831287414
- PARSER =
Parsing::PitchParser.new
- CONVERSION_METHOD =
:to_pitch
Constants included from Parseable
Musicality::Parseable::DEFAULT_SPLIT_PATTERN
Constants included from Packable
Instance Attribute Summary collapse
-
#cent ⇒ Object
readonly
Returns the value of attribute cent.
-
#octave ⇒ Integer
readonly
The pitch octave.
-
#semitone ⇒ Integer
readonly
The pitch semitone.
-
#total_cents ⇒ Object
readonly
Returns the value of attribute total_cents.
Class Method Summary collapse
- .from_freq(freq) ⇒ Object
- .from_ratio(ratio) ⇒ Object
- .from_semitones(semitones) ⇒ Object
- .pc_str(semitone, sharpit) ⇒ Object
Instance Method Summary collapse
- #+(semitones) ⇒ Object
- #-(semitones) ⇒ Object
-
#<=>(other) ⇒ Object
Compare pitches.
-
#==(other) ⇒ Object
Compare pitch equality using total semitone.
- #clone ⇒ Object
-
#diff(other) ⇒ Object
diff in (rounded) semitones.
- #eql?(other) ⇒ Boolean
-
#freq ⇒ Object
Return the pitch’s frequency, which is determined by multiplying the base frequency and the pitch ratio.
-
#hash ⇒ Object
Override default hash method.
-
#initialize(octave: 0, semitone: 0, cent: 0) ⇒ Pitch
constructor
A new instance of Pitch.
- #natural? ⇒ Boolean
-
#ratio ⇒ Float
Calculate the pitch ratio.
-
#round ⇒ Object
rounds to the nearest semitone.
- #to_lilypond(sharpit = false) ⇒ Object
- #to_pc ⇒ Object
- #to_s(sharpit = false) ⇒ Object
- #total_semitones ⇒ Object
- #transpose(semitones) ⇒ Object
Methods included from Parseable
Methods included from Packable
#class_str, included, #init_params, #pack, pack_val, recover_class, unpack_val
Constructor Details
#initialize(octave: 0, semitone: 0, cent: 0) ⇒ Pitch
Returns a new instance of Pitch.
35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/musicality/notation/model/pitch.rb', line 35 def initialize octave:0, semitone:0, cent: 0 raise NonIntegerError, "octave #{octave} is not an integer" unless octave.is_a?(Integer) raise NonIntegerError, "semitone #{semitone} is not an integer" unless semitone.is_a?(Integer) raise NonIntegerError, "cent #{cent} is not an integer" unless cent.is_a?(Integer) @octave = octave @semitone = semitone @cent = cent @total_cents = (@octave*SEMITONES_PER_OCTAVE + @semitone)*CENTS_PER_SEMITONE + @cent balance! end |
Instance Attribute Details
#cent ⇒ Object (readonly)
Returns the value of attribute cent.
24 25 26 |
# File 'lib/musicality/notation/model/pitch.rb', line 24 def cent @cent end |
#octave ⇒ Integer (readonly)
Returns The pitch octave.
20 21 22 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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/musicality/notation/model/pitch.rb', line 20 class Pitch include Comparable include Packable attr_reader :octave, :semitone, :cent, :total_cents #The default number of semitones per octave is 12, corresponding to # the twelve-tone equal temperment tuning system. SEMITONES_PER_OCTAVE = PitchClass::MOD CENTS_PER_SEMITONE = 100 CENTS_PER_OCTAVE = SEMITONES_PER_OCTAVE * CENTS_PER_SEMITONE # The base ferquency is C0 BASE_FREQ = 16.351597831287414 def initialize octave:0, semitone:0, cent: 0 raise NonIntegerError, "octave #{octave} is not an integer" unless octave.is_a?(Integer) raise NonIntegerError, "semitone #{semitone} is not an integer" unless semitone.is_a?(Integer) raise NonIntegerError, "cent #{cent} is not an integer" unless cent.is_a?(Integer) @octave = octave @semitone = semitone @cent = cent @total_cents = (@octave*SEMITONES_PER_OCTAVE + @semitone)*CENTS_PER_SEMITONE + @cent balance! end # Return the pitch's frequency, which is determined by multiplying the base # frequency and the pitch ratio. Base frequency defaults to DEFAULT_BASE_FREQ, # but can be set during initialization to something else by specifying the # :base_freq key. def freq return self.ratio() * BASE_FREQ end # Calculate the pitch ratio. Raises 2 to the power of the total cent # count divided by cents-per-octave. # @return [Float] ratio def ratio 2.0**(@total_cents.to_f / CENTS_PER_OCTAVE) end # Override default hash method. def hash return @total_cents end # Compare pitch equality using total semitone def ==(other) return (self.class == other.class && @total_cents == other.total_cents) end def eql?(other) self == other end # Compare pitches. A higher ratio or total semitone is considered larger. # @param [Pitch] other The pitch object to compare. def <=> (other) @total_cents <=> other.total_cents end # rounds to the nearest semitone def round if @cent == 0 self.clone else Pitch.new(semitone: (@total_cents / CENTS_PER_SEMITONE.to_f).round) end end # diff in (rounded) semitones def diff other Rational(@total_cents - other.total_cents, CENTS_PER_SEMITONE) end def transpose semitones Pitch.new(cent: (@total_cents + semitones * CENTS_PER_SEMITONE).round) end def + semitones transpose(semitones) end def - semitones transpose(-semitones) end def total_semitones Rational(@total_cents, CENTS_PER_SEMITONE) end def self.from_semitones semitones Pitch.new(cent: (semitones * CENTS_PER_SEMITONE).round) end def clone Pitch.new(cent: @total_cents) end def natural? [0,2,4,5,7,9,11].include?(semitone) end def self.pc_str semitone, sharpit case semitone when 0 then "C" when 1 then sharpit ? "C#" : "Db" when 2 then "D" when 3 then sharpit ? "D#" : "Eb" when 4 then "E" when 5 then "F" when 6 then sharpit ? "F#" : "Gb" when 7 then "G" when 8 then sharpit ? "G#" : "Ab" when 9 then "A" when 10 then sharpit ? "A#" : "Bb" when 11 then "B" end end def to_s(sharpit = false) letter = Pitch.pc_str(semitone, sharpit) if @cent == 0 return letter + octave.to_s elsif @cent > 0 return letter + octave.to_s + "+" + @cent.to_s else return letter + octave.to_s + @cent.to_s end end def self.from_ratio ratio raise NonPositiveError, "ratio #{ratio} is not > 0" unless ratio > 0 x = Math.log2 ratio new(cent: (x * CENTS_PER_OCTAVE).round) end def self.from_freq freq from_ratio(freq / BASE_FREQ) end private # Balance out the octave and semitone count. def balance! centsTotal = @total_cents @octave = centsTotal / CENTS_PER_OCTAVE centsTotal -= @octave * CENTS_PER_OCTAVE @semitone = centsTotal / CENTS_PER_SEMITONE centsTotal -= @semitone * CENTS_PER_SEMITONE @cent = centsTotal return self end end |
#semitone ⇒ Integer (readonly)
Returns The pitch semitone.
20 21 22 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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/musicality/notation/model/pitch.rb', line 20 class Pitch include Comparable include Packable attr_reader :octave, :semitone, :cent, :total_cents #The default number of semitones per octave is 12, corresponding to # the twelve-tone equal temperment tuning system. SEMITONES_PER_OCTAVE = PitchClass::MOD CENTS_PER_SEMITONE = 100 CENTS_PER_OCTAVE = SEMITONES_PER_OCTAVE * CENTS_PER_SEMITONE # The base ferquency is C0 BASE_FREQ = 16.351597831287414 def initialize octave:0, semitone:0, cent: 0 raise NonIntegerError, "octave #{octave} is not an integer" unless octave.is_a?(Integer) raise NonIntegerError, "semitone #{semitone} is not an integer" unless semitone.is_a?(Integer) raise NonIntegerError, "cent #{cent} is not an integer" unless cent.is_a?(Integer) @octave = octave @semitone = semitone @cent = cent @total_cents = (@octave*SEMITONES_PER_OCTAVE + @semitone)*CENTS_PER_SEMITONE + @cent balance! end # Return the pitch's frequency, which is determined by multiplying the base # frequency and the pitch ratio. Base frequency defaults to DEFAULT_BASE_FREQ, # but can be set during initialization to something else by specifying the # :base_freq key. def freq return self.ratio() * BASE_FREQ end # Calculate the pitch ratio. Raises 2 to the power of the total cent # count divided by cents-per-octave. # @return [Float] ratio def ratio 2.0**(@total_cents.to_f / CENTS_PER_OCTAVE) end # Override default hash method. def hash return @total_cents end # Compare pitch equality using total semitone def ==(other) return (self.class == other.class && @total_cents == other.total_cents) end def eql?(other) self == other end # Compare pitches. A higher ratio or total semitone is considered larger. # @param [Pitch] other The pitch object to compare. def <=> (other) @total_cents <=> other.total_cents end # rounds to the nearest semitone def round if @cent == 0 self.clone else Pitch.new(semitone: (@total_cents / CENTS_PER_SEMITONE.to_f).round) end end # diff in (rounded) semitones def diff other Rational(@total_cents - other.total_cents, CENTS_PER_SEMITONE) end def transpose semitones Pitch.new(cent: (@total_cents + semitones * CENTS_PER_SEMITONE).round) end def + semitones transpose(semitones) end def - semitones transpose(-semitones) end def total_semitones Rational(@total_cents, CENTS_PER_SEMITONE) end def self.from_semitones semitones Pitch.new(cent: (semitones * CENTS_PER_SEMITONE).round) end def clone Pitch.new(cent: @total_cents) end def natural? [0,2,4,5,7,9,11].include?(semitone) end def self.pc_str semitone, sharpit case semitone when 0 then "C" when 1 then sharpit ? "C#" : "Db" when 2 then "D" when 3 then sharpit ? "D#" : "Eb" when 4 then "E" when 5 then "F" when 6 then sharpit ? "F#" : "Gb" when 7 then "G" when 8 then sharpit ? "G#" : "Ab" when 9 then "A" when 10 then sharpit ? "A#" : "Bb" when 11 then "B" end end def to_s(sharpit = false) letter = Pitch.pc_str(semitone, sharpit) if @cent == 0 return letter + octave.to_s elsif @cent > 0 return letter + octave.to_s + "+" + @cent.to_s else return letter + octave.to_s + @cent.to_s end end def self.from_ratio ratio raise NonPositiveError, "ratio #{ratio} is not > 0" unless ratio > 0 x = Math.log2 ratio new(cent: (x * CENTS_PER_OCTAVE).round) end def self.from_freq freq from_ratio(freq / BASE_FREQ) end private # Balance out the octave and semitone count. def balance! centsTotal = @total_cents @octave = centsTotal / CENTS_PER_OCTAVE centsTotal -= @octave * CENTS_PER_OCTAVE @semitone = centsTotal / CENTS_PER_SEMITONE centsTotal -= @semitone * CENTS_PER_SEMITONE @cent = centsTotal return self end end |
#total_cents ⇒ Object (readonly)
Returns the value of attribute total_cents.
24 25 26 |
# File 'lib/musicality/notation/model/pitch.rb', line 24 def total_cents @total_cents end |
Class Method Details
.from_freq(freq) ⇒ Object
159 160 161 |
# File 'lib/musicality/notation/model/pitch.rb', line 159 def self.from_freq freq from_ratio(freq / BASE_FREQ) end |
.from_ratio(ratio) ⇒ Object
153 154 155 156 157 |
# File 'lib/musicality/notation/model/pitch.rb', line 153 def self.from_ratio ratio raise NonPositiveError, "ratio #{ratio} is not > 0" unless ratio > 0 x = Math.log2 ratio new(cent: (x * CENTS_PER_OCTAVE).round) end |
.from_semitones(semitones) ⇒ Object
113 114 115 |
# File 'lib/musicality/notation/model/pitch.rb', line 113 def self.from_semitones semitones Pitch.new(cent: (semitones * CENTS_PER_SEMITONE).round) end |
.pc_str(semitone, sharpit) ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/musicality/notation/model/pitch.rb', line 125 def self.pc_str semitone, sharpit case semitone when 0 then "C" when 1 then sharpit ? "C#" : "Db" when 2 then "D" when 3 then sharpit ? "D#" : "Eb" when 4 then "E" when 5 then "F" when 6 then sharpit ? "F#" : "Gb" when 7 then "G" when 8 then sharpit ? "G#" : "Ab" when 9 then "A" when 10 then sharpit ? "A#" : "Bb" when 11 then "B" end end |
Instance Method Details
#+(semitones) ⇒ Object
101 102 103 |
# File 'lib/musicality/notation/model/pitch.rb', line 101 def + semitones transpose(semitones) end |
#-(semitones) ⇒ Object
105 106 107 |
# File 'lib/musicality/notation/model/pitch.rb', line 105 def - semitones transpose(-semitones) end |
#<=>(other) ⇒ Object
Compare pitches. A higher ratio or total semitone is considered larger.
79 80 81 |
# File 'lib/musicality/notation/model/pitch.rb', line 79 def <=> (other) @total_cents <=> other.total_cents end |
#==(other) ⇒ Object
Compare pitch equality using total semitone
68 69 70 71 |
# File 'lib/musicality/notation/model/pitch.rb', line 68 def ==(other) return (self.class == other.class && @total_cents == other.total_cents) end |
#clone ⇒ Object
117 118 119 |
# File 'lib/musicality/notation/model/pitch.rb', line 117 def clone Pitch.new(cent: @total_cents) end |
#diff(other) ⇒ Object
diff in (rounded) semitones
93 94 95 |
# File 'lib/musicality/notation/model/pitch.rb', line 93 def diff other Rational(@total_cents - other.total_cents, CENTS_PER_SEMITONE) end |
#eql?(other) ⇒ Boolean
73 74 75 |
# File 'lib/musicality/notation/model/pitch.rb', line 73 def eql?(other) self == other end |
#freq ⇒ Object
Return the pitch’s frequency, which is determined by multiplying the base frequency and the pitch ratio. Base frequency defaults to DEFAULT_BASE_FREQ, but can be set during initialization to something else by specifying the :base_freq key.
51 52 53 |
# File 'lib/musicality/notation/model/pitch.rb', line 51 def freq return self.ratio() * BASE_FREQ end |
#hash ⇒ Object
Override default hash method.
63 64 65 |
# File 'lib/musicality/notation/model/pitch.rb', line 63 def hash return @total_cents end |
#natural? ⇒ Boolean
121 122 123 |
# File 'lib/musicality/notation/model/pitch.rb', line 121 def natural? [0,2,4,5,7,9,11].include?(semitone) end |
#ratio ⇒ Float
Calculate the pitch ratio. Raises 2 to the power of the total cent count divided by cents-per-octave.
58 59 60 |
# File 'lib/musicality/notation/model/pitch.rb', line 58 def ratio 2.0**(@total_cents.to_f / CENTS_PER_OCTAVE) end |
#round ⇒ Object
rounds to the nearest semitone
84 85 86 87 88 89 90 |
# File 'lib/musicality/notation/model/pitch.rb', line 84 def round if @cent == 0 self.clone else Pitch.new(semitone: (@total_cents / CENTS_PER_SEMITONE.to_f).round) end end |
#to_lilypond(sharpit = false) ⇒ Object
4 5 6 7 8 9 10 11 12 13 14 |
# File 'lib/musicality/printing/lilypond/pitch_engraving.rb', line 4 def to_lilypond sharpit = false output = PitchClass.to_lilypond(semitone, sharpit) if octave > 3 output += "'"*(octave - 3) elsif octave < 3 output += ","*(3 - octave) end return output end |
#to_pc ⇒ Object
16 17 18 |
# File 'lib/musicality/pitch_class.rb', line 16 def to_pc PitchClass.from_i semitone end |
#to_s(sharpit = false) ⇒ Object
142 143 144 145 146 147 148 149 150 151 |
# File 'lib/musicality/notation/model/pitch.rb', line 142 def to_s(sharpit = false) letter = Pitch.pc_str(semitone, sharpit) if @cent == 0 return letter + octave.to_s elsif @cent > 0 return letter + octave.to_s + "+" + @cent.to_s else return letter + octave.to_s + @cent.to_s end end |
#total_semitones ⇒ Object
109 110 111 |
# File 'lib/musicality/notation/model/pitch.rb', line 109 def total_semitones Rational(@total_cents, CENTS_PER_SEMITONE) end |
#transpose(semitones) ⇒ Object
97 98 99 |
# File 'lib/musicality/notation/model/pitch.rb', line 97 def transpose semitones Pitch.new(cent: (@total_cents + semitones * CENTS_PER_SEMITONE).round) end |