lib/music-transcription/model/pitch.rb in music-transcription-0.13.0 vs lib/music-transcription/model/pitch.rb in music-transcription-0.14.0

- old
+ new

@@ -41,51 +41,24 @@ # :base_freq key. def freq return self.ratio() * BASE_FREQ end - # Set the pitch according to the given frequency. Uses the current base_freq - # to determine what the pitch ratio should be, and sets it accordingly. - def freq= freq - self.ratio = freq / BASE_FREQ - end - # Calculate the total semitone count. Converts octave to semitone count # before adding to existing semitone count. # @return [Fixnum] total semitone count def total_semitone return (@octave * SEMITONES_PER_OCTAVE) + @semitone end - # Set the Pitch ratio according to a total number of semitones. - # @param [Fixnum] semitone The total number of semitones to use. - # @raise [NonIntegerError] if semitone is not an Integer - def total_semitone= semitone - unless semitone.is_a?(Integer) - raise NonIntegerError, "semitone #{semitone} is not a Integer" - end - @octave, @semitone = 0, semitone - normalize! - end - # Calculate the pitch ratio. Raises 2 to the power of the total semitone # count divided by semitones-per-octave. # @return [Float] ratio def ratio 2.0**(self.total_semitone.to_f / SEMITONES_PER_OCTAVE) end - # Represent the Pitch ratio according to a ratio. - # @param [Numeric] ratio The ratio to represent. - # @raise [NonPositiveError] unless ratio is > 0 - def ratio= ratio - raise NonPositiveError, "ratio #{ratio} is not > 0" unless ratio > 0 - - x = Math.log2 ratio - self.total_semitone = (x * SEMITONES_PER_OCTAVE).round - end - # Round to the nearest semitone. def round self.clone.round! end @@ -117,41 +90,34 @@ end # Add pitches by adding the total semitone count of each. # @param [Pitch] other The pitch object to add. def + (other) - self.class.new( - octave: (@octave + other.octave), - semitone: (@semitone + other.semitone) - ) + if other.is_a? Integer + return Pitch.new(octave: @octave, semitone: @semitone + other) + else + return Pitch.new(octave: (@octave + other.octave), + semitone: (@semitone + other.semitone)) + end end # Add pitches by subtracting the total semitone count. # @param [Pitch] other The pitch object to subtract. def - (other) - self.class.new( - octave: (@octave - other.octave), - semitone: (@semitone - other.semitone), - ) + if other.is_a? Integer + return Pitch.new(octave: @octave, semitone: @semitone - other) + else + return Pitch.new(octave: (@octave - other.octave), + semitone: (@semitone - other.semitone)) + end end # Produce an identical Pitch object. def clone Marshal.load(Marshal.dump(self)) # is this cheating? end - # Balance out the octave and semitone count. - def normalize! - semitoneTotal = (@octave * SEMITONES_PER_OCTAVE) + @semitone - - @octave = semitoneTotal / SEMITONES_PER_OCTAVE - semitoneTotal -= @octave * SEMITONES_PER_OCTAVE - - @semitone = semitoneTotal - return self - end - def to_s(sharpit = false) letter = case semitone when 0 then "C" when 1 then sharpit ? "C#" : "Db" when 2 then "D" @@ -167,19 +133,35 @@ end return letter + octave.to_s end - def self.make_from_freq(freq) - pitch = Pitch.new() - pitch.ratio = freq / BASE_FREQ - return pitch + def self.from_ratio ratio + raise NonPositiveError, "ratio #{ratio} is not > 0" unless ratio > 0 + x = Math.log2 ratio + semitones = (x * SEMITONES_PER_OCTAVE).round + from_semitones(semitones) end - def self.make_from_semitone semitones - pitch = Pitch.new() - pitch.total_semitone = semitones - return pitch + def self.from_freq freq + from_ratio(freq / BASE_FREQ) + end + + def self.from_semitones semitones + Pitch.new(semitone: semitones) + end + + private + + # Balance out the octave and semitone count. + def normalize! + semitoneTotal = (@octave * SEMITONES_PER_OCTAVE) + @semitone + + @octave = semitoneTotal / SEMITONES_PER_OCTAVE + semitoneTotal -= @octave * SEMITONES_PER_OCTAVE + + @semitone = semitoneTotal + return self end end end end