class MTK::Core::Duration

A measure of time in musical beats. May be negative to indicate a rest, which uses the absolute value for the effective duration.

@see Lang::Durations

Constants

NAMES

The names of the base durations. See {MTK::Lang::Durations} for more info.

VALUES_BY_NAME

Attributes

value[R]

The number of beats, typically represented as a Rational

Public Class Methods

[](length_in_beats) click to toggle source

Return a duration, only constructing a new instance when not already in the flyweight cache

# File lib/mtk/core/duration.rb, line 35
def self.[](length_in_beats)
  if length_in_beats.is_a? Fixnum
    value = length_in_beats
  else
    value = Rational(length_in_beats)
  end
  @flyweight[value] ||= new(value)
end
Also aliased as: from_f, from_i
from_f(length_in_beats)
Alias for: []
from_i(length_in_beats)
Alias for: []
from_name(s)
Alias for: from_s
from_s(s) click to toggle source

Lookup a duration by name. This method supports appending any combination of ‘.’ and ‘t’ for more fine-grained values. each ‘.’ multiplies by 3/2, and each ‘t’ multiplies by 2/3. You may use the prefix ‘-’ to negate the duration (which turns it into a rest of the same length). You may also prefix (after the ‘-’ if present) the base duration name with an integer, float, or rational number to multiply the base duration value. Rationals are in the form “#!{numerator_integer}/#!{denominator_integer}”. @example lookup value of ‘q.’, which is 1.5 times a quarter note (1.5 beats):

MTK::Core::Duration.from_s('q.')

@example lookup the value of 3/4w, which three-quarters of a whole note (3 beats):

MTK::Core::Duration.from_s('3/4w')
# File lib/mtk/core/duration.rb, line 59
def self.from_s(s)
  if s =~ /^(-)?(\d+([\.\/]\d+)?)?([whqesrx])((\.|t)*)$/i
    name = $4.downcase
    modifier = $5.downcase
    modifier << $1 if $1 # negation
    multiplier = $2
  else
    raise ArgumentError.new("Invalid Duration string '#{s}'")
  end

  value = VALUES_BY_NAME[name]
  modifier.each_char do |mod|
    case mod
      when '-' then value *= -1
      when '.' then value *= Rational(3,2)
      when 't' then value *= Rational(2,3)
    end
  end

  if multiplier
    case multiplier
      when /\./
        value *= multiplier.to_f
      when /\//
        numerator, denominator = multiplier.split('/')
        value *= Rational(numerator.to_i, denominator.to_i)
      else
        value *= multiplier.to_i
    end
  end

  self[value]
end
Also aliased as: from_name
new( length_in_beats ) click to toggle source
# File lib/mtk/core/duration.rb, line 30
def initialize( length_in_beats )
  @value = length_in_beats
end

Public Instance Methods

*(duration) click to toggle source

Multiply this duration with another. @return a new Duration that has a value of the product of the arguments.

# File lib/mtk/core/duration.rb, line 182
def * duration
  if duration.is_a? MTK::Core::Duration
    MTK::Core::Duration[@value * duration.value]
  else
    MTK::Core::Duration[@value * duration]
  end
end
+(duration) click to toggle source

Add this duration to another. @return a new Duration that has a value of the sum of the arguments.

# File lib/mtk/core/duration.rb, line 162
def + duration
  if duration.is_a? MTK::Core::Duration
    MTK::Core::Duration[@value + duration.value]
  else
    MTK::Core::Duration[@value + duration]
  end
end
-(duration) click to toggle source

Subtract another duration from this one. @return a new Duration that has a value of the difference of the arguments.

# File lib/mtk/core/duration.rb, line 172
def - duration
  if duration.is_a? MTK::Core::Duration
    MTK::Core::Duration[@value - duration.value]
  else
    MTK::Core::Duration[@value - duration]
  end
end
-@() click to toggle source

Negate the duration value. Turns normal durations into rests and vice versa. @return a new Duration that has a negated value. @see rest?

# File lib/mtk/core/duration.rb, line 204
def -@
  MTK::Core::Duration[@value * -1]
end
/(duration) click to toggle source

Divide this duration with another. @return a new Duration that has a value of the division of the arguments.

# File lib/mtk/core/duration.rb, line 192
def / duration
  if duration.is_a? MTK::Core::Duration
    MTK::Core::Duration[to_f / duration.value]
  else
    MTK::Core::Duration[to_f / duration]
  end
end
<=>(other) click to toggle source
# File lib/mtk/core/duration.rb, line 152
def <=> other
  if other.respond_to? :value
    @value <=> other.value
  else
    @value <=> other
  end
end
==( other ) click to toggle source
# File lib/mtk/core/duration.rb, line 144
def ==( other )
  if other.is_a? MTK::Core::Duration
    other.value == @value
  else
    other == @value
  end
end
abs() click to toggle source

Force resets to be non-rests, otherwise don’t change the duration. @see -@ @see length @see rest?

# File lib/mtk/core/duration.rb, line 116
def abs
  if @value < 0
    -self
  else
    self
  end
end
coerce(other) click to toggle source

Allow basic math operations with Numeric objects.

# File lib/mtk/core/duration.rb, line 209
def coerce(other)
  return MTK::Core::Duration[other], self
end
inspect() click to toggle source
# File lib/mtk/core/duration.rb, line 140
def inspect
  "#<#{self.class}:#{object_id} @value=#{@value}>"
end
length() click to toggle source

The magnitude (absolute value) of the duration. This is the actual duration for rests. @see rest? @see abs

# File lib/mtk/core/duration.rb, line 101
def length
  @value < 0 ? -@value : @value
end
rest?() click to toggle source

Durations with negative values are rests. @see length @see -@

# File lib/mtk/core/duration.rb, line 108
def rest?
  @value < 0
end
to_f() click to toggle source

The number of beats as a floating point number

# File lib/mtk/core/duration.rb, line 125
def to_f
  @value.to_f
end
to_i() click to toggle source

The numerical value for the nearest whole number of beats

# File lib/mtk/core/duration.rb, line 130
def to_i
  @value.round
end
to_s() click to toggle source
# File lib/mtk/core/duration.rb, line 134
def to_s
  value = @value.to_s
  value = sprintf '%.2f', @value if value.length > 6 # threshold is 6 for no particular reason...
  "#{value} #{@value.abs > 1 || @value==0 ? 'beats' : 'beat'}"
end