class SPCore::Oscillator

A generic oscillator base class, which can render a sample for any phase between -PI and +PI.

@author James Tunnell

Constants

ARG_SPECS

Used to process hashed arguments in initialize.

K_SAWTOOTH_A

constant used to calculate sawtooth wave

K_SINE_B

constant used to calculate sine wave

K_SINE_C

constant used to calculate sine wave

K_SINE_P

Q = 0.775 constant used to calculate sine wave

K_TRIANGLE_A

constant used to calculate triangle wave

WAVES

Defines a list of the valid wave types.

WAVE_SAWTOOTH

Defines a sawtooth wave type.

WAVE_SINE

Defines a sine wave type.

WAVE_SQUARE

Defines a square wave type.

WAVE_TRIANGLE

Defines a triangle wave type.

Attributes

amplitude[RW]
dc_offset[RW]
frequency[R]
phase_offset[R]
sample_rate[R]
wave_type[RW]

Public Class Methods

new(args) click to toggle source

A new instance of Oscillator. The controllable wave parameters are frequency, amplitude, phase offset, and DC offset. The current phase angle is initialized to the given phase offset.

@param [Hash] args Hashed arguments. Required key is :sample_rate. Optional keys are

:wave_type, :frequency, :amplitude, :phase_offset, and :dc_offset.
See ARG_SPECS for more details.
# File lib/spcore/generation/oscillator.rb, line 40
def initialize args
  hash_make args, Oscillator::ARG_SPECS
  
  @phase_angle_incr = (@frequency * TWO_PI) / @sample_rate
  @current_phase_angle = @phase_offset
end

Public Instance Methods

frequency=(frequency) click to toggle source

Set the frequency (also updates the rate at which phase angle increments).

# File lib/spcore/generation/oscillator.rb, line 56
def frequency= frequency
  raise ArgumentError, "frequency is not > 0" unless frequency > 0
  @frequency = frequency
  @phase_angle_incr = (@frequency * TWO_PI) / @sample_rate
end
phase_offset=(phase_offset) click to toggle source

Set the phase angle offset. Update the current phase angle according to the difference between the current phase offset and the new phase offset.

# File lib/spcore/generation/oscillator.rb, line 64
def phase_offset= phase_offset
  @current_phase_angle += (phase_offset - @phase_offset);
  @phase_offset = phase_offset
end
sample() click to toggle source

Step forward one sampling period and sample the oscillator waveform.

# File lib/spcore/generation/oscillator.rb, line 70
def sample
  output = 0.0

  while(@current_phase_angle < -Math::PI)
    @current_phase_angle += TWO_PI
  end

  while(@current_phase_angle > Math::PI)
    @current_phase_angle -= TWO_PI
  end

  case @wave_type
  when WAVE_SINE
    output = @amplitude * sine(@current_phase_angle) + @dc_offset
  when WAVE_TRIANGLE
    output = @amplitude * triangle(@current_phase_angle) + @dc_offset
  when WAVE_SQUARE
    output = @amplitude * square(@current_phase_angle) + @dc_offset
  when WAVE_SAWTOOTH
    output = @amplitude * sawtooth(@current_phase_angle) + @dc_offset
  else
    raise "Encountered unexpected wave type #{@wave_type}"
  end
  
  @current_phase_angle += @phase_angle_incr
  return output
end
sample_rate=(sample_rate) click to toggle source

Set the sample rate (also updates the rate at which phase angle increments). @raise [ArgumentError] if sample rate is not positive.

# File lib/spcore/generation/oscillator.rb, line 49
def sample_rate= sample_rate
  raise ArgumentError, "sample_rate is not > 0" unless sample_rate > 0
  @sample_rate = sample_rate
  self.frequency = @frequency
end
sawtooth(x) click to toggle source

generate a sawtooth wave: input range: -PI to PI ouput range: -1 to 1

# File lib/spcore/generation/oscillator.rb, line 142
def sawtooth x
  K_SAWTOOTH_A * x
end
sine(x) click to toggle source

generate a sine wave: input range: -PI to PI ouput range: -1 to 1

# File lib/spcore/generation/oscillator.rb, line 109
def sine x
  y = K_SINE_B * x + K_SINE_C * x * x.abs
  # for extra precision
  y = K_SINE_P * (y * y.abs - y) + y   # Q * y + P * y * y.abs
  
  # sin normally output outputs -1 to 1, so to adjust
  # it to output 0 to 1, return (y*0.5)+0.5
  return y
end
square(x) click to toggle source

generate a square wave (50% duty cycle): input range: -PI to PI ouput range: 0 to 1

# File lib/spcore/generation/oscillator.rb, line 132
def square x
  (x >= 0.0) ? 1.0 : -1.0
end
triangle(x) click to toggle source

generate a triangle wave: input range: -PI to PI ouput range: -1 to 1

# File lib/spcore/generation/oscillator.rb, line 125
def triangle x
  (K_TRIANGLE_A * x).abs - 1.0
end