Class: Deftones::Source::Oscillator

Inherits:
Core::Source show all
Defined in:
lib/deftones/source/oscillator.rb

Direct Known Subclasses

Component::LFO, ToneOscillatorNode

Constant Summary collapse

TYPES =
%i[sine square sawtooth triangle].freeze
GENERATORS =
{
  sine: ->(phase) { Math.sin(2.0 * Math::PI * phase) },
  square: ->(phase) { phase < 0.5 ? 1.0 : -1.0 },
  sawtooth: ->(phase) { (2.0 * phase) - 1.0 },
  triangle: ->(phase) { (4.0 * (phase < 0.5 ? phase : 1.0 - phase)) - 1.0 }
}.freeze

Instance Attribute Summary collapse

Attributes inherited from Core::Source

#mute, #onstop, #volume

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Core::Source

#active_at?, #apply_volume!, #cancel_stop, #clear_transport_event, #dispose, #mute?, #notify_stop_in_window, #number_of_inputs, #render, #render_block, #resolve_time, #resolve_transport_time, #restart, #schedule_transport_event, #source_type, #start, #state, #stop, #sync, #synced?, #unsync, #uses_legacy_render_for_block?

Constructor Details

#initialize(type: :sine, frequency: 440.0, detune: 0.0, phase: 0.0, context: Deftones.context) ⇒ Oscillator

Returns a new instance of Oscillator.



79
80
81
82
83
84
85
# File 'lib/deftones/source/oscillator.rb', line 79

def initialize(type: :sine, frequency: 440.0, detune: 0.0, phase: 0.0, context: Deftones.context)
  super(context: context)
  self.type = type
  @frequency = Core::Signal.new(value: frequency, units: :frequency, context: context)
  @detune = Core::Signal.new(value: detune, units: :number, context: context)
  self.phase = phase
end

Instance Attribute Details

#detuneObject

Returns the value of attribute detune.



77
78
79
# File 'lib/deftones/source/oscillator.rb', line 77

def detune
  @detune
end

#frequencyObject (readonly)

Returns the value of attribute frequency.



77
78
79
# File 'lib/deftones/source/oscillator.rb', line 77

def frequency
  @frequency
end

#typeObject

Returns the value of attribute type.



77
78
79
# File 'lib/deftones/source/oscillator.rb', line 77

def type
  @type
end

Class Method Details

.bandlimited_sawtooth(phase, phase_increment) ⇒ Object (private)



37
38
39
# File 'lib/deftones/source/oscillator.rb', line 37

def bandlimited_sawtooth(phase, phase_increment)
  ((2.0 * phase) - 1.0) - poly_blep(phase, phase_increment)
end

.bandlimited_square(phase, phase_increment) ⇒ Object (private)



30
31
32
33
34
35
# File 'lib/deftones/source/oscillator.rb', line 30

def bandlimited_square(phase, phase_increment)
  sample = phase < 0.5 ? 1.0 : -1.0
  sample += poly_blep(phase, phase_increment)
  sample -= poly_blep((phase + 0.5) % 1.0, phase_increment)
  sample
end

.bandlimited_triangle(phase, phase_increment) ⇒ Object (private)



41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/deftones/source/oscillator.rb', line 41

def bandlimited_triangle(phase, phase_increment)
  return naive_triangle(phase) unless phase_increment.positive?

  max_harmonic = (0.5 / phase_increment.abs).floor
  return naive_triangle(phase) if max_harmonic < 1

  sum = 0.0
  harmonic = 1
  while harmonic <= max_harmonic
    sum += Math.cos(2.0 * Math::PI * harmonic * phase) / (harmonic * harmonic)
    harmonic += 2
  end
  -(8.0 / (Math::PI * Math::PI)) * sum
end

.naive_triangle(phase) ⇒ Object (private)



56
57
58
# File 'lib/deftones/source/oscillator.rb', line 56

def naive_triangle(phase)
  (4.0 * (phase < 0.5 ? phase : 1.0 - phase)) - 1.0
end

.poly_blep(phase, phase_increment) ⇒ Object (private)



60
61
62
63
64
65
66
# File 'lib/deftones/source/oscillator.rb', line 60

def poly_blep(phase, phase_increment)
  increment = [phase_increment.abs, 1.0e-9].max
  return poly_blep_start(phase / increment) if phase < increment
  return poly_blep_end((phase - 1.0) / increment) if phase > 1.0 - increment

  0.0
end

.poly_blep_end(t) ⇒ Object (private)



72
73
74
# File 'lib/deftones/source/oscillator.rb', line 72

def poly_blep_end(t)
  (t * t) + (t + t) + 1.0
end

.poly_blep_start(t) ⇒ Object (private)



68
69
70
# File 'lib/deftones/source/oscillator.rb', line 68

def poly_blep_start(t)
  (t + t) - (t * t) - 1.0
end

.sample(type, phase, phase_increment = 0.0) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/deftones/source/oscillator.rb', line 15

def sample(type, phase, phase_increment = 0.0)
  case type
  when :sine
    Math.sin(2.0 * Math::PI * phase)
  when :square
    bandlimited_square(phase, phase_increment)
  when :sawtooth
    bandlimited_sawtooth(phase, phase_increment)
  when :triangle
    bandlimited_triangle(phase, phase_increment)
  end
end

Instance Method Details

#detune_ratio(cents) ⇒ Object (private)



126
127
128
# File 'lib/deftones/source/oscillator.rb', line 126

def detune_ratio(cents)
  2.0**(cents.to_f / 1200.0)
end

#normalize_type(type) ⇒ Object (private)

Raises:

  • (ArgumentError)


130
131
132
133
134
135
# File 'lib/deftones/source/oscillator.rb', line 130

def normalize_type(type)
  normalized = type.to_sym
  return normalized if TYPES.include?(normalized)

  raise ArgumentError, "Unsupported oscillator type: #{type}"
end

#phaseObject



91
92
93
# File 'lib/deftones/source/oscillator.rb', line 91

def phase
  @phase
end

#phase=(value) ⇒ Object



95
96
97
# File 'lib/deftones/source/oscillator.rb', line 95

def phase=(value)
  @phase = value.to_f % 1.0
end

#process(_input_buffer, num_frames, start_frame, _cache) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/deftones/source/oscillator.rb', line 103

def process(_input_buffer, num_frames, start_frame, _cache)
  oscillator_type = normalize_type(@type)
  frequencies = @frequency.process(num_frames, start_frame)
  detunes = @detune.process(num_frames, start_frame)

  Array.new(num_frames) do |index|
    current_time = (start_frame + index).to_f / context.sample_rate
    next 0.0 unless active_at?(current_time)

    frequency = frequencies[index] * detune_ratio(detunes[index])
    phase_increment = frequency / context.sample_rate
    sample = sample_for(oscillator_type, @phase, phase_increment)
    @phase = (@phase + phase_increment) % 1.0
    sample
  end
end

#sample_for(type, phase, phase_increment) ⇒ Object (private)



122
123
124
# File 'lib/deftones/source/oscillator.rb', line 122

def sample_for(type, phase, phase_increment)
  Oscillator.sample(type, phase, phase_increment)
end