Class: Wavify::DSP::Oscillator
- Inherits:
-
Object
- Object
- Wavify::DSP::Oscillator
- Defined in:
- lib/wavify/dsp/oscillator.rb,
sig/dsp.rbs
Overview
Oscillator and noise source generator.
Constant Summary collapse
- WAVEFORMS =
Supported waveform symbols.
%i[sine square sawtooth triangle pulse white_noise pink_noise].freeze
- SINE_TABLE_SIZE =
Sample count in the interpolated sine wavetable.
2_048- SINE_WAVETABLE =
Shared sine cycle used by the eager generation hot path.
Array.new(SINE_TABLE_SIZE) do |index| Math.sin(2.0 * Math::PI * index / SINE_TABLE_SIZE) end.freeze
- TRIANGLE_TABLE_SIZE =
Sample count in each band-limited triangle wavetable.
2_048- TRIANGLE_MAX_HARMONIC =
Highest odd harmonic considered when building triangle tables.
255- TRIANGLE_TABLE_CACHE_LIMIT =
Maximum number of sample-rate/frequency-specific tables retained.
8- MAX_DURATION_SECONDS =
Maximum duration accepted by one eager generation call.
3_600.0- MAX_GENERATE_FRAMES =
Maximum number of frames allocated by one eager generation call.
50_000_000- MAX_FREQUENCY =
Absolute input guard before output-format Nyquist validation.
1_000_000.0- MAX_UNISON =
Maximum number of detuned oscillator voices.
64
Instance Method Summary collapse
-
#each_sample(format:) ⇒ Enumerator<Float>
Returns a stateful infinite enumerator of mono sample values.
-
#generate(duration_seconds, format:) ⇒ Wavify::Core::SampleBuffer
Generates the next finite sample buffer in the requested format.
-
#initialize(waveform:, frequency:, amplitude: 1.0, phase: 0.0, pulse_width: 0.5, detune: 0.0, unison: 1, random: Random.new) ⇒ Oscillator
constructor
A new instance of Oscillator.
- #reset_phase(phase = @initial_phase) ⇒ Oscillator
Constructor Details
#initialize(waveform:, frequency:, amplitude: 1.0, phase: 0.0, pulse_width: 0.5, detune: 0.0, unison: 1, random: Random.new) ⇒ Oscillator
Returns a new instance of Oscillator.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/wavify/dsp/oscillator.rb', line 31 def initialize(waveform:, frequency:, amplitude: 1.0, phase: 0.0, pulse_width: 0.5, detune: 0.0, unison: 1, random: Random.new) @waveform = validate_waveform!(waveform) @frequency = validate_frequency!(frequency) @amplitude = validate_amplitude!(amplitude) @initial_phase = validate_phase!(phase) @voice_phases = nil @voice_frequencies = nil @sample_rate = nil @pulse_width = validate_pulse_width!(pulse_width) @detune = validate_detune!(detune) @unison = validate_unison!(unison) @random = random @triangle_tables = {} reset_pink_noise! end |
Instance Method Details
#each_sample(format:) ⇒ Enumerator<Float>
Returns a stateful infinite enumerator of mono sample values.
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/wavify/dsp/oscillator.rb', line 91 def each_sample(format:) validate_format!(format) prepare_sample_rate!(format.sample_rate) Enumerator.new do |yielder| loop do value = noise_waveform? ? scaled_noise_sample : next_periodic_sample(format.sample_rate) yielder << value end end end |
#generate(duration_seconds, format:) ⇒ Wavify::Core::SampleBuffer
Generates the next finite sample buffer in the requested format. Calls are stateful and continue oscillator phase. Call #reset_phase before changing sample rate or when repeatable output is required.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/wavify/dsp/oscillator.rb', line 64 def generate(duration_seconds, format:) validate_format!(format) prepare_sample_rate!(format.sample_rate) unless duration_seconds.is_a?(Numeric) && duration_seconds.respond_to?(:finite?) && duration_seconds.finite? && duration_seconds.between?(0.0, MAX_DURATION_SECONDS) raise InvalidParameterError, "duration_seconds must be a finite Numeric in 0.0..#{MAX_DURATION_SECONDS}" end sample_frames = (duration_seconds.to_f * format.sample_rate).round if sample_frames > MAX_GENERATE_FRAMES raise InvalidParameterError, "generation is limited to #{MAX_GENERATE_FRAMES} sample frames" end samples = Array.new(sample_frames * format.channels) if @waveform == :sine generate_sine_samples!(samples, sample_frames, format.channels, format.sample_rate) else generate_samples!(samples, sample_frames, format.channels, format.sample_rate) end Core::SampleBuffer.new(samples, format) end |
#reset_phase(phase = @initial_phase) ⇒ Oscillator
48 49 50 51 52 53 54 55 |
# File 'lib/wavify/dsp/oscillator.rb', line 48 def reset_phase(phase = @initial_phase) @initial_phase = validate_phase!(phase) @voice_phases = nil @voice_frequencies = nil @sample_rate = nil reset_pink_noise! self end |