deftones 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +12 -0
- data/LICENSE.txt +21 -0
- data/README.md +197 -0
- data/Rakefile +8 -0
- data/examples/poly_chord.rb +14 -0
- data/examples/render_sampler.rb +16 -0
- data/examples/render_sequence.rb +13 -0
- data/examples/render_synth.rb +18 -0
- data/lib/deftones/analysis/analyser.rb +162 -0
- data/lib/deftones/analysis/dc_meter.rb +56 -0
- data/lib/deftones/analysis/fft.rb +128 -0
- data/lib/deftones/analysis/meter.rb +83 -0
- data/lib/deftones/analysis/waveform.rb +93 -0
- data/lib/deftones/component/amplitude_envelope.rb +8 -0
- data/lib/deftones/component/biquad_filter.rb +7 -0
- data/lib/deftones/component/channel.rb +109 -0
- data/lib/deftones/component/compressor.rb +64 -0
- data/lib/deftones/component/convolver.rb +99 -0
- data/lib/deftones/component/cross_fade.rb +67 -0
- data/lib/deftones/component/envelope.rb +160 -0
- data/lib/deftones/component/eq3.rb +73 -0
- data/lib/deftones/component/feedback_comb_filter.rb +75 -0
- data/lib/deftones/component/filter.rb +75 -0
- data/lib/deftones/component/follower.rb +55 -0
- data/lib/deftones/component/frequency_envelope.rb +24 -0
- data/lib/deftones/component/gate.rb +46 -0
- data/lib/deftones/component/lfo.rb +88 -0
- data/lib/deftones/component/limiter.rb +11 -0
- data/lib/deftones/component/lowpass_comb_filter.rb +43 -0
- data/lib/deftones/component/merge.rb +45 -0
- data/lib/deftones/component/mid_side_compressor.rb +43 -0
- data/lib/deftones/component/mid_side_merge.rb +53 -0
- data/lib/deftones/component/mid_side_split.rb +54 -0
- data/lib/deftones/component/mono.rb +8 -0
- data/lib/deftones/component/multiband_compressor.rb +70 -0
- data/lib/deftones/component/multiband_split.rb +133 -0
- data/lib/deftones/component/one_pole_filter.rb +71 -0
- data/lib/deftones/component/pan_vol.rb +26 -0
- data/lib/deftones/component/panner.rb +75 -0
- data/lib/deftones/component/panner3d.rb +322 -0
- data/lib/deftones/component/solo.rb +56 -0
- data/lib/deftones/component/split.rb +47 -0
- data/lib/deftones/component/volume.rb +31 -0
- data/lib/deftones/context.rb +213 -0
- data/lib/deftones/core/audio_block.rb +82 -0
- data/lib/deftones/core/audio_node.rb +262 -0
- data/lib/deftones/core/clock.rb +91 -0
- data/lib/deftones/core/computed_signal.rb +69 -0
- data/lib/deftones/core/delay.rb +44 -0
- data/lib/deftones/core/effect.rb +66 -0
- data/lib/deftones/core/emitter.rb +51 -0
- data/lib/deftones/core/gain.rb +39 -0
- data/lib/deftones/core/instrument.rb +109 -0
- data/lib/deftones/core/param.rb +31 -0
- data/lib/deftones/core/signal.rb +452 -0
- data/lib/deftones/core/signal_operator_methods.rb +73 -0
- data/lib/deftones/core/signal_operators.rb +138 -0
- data/lib/deftones/core/signal_shapers.rb +83 -0
- data/lib/deftones/core/source.rb +213 -0
- data/lib/deftones/core/synced_signal.rb +88 -0
- data/lib/deftones/destination.rb +132 -0
- data/lib/deftones/draw.rb +100 -0
- data/lib/deftones/dsp/biquad.rb +129 -0
- data/lib/deftones/dsp/delay_line.rb +41 -0
- data/lib/deftones/dsp/helpers.rb +25 -0
- data/lib/deftones/effect/auto_filter.rb +92 -0
- data/lib/deftones/effect/auto_panner.rb +57 -0
- data/lib/deftones/effect/auto_wah.rb +98 -0
- data/lib/deftones/effect/bit_crusher.rb +38 -0
- data/lib/deftones/effect/chebyshev.rb +36 -0
- data/lib/deftones/effect/chorus.rb +73 -0
- data/lib/deftones/effect/distortion.rb +22 -0
- data/lib/deftones/effect/feedback_delay.rb +38 -0
- data/lib/deftones/effect/freeverb.rb +11 -0
- data/lib/deftones/effect/frequency_shifter.rb +89 -0
- data/lib/deftones/effect/jc_reverb.rb +11 -0
- data/lib/deftones/effect/modulation_control.rb +159 -0
- data/lib/deftones/effect/phaser.rb +72 -0
- data/lib/deftones/effect/ping_pong_delay.rb +40 -0
- data/lib/deftones/effect/pitch_shift.rb +156 -0
- data/lib/deftones/effect/reverb.rb +71 -0
- data/lib/deftones/effect/stereo_widener.rb +34 -0
- data/lib/deftones/effect/tremolo.rb +52 -0
- data/lib/deftones/effect/vibrato.rb +47 -0
- data/lib/deftones/event/callback_behavior.rb +61 -0
- data/lib/deftones/event/loop.rb +53 -0
- data/lib/deftones/event/part.rb +51 -0
- data/lib/deftones/event/pattern.rb +94 -0
- data/lib/deftones/event/sequence.rb +87 -0
- data/lib/deftones/event/tone_event.rb +77 -0
- data/lib/deftones/event/transport.rb +276 -0
- data/lib/deftones/instrument/am_synth.rb +56 -0
- data/lib/deftones/instrument/duo_synth.rb +68 -0
- data/lib/deftones/instrument/fm_synth.rb +60 -0
- data/lib/deftones/instrument/membrane_synth.rb +60 -0
- data/lib/deftones/instrument/metal_synth.rb +61 -0
- data/lib/deftones/instrument/mono_synth.rb +88 -0
- data/lib/deftones/instrument/noise_synth.rb +56 -0
- data/lib/deftones/instrument/pluck_synth.rb +41 -0
- data/lib/deftones/instrument/poly_synth.rb +96 -0
- data/lib/deftones/instrument/sampler.rb +97 -0
- data/lib/deftones/instrument/synth.rb +60 -0
- data/lib/deftones/io/buffer.rb +352 -0
- data/lib/deftones/io/buffers.rb +77 -0
- data/lib/deftones/io/recorder.rb +89 -0
- data/lib/deftones/listener.rb +120 -0
- data/lib/deftones/music/frequency.rb +128 -0
- data/lib/deftones/music/midi.rb +206 -0
- data/lib/deftones/music/note.rb +58 -0
- data/lib/deftones/music/ticks.rb +106 -0
- data/lib/deftones/music/time.rb +209 -0
- data/lib/deftones/music/transport_time.rb +94 -0
- data/lib/deftones/music/unit_helpers.rb +30 -0
- data/lib/deftones/offline_context.rb +46 -0
- data/lib/deftones/portaudio_support.rb +112 -0
- data/lib/deftones/source/am_oscillator.rb +42 -0
- data/lib/deftones/source/fat_oscillator.rb +49 -0
- data/lib/deftones/source/fm_oscillator.rb +47 -0
- data/lib/deftones/source/grain_player.rb +198 -0
- data/lib/deftones/source/karplus_strong.rb +51 -0
- data/lib/deftones/source/noise.rb +99 -0
- data/lib/deftones/source/omni_oscillator.rb +175 -0
- data/lib/deftones/source/oscillator.rb +74 -0
- data/lib/deftones/source/player.rb +228 -0
- data/lib/deftones/source/players.rb +133 -0
- data/lib/deftones/source/pulse_oscillator.rb +38 -0
- data/lib/deftones/source/pwm_oscillator.rb +49 -0
- data/lib/deftones/source/tone_buffer_source.rb +136 -0
- data/lib/deftones/source/tone_oscillator_node.rb +65 -0
- data/lib/deftones/source/user_media.rb +519 -0
- data/lib/deftones/version.rb +5 -0
- data/lib/deftones.rb +542 -0
- metadata +221 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deftones
|
|
4
|
+
module Effects
|
|
5
|
+
class StereoWidener < Core::Effect
|
|
6
|
+
attr_accessor :width
|
|
7
|
+
|
|
8
|
+
def initialize(width: 0.5, context: Deftones.context, **options)
|
|
9
|
+
super(context: context, **options)
|
|
10
|
+
@width = width.to_f
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def process_effect_block(input_block, num_frames, _start_frame, _cache)
|
|
16
|
+
stereo_input = input_block.fit_channels(2)
|
|
17
|
+
width = @width.to_f.clamp(0.0, 1.0)
|
|
18
|
+
left = Array.new(num_frames)
|
|
19
|
+
right = Array.new(num_frames)
|
|
20
|
+
|
|
21
|
+
num_frames.times do |index|
|
|
22
|
+
left_sample = stereo_input.channel_data[0][index]
|
|
23
|
+
right_sample = stereo_input.channel_data[1][index]
|
|
24
|
+
mid = (left_sample + right_sample) * (1.0 - width)
|
|
25
|
+
side = (left_sample - right_sample) * width
|
|
26
|
+
left[index] = mid + side
|
|
27
|
+
right[index] = mid - side
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
Core::AudioBlock.from_channel_data([left, right])
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deftones
|
|
4
|
+
module Effects
|
|
5
|
+
class Tremolo < Core::Effect
|
|
6
|
+
include ModulationControl
|
|
7
|
+
|
|
8
|
+
attr_accessor :frequency, :depth, :spread, :type
|
|
9
|
+
|
|
10
|
+
def initialize(frequency: 5.0, depth: 0.8, spread: 0.0, type: :sine, context: Deftones.context, **options)
|
|
11
|
+
super(context: context, wet: 1.0, **options)
|
|
12
|
+
@frequency = frequency.to_f
|
|
13
|
+
@depth = depth.to_f
|
|
14
|
+
@spread = spread.to_f
|
|
15
|
+
@type = normalize_modulation_type(type)
|
|
16
|
+
@phase = 0.0
|
|
17
|
+
initialize_modulation_control
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def process_effect_block(input_block, num_frames, start_frame, _cache)
|
|
23
|
+
output_channels = [input_block.channels, 2].max
|
|
24
|
+
source = input_block.fit_channels(output_channels)
|
|
25
|
+
output = Array.new(output_channels) { Array.new(num_frames, 0.0) }
|
|
26
|
+
|
|
27
|
+
num_frames.times do |index|
|
|
28
|
+
current_time = (start_frame + index).to_f / context.sample_rate
|
|
29
|
+
base_phase = modulation_phase_for(current_time)
|
|
30
|
+
|
|
31
|
+
output_channels.times do |channel_index|
|
|
32
|
+
phase = base_phase.nil? ? nil : base_phase + channel_phase_offset(channel_index, output_channels)
|
|
33
|
+
output[channel_index][index] = source.channel_data[channel_index][index] * channel_gain_for_phase(phase)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
Core::AudioBlock.from_channel_data(output)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def channel_phase_offset(channel_index, channels)
|
|
41
|
+
return 0.0 if channels <= 1
|
|
42
|
+
|
|
43
|
+
(@spread / 360.0) * (channel_index.to_f / [channels - 1, 1].max)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def channel_gain_for_phase(phase)
|
|
47
|
+
modulation = unipolar_modulation_value(phase, default: 1.0)
|
|
48
|
+
1.0 - (@depth * (1.0 - modulation))
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deftones
|
|
4
|
+
module Effects
|
|
5
|
+
class Vibrato < Core::Effect
|
|
6
|
+
include ModulationControl
|
|
7
|
+
|
|
8
|
+
attr_accessor :frequency, :depth, :type
|
|
9
|
+
|
|
10
|
+
def initialize(frequency: 5.0, depth: 0.002, type: :sine, context: Deftones.context, **options)
|
|
11
|
+
super(context: context, wet: 1.0, **options)
|
|
12
|
+
@frequency = frequency.to_f
|
|
13
|
+
@depth = depth.to_f
|
|
14
|
+
@type = normalize_modulation_type(type)
|
|
15
|
+
@phase = 0.0
|
|
16
|
+
@delay_lines = []
|
|
17
|
+
initialize_modulation_control
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def process_effect_block(input_block, num_frames, start_frame, _cache)
|
|
23
|
+
ensure_delay_lines(input_block.channels)
|
|
24
|
+
output = Array.new(input_block.channels) { Array.new(num_frames, 0.0) }
|
|
25
|
+
|
|
26
|
+
num_frames.times do |index|
|
|
27
|
+
current_time = (start_frame + index).to_f / context.sample_rate
|
|
28
|
+
phase = modulation_phase_for(current_time)
|
|
29
|
+
modulation = unipolar_modulation_value(phase, default: 0.5)
|
|
30
|
+
delay_samples = (0.01 + (@depth * modulation)) * context.sample_rate
|
|
31
|
+
input_block.channel_data.each_with_index do |channel, channel_index|
|
|
32
|
+
output[channel_index][index] = @delay_lines[channel_index].tap(delay_samples, input_sample: channel[index])
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Core::AudioBlock.from_channel_data(output)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def ensure_delay_lines(channels)
|
|
40
|
+
required = [channels.to_i, 1].max
|
|
41
|
+
while @delay_lines.length < required
|
|
42
|
+
@delay_lines << DSP::DelayLine.new((0.05 * context.sample_rate).ceil)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deftones
|
|
4
|
+
module Event
|
|
5
|
+
module CallbackBehavior
|
|
6
|
+
attr_accessor :humanize, :mute, :playback_rate, :probability
|
|
7
|
+
attr_reader :state
|
|
8
|
+
|
|
9
|
+
def mute?
|
|
10
|
+
@mute
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
alias playbackRate playback_rate
|
|
14
|
+
|
|
15
|
+
def playbackRate=(value)
|
|
16
|
+
self.playback_rate = value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def initialize_callback_behavior(probability: 1.0, humanize: false, mute: false, playback_rate: 1.0)
|
|
22
|
+
@probability = probability.to_f
|
|
23
|
+
@humanize = humanize
|
|
24
|
+
@mute = !!mute
|
|
25
|
+
@playback_rate = playback_rate.to_f
|
|
26
|
+
@state = :stopped
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def mark_started
|
|
30
|
+
@state = :started
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def mark_stopped
|
|
34
|
+
@state = :stopped
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def callback_interval(value)
|
|
38
|
+
base = Deftones::Music::Time.parse(value)
|
|
39
|
+
rate = @playback_rate.zero? ? 1.0 : @playback_rate.abs
|
|
40
|
+
base / rate
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def callback_time(value)
|
|
44
|
+
Deftones::Music::Time.parse(value)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def callback_permitted?
|
|
48
|
+
return false if @mute
|
|
49
|
+
|
|
50
|
+
rand <= @probability
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def humanized_time(time)
|
|
54
|
+
return time unless @humanize
|
|
55
|
+
|
|
56
|
+
amount = @humanize == true ? 0.01 : Deftones::Music::Time.parse(@humanize)
|
|
57
|
+
time + (((rand * 2.0) - 1.0) * amount)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deftones
|
|
4
|
+
module Event
|
|
5
|
+
class Loop
|
|
6
|
+
include CallbackBehavior
|
|
7
|
+
|
|
8
|
+
attr_reader :interval, :iterations
|
|
9
|
+
|
|
10
|
+
def initialize(interval:, iterations: nil, transport: Deftones.transport,
|
|
11
|
+
probability: 1.0, humanize: false, mute: false, playback_rate: 1.0, &callback)
|
|
12
|
+
@interval = interval
|
|
13
|
+
@iterations = iterations
|
|
14
|
+
@transport = transport
|
|
15
|
+
@callback = callback
|
|
16
|
+
@event_id = nil
|
|
17
|
+
initialize_callback_behavior(
|
|
18
|
+
probability: probability,
|
|
19
|
+
humanize: humanize,
|
|
20
|
+
mute: mute,
|
|
21
|
+
playback_rate: playback_rate
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def start(time = 0)
|
|
26
|
+
count = 0
|
|
27
|
+
scaled_interval = callback_interval(@interval)
|
|
28
|
+
duration = @iterations ? (scaled_interval * (@iterations - 1)) : nil
|
|
29
|
+
@event_id = @transport.schedule_repeat(scaled_interval, start_time: time, duration: duration) do |scheduled_time|
|
|
30
|
+
@callback.call(humanized_time(scheduled_time)) if callback_permitted?
|
|
31
|
+
count += 1
|
|
32
|
+
end
|
|
33
|
+
mark_started
|
|
34
|
+
self
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def stop(_time = nil)
|
|
38
|
+
cancel
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def cancel
|
|
42
|
+
@transport.cancel(event_id: @event_id) if @event_id
|
|
43
|
+
@event_id = nil
|
|
44
|
+
mark_stopped
|
|
45
|
+
self
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def dispose
|
|
49
|
+
cancel
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deftones
|
|
4
|
+
module Event
|
|
5
|
+
class Part
|
|
6
|
+
include CallbackBehavior
|
|
7
|
+
|
|
8
|
+
def initialize(events:, transport: Deftones.transport,
|
|
9
|
+
probability: 1.0, humanize: false, mute: false, playback_rate: 1.0, &callback)
|
|
10
|
+
@events = events
|
|
11
|
+
@transport = transport
|
|
12
|
+
@callback = callback
|
|
13
|
+
@event_ids = []
|
|
14
|
+
initialize_callback_behavior(
|
|
15
|
+
probability: probability,
|
|
16
|
+
humanize: humanize,
|
|
17
|
+
mute: mute,
|
|
18
|
+
playback_rate: playback_rate
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def start(time = 0)
|
|
23
|
+
offset = callback_time(time)
|
|
24
|
+
@event_ids = @events.map do |event|
|
|
25
|
+
event_time = offset + callback_interval(event.fetch(:time, 0))
|
|
26
|
+
@transport.schedule(event_time) do |scheduled_time|
|
|
27
|
+
@callback.call(humanized_time(scheduled_time), event) if callback_permitted?
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
mark_started
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def stop(_time = nil)
|
|
35
|
+
cancel
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def cancel
|
|
39
|
+
@event_ids.each { |event_id| @transport.cancel(event_id: event_id) }
|
|
40
|
+
@event_ids.clear
|
|
41
|
+
mark_stopped
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def dispose
|
|
46
|
+
cancel
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deftones
|
|
4
|
+
module Event
|
|
5
|
+
class Pattern
|
|
6
|
+
include CallbackBehavior
|
|
7
|
+
|
|
8
|
+
PATTERNS = %i[up down up_down random].freeze
|
|
9
|
+
|
|
10
|
+
def initialize(values:, pattern: :up, interval: "4n", transport: Deftones.transport,
|
|
11
|
+
probability: 1.0, humanize: false, mute: false, playback_rate: 1.0, &callback)
|
|
12
|
+
@values = values
|
|
13
|
+
@pattern = normalize_pattern(pattern)
|
|
14
|
+
@interval = interval
|
|
15
|
+
@transport = transport
|
|
16
|
+
@callback = callback
|
|
17
|
+
@event_id = nil
|
|
18
|
+
@index = 0
|
|
19
|
+
@direction = 1
|
|
20
|
+
initialize_callback_behavior(
|
|
21
|
+
probability: probability,
|
|
22
|
+
humanize: humanize,
|
|
23
|
+
mute: mute,
|
|
24
|
+
playback_rate: playback_rate
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def start(time = 0)
|
|
29
|
+
@event_id = @transport.schedule_repeat(callback_interval(@interval), start_time: time) do |scheduled_time|
|
|
30
|
+
@callback.call(humanized_time(scheduled_time), next_value) if callback_permitted?
|
|
31
|
+
end
|
|
32
|
+
mark_started
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def stop(_time = nil)
|
|
37
|
+
cancel
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def cancel
|
|
41
|
+
@transport.cancel(event_id: @event_id) if @event_id
|
|
42
|
+
@event_id = nil
|
|
43
|
+
mark_stopped
|
|
44
|
+
self
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def dispose
|
|
48
|
+
cancel
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def next_value
|
|
54
|
+
case @pattern
|
|
55
|
+
when :up
|
|
56
|
+
ordered_value
|
|
57
|
+
when :down
|
|
58
|
+
descending_value
|
|
59
|
+
when :up_down
|
|
60
|
+
bounce_value
|
|
61
|
+
when :random
|
|
62
|
+
@values.sample
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def ordered_value
|
|
67
|
+
value = @values[@index % @values.length]
|
|
68
|
+
@index += 1
|
|
69
|
+
value
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def descending_value
|
|
73
|
+
value = @values.reverse[@index % @values.length]
|
|
74
|
+
@index += 1
|
|
75
|
+
value
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def bounce_value
|
|
79
|
+
value = @values[@index]
|
|
80
|
+
@direction = -1 if @index >= @values.length - 1
|
|
81
|
+
@direction = 1 if @index <= 0
|
|
82
|
+
@index += @direction
|
|
83
|
+
value
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def normalize_pattern(pattern)
|
|
87
|
+
normalized = pattern.to_sym
|
|
88
|
+
return normalized if PATTERNS.include?(normalized)
|
|
89
|
+
|
|
90
|
+
raise ArgumentError, "Unsupported pattern: #{pattern}"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deftones
|
|
4
|
+
module Event
|
|
5
|
+
class Sequence
|
|
6
|
+
include Enumerable
|
|
7
|
+
include CallbackBehavior
|
|
8
|
+
|
|
9
|
+
def initialize(notes:, subdivision: "4n", loop: true, transport: Deftones.transport,
|
|
10
|
+
probability: 1.0, humanize: false, mute: false, playback_rate: 1.0, &callback)
|
|
11
|
+
@notes = notes
|
|
12
|
+
@subdivision = subdivision
|
|
13
|
+
@loop = loop
|
|
14
|
+
@transport = transport
|
|
15
|
+
@callback = callback
|
|
16
|
+
@event_id = nil
|
|
17
|
+
@current_step = 0
|
|
18
|
+
initialize_callback_behavior(
|
|
19
|
+
probability: probability,
|
|
20
|
+
humanize: humanize,
|
|
21
|
+
mute: mute,
|
|
22
|
+
playback_rate: playback_rate
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def start(time = 0)
|
|
27
|
+
@current_step = 0
|
|
28
|
+
scaled_subdivision = callback_interval(@subdivision)
|
|
29
|
+
duration = @loop ? nil : (scaled_subdivision * (@notes.length - 1))
|
|
30
|
+
@event_id = @transport.schedule_repeat(scaled_subdivision, start_time: time, duration: duration) do |scheduled_time|
|
|
31
|
+
process_step(scheduled_time)
|
|
32
|
+
@current_step += 1
|
|
33
|
+
end
|
|
34
|
+
mark_started
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def stop(_time = nil)
|
|
39
|
+
cancel
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def cancel
|
|
43
|
+
@transport.cancel(event_id: @event_id) if @event_id
|
|
44
|
+
@event_id = nil
|
|
45
|
+
mark_stopped
|
|
46
|
+
self
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def dispose
|
|
50
|
+
cancel
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def [](index)
|
|
54
|
+
@notes[index]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def []=(index, value)
|
|
58
|
+
@notes[index] = value
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def each(&block)
|
|
62
|
+
return enum_for(:each) unless block
|
|
63
|
+
|
|
64
|
+
@notes.each(&block)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def process_step(scheduled_time)
|
|
70
|
+
note = @notes[@current_step % @notes.length]
|
|
71
|
+
return if note.nil?
|
|
72
|
+
return unless callback_permitted?
|
|
73
|
+
|
|
74
|
+
if note.is_a?(Array)
|
|
75
|
+
sub_duration = callback_interval(@subdivision) / note.length.to_f
|
|
76
|
+
note.each_with_index do |nested_note, index|
|
|
77
|
+
next if nested_note.nil?
|
|
78
|
+
|
|
79
|
+
@callback.call(humanized_time(scheduled_time + (sub_duration * index)), nested_note)
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
@callback.call(humanized_time(scheduled_time), note)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Deftones
|
|
4
|
+
module Event
|
|
5
|
+
class ToneEvent
|
|
6
|
+
include CallbackBehavior
|
|
7
|
+
|
|
8
|
+
attr_accessor :loop, :loop_start, :loop_end, :probability
|
|
9
|
+
|
|
10
|
+
def initialize(transport: Deftones.transport, probability: 1.0, loop: false,
|
|
11
|
+
loop_start: 0.0, loop_end: nil, humanize: false, mute: false, playback_rate: 1.0, &callback)
|
|
12
|
+
@transport = transport
|
|
13
|
+
@callback = callback
|
|
14
|
+
@loop = loop
|
|
15
|
+
@loop_start = loop_start
|
|
16
|
+
@loop_end = loop_end
|
|
17
|
+
@event_id = nil
|
|
18
|
+
initialize_callback_behavior(
|
|
19
|
+
probability: probability,
|
|
20
|
+
humanize: humanize,
|
|
21
|
+
mute: mute,
|
|
22
|
+
playback_rate: playback_rate
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def start(time = 0)
|
|
27
|
+
start_time = resolve_time(time)
|
|
28
|
+
|
|
29
|
+
@event_id =
|
|
30
|
+
if @loop && @loop_end
|
|
31
|
+
interval = callback_interval(resolve_time(@loop_end) - resolve_time(@loop_start))
|
|
32
|
+
@transport.schedule_repeat(interval, start_time: start_time + resolve_time(@loop_start)) do |scheduled_time|
|
|
33
|
+
@callback.call(humanized_time(scheduled_time)) if callback_permitted?
|
|
34
|
+
end
|
|
35
|
+
else
|
|
36
|
+
@transport.schedule(start_time) do |scheduled_time|
|
|
37
|
+
@callback.call(humanized_time(scheduled_time)) if callback_permitted?
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
mark_started
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def stop(_time = nil)
|
|
45
|
+
cancel
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def cancel
|
|
49
|
+
@transport.cancel(event_id: @event_id) if @event_id
|
|
50
|
+
@event_id = nil
|
|
51
|
+
mark_stopped
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def dispose
|
|
56
|
+
cancel
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
alias loopStart loop_start
|
|
60
|
+
alias loopEnd loop_end
|
|
61
|
+
|
|
62
|
+
def loopStart=(value)
|
|
63
|
+
self.loop_start = value
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def loopEnd=(value)
|
|
67
|
+
self.loop_end = value
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def resolve_time(value)
|
|
73
|
+
Deftones::Music::Time.parse(value)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|