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
Public Class Methods
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
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
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
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
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
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
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
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
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