Module: Cyclotone::Oscillators
- Defined in:
- lib/cyclotone/oscillators.rb
Class Method Summary collapse
- .bipolar(pattern) ⇒ Object
- .brownian(step: 0.1) ⇒ Object
- .cosine(freq: 1, phase: 0, bipolar: false) ⇒ Object
- .irand(maximum) ⇒ Object
- .isaw(freq: 1, phase: 0, bipolar: false) ⇒ Object
- .noise(steps: 128) ⇒ Object
- .perlin ⇒ Object
- .positive_integer(value, label) ⇒ Object
- .rand(steps: 128) ⇒ Object
- .range(low, high, pattern, mode: :raw) ⇒ Object
- .sample_and_hold(pattern, steps: 8) ⇒ Object
- .saw(freq: 1, phase: 0, bipolar: false) ⇒ Object
- .sine(freq: 1, phase: 0, bipolar: false) ⇒ Object
- .smooth(pattern, interpolator: nil, &block) ⇒ Object
- .square(freq: 1, phase: 0, bipolar: false) ⇒ Object
- .tri(freq: 1, phase: 0, bipolar: false) ⇒ Object
Class Method Details
.bipolar(pattern) ⇒ Object
74 75 76 |
# File 'lib/cyclotone/oscillators.rb', line 74 def bipolar(pattern) Pattern.ensure_pattern(pattern).fmap { |value| (value.to_f * 2.0) - 1.0 } end |
.brownian(step: 0.1) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/cyclotone/oscillators.rb', line 92 def brownian(step: 0.1) normalized_step = step.to_f raise ArgumentError, "brownian step must be positive" unless normalized_step.positive? cache = { -1 => 0.5 } highest_cycle = -1 Pattern.continuous do |time| cycle = time.floor while highest_cycle < cycle next_cycle = highest_cycle + 1 cache[next_cycle] = brownian_step(cache.fetch(highest_cycle), next_cycle, normalized_step) highest_cycle = next_cycle end cache.fetch(cycle, 0.5) end end |
.cosine(freq: 1, phase: 0, bipolar: false) ⇒ Object
13 14 15 16 17 |
# File 'lib/cyclotone/oscillators.rb', line 13 def cosine(freq: 1, phase: 0, bipolar: false) oscillator(freq: freq, phase_offset: phase, bipolar: bipolar) do |time| (Math.cos(phase(time)) + 1.0) / 2.0 end end |
.irand(maximum) ⇒ Object
48 49 50 51 52 |
# File 'lib/cyclotone/oscillators.rb', line 48 def irand(maximum) normalized_maximum = positive_integer(maximum, "irand maximum") rand.fmap { |value| (value * normalized_maximum).floor } end |
.isaw(freq: 1, phase: 0, bipolar: false) ⇒ Object
30 31 32 |
# File 'lib/cyclotone/oscillators.rb', line 30 def isaw(freq: 1, phase: 0, bipolar: false) oscillator(freq: freq, phase_offset: phase, bipolar: bipolar) { |time| 1.0 - cycle_position(time) } end |
.noise(steps: 128) ⇒ Object
78 79 80 |
# File 'lib/cyclotone/oscillators.rb', line 78 def noise(steps: 128) rand(steps: steps) end |
.perlin ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/cyclotone/oscillators.rb', line 54 def perlin Pattern.continuous do |time| left = time.floor right = left + 1 amount = cycle_position(time) smooth = amount * amount * (3.0 - (2.0 * amount)) left_value = Support::Deterministic.float(:perlin, left) right_value = Support::Deterministic.float(:perlin, right) left_value + ((right_value - left_value) * smooth) end end |
.positive_integer(value, label) ⇒ Object
167 168 169 170 171 172 173 174 |
# File 'lib/cyclotone/oscillators.rb', line 167 def positive_integer(value, label) normalized = Integer(value) raise ArgumentError, "#{label} must be positive" unless normalized.positive? normalized rescue ArgumentError, TypeError => error raise ArgumentError, "invalid #{label}: #{error.}" end |
.rand(steps: 128) ⇒ Object
38 39 40 41 42 43 44 45 46 |
# File 'lib/cyclotone/oscillators.rb', line 38 def rand(steps: 128) normalized_steps = positive_integer(steps, "rand steps") Pattern.continuous do |time| cycle = time.floor step = (cycle_position(time) * normalized_steps).floor.to_i Support::Deterministic.float(:rand, cycle, step) end end |
.range(low, high, pattern, mode: :raw) ⇒ Object
67 68 69 70 71 72 |
# File 'lib/cyclotone/oscillators.rb', line 67 def range(low, high, pattern, mode: :raw) Pattern.ensure_pattern(pattern).fmap do |value| normalized_value = normalize_range_value(value.to_f, mode) low.to_f + ((high.to_f - low.to_f) * normalized_value) end end |
.sample_and_hold(pattern, steps: 8) ⇒ Object
82 83 84 85 86 87 88 89 90 |
# File 'lib/cyclotone/oscillators.rb', line 82 def sample_and_hold(pattern, steps: 8) normalized_steps = positive_integer(steps, "sample_and_hold steps") source = Pattern.ensure_pattern(pattern) Pattern.continuous do |time| sampled_time = Rational((time * normalized_steps).floor, normalized_steps) source.query_point(sampled_time) end end |
.saw(freq: 1, phase: 0, bipolar: false) ⇒ Object
26 27 28 |
# File 'lib/cyclotone/oscillators.rb', line 26 def saw(freq: 1, phase: 0, bipolar: false) oscillator(freq: freq, phase_offset: phase, bipolar: bipolar) { |time| cycle_position(time) } end |
.sine(freq: 1, phase: 0, bipolar: false) ⇒ Object
7 8 9 10 11 |
# File 'lib/cyclotone/oscillators.rb', line 7 def sine(freq: 1, phase: 0, bipolar: false) oscillator(freq: freq, phase_offset: phase, bipolar: bipolar) do |time| (Math.sin(phase(time)) + 1.0) / 2.0 end end |
.smooth(pattern, interpolator: nil, &block) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/cyclotone/oscillators.rb', line 112 def smooth(pattern, interpolator: nil, &block) source = Pattern.ensure_pattern(pattern) return source if source.continuous? interpolation = block || interpolator cache = {} Pattern.continuous do |time| rational_time = Pattern.to_rational(time) cache.fetch(rational_time) do cache[rational_time] = interpolate(source, rational_time, interpolation) cache.shift if cache.length > 256 cache[rational_time] end end end |
.square(freq: 1, phase: 0, bipolar: false) ⇒ Object
34 35 36 |
# File 'lib/cyclotone/oscillators.rb', line 34 def square(freq: 1, phase: 0, bipolar: false) oscillator(freq: freq, phase_offset: phase, bipolar: bipolar) { |time| cycle_position(time) < 0.5 ? 0.0 : 1.0 } end |
.tri(freq: 1, phase: 0, bipolar: false) ⇒ Object
19 20 21 22 23 24 |
# File 'lib/cyclotone/oscillators.rb', line 19 def tri(freq: 1, phase: 0, bipolar: false) oscillator(freq: freq, phase_offset: phase, bipolar: bipolar) do |time| position = cycle_position(time) position < 0.5 ? position * 2.0 : (1.0 - position) * 2.0 end end |