Class: Deftones::Instrument::Sampler
Instance Attribute Summary collapse
#mute, #output, #volume
#context, #input
Instance Method Summary
collapse
-
#add(note, buffer) ⇒ Object
-
#choke_matching_voices(time) ⇒ Object
private
-
#closest_sample(note) ⇒ Object
private
-
#dispose ⇒ Object
-
#get(note) ⇒ Object
-
#has?(note) ⇒ Boolean
-
#initialize(samples:, max_voices: 8, release: 0.0, one_shot: false, choke_group: nil, context: Deftones.context) ⇒ Sampler
constructor
A new instance of Sampler.
-
#loaded? ⇒ Boolean
(also: #loaded)
-
#play(notes, duration: "8n", at: nil, velocity: 1.0) ⇒ Object
-
#rebuild_root_note_cache ⇒ Object
private
-
#release_all(time = nil, force: false) ⇒ Object
(also: #releaseAll)
-
#resolve_time(time) ⇒ Object
private
-
#steal_oldest_voice(time) ⇒ Object
private
-
#trigger_attack(note, time = nil, velocity = 1.0) ⇒ Object
-
#trigger_attack_release(note, duration, time = nil, velocity = 1.0) ⇒ Object
(also: #triggerAttackRelease)
-
#trigger_release(note, time = nil) ⇒ Object
#apply_volume!, #input, #mute?, #render, #render_block, #set, #triggerAttack, #triggerRelease
#>>, #attach_destination, #attach_source, #block_time, #chain, #channel_count, #channel_count_mode, #channel_interpretation, #connect, #connected?, #default_input_channels, #default_output_channels, #destination_for_connection, #detach_all_destinations, #detach_destination, #detach_source, #disconnect, #disposed?, #fan, #immediate, #input_for_index, #inputs, #mix_source_blocks, #multichannel_process?, #name, #normalize_connection_index, #normalize_output_block, #now, #number_of_inputs, #number_of_outputs, #output, #output_for_connection, #output_for_index, #outputs, #process, #raise_connection_index_error!, #reaches_node?, #render, #render_block, #sample_time, #set, #to_destination, #to_frequency, #to_master, #to_midi, #to_output, #to_s, #to_seconds, #to_ticks, #uses_legacy_render_for_block?, #validate_connectable!, #validate_connection_index!
Constructor Details
#initialize(samples:, max_voices: 8, release: 0.0, one_shot: false, choke_group: nil, context: Deftones.context) ⇒ Sampler
Returns a new instance of Sampler.
9
10
11
12
13
14
15
16
17
18
19
|
# File 'lib/deftones/instrument/sampler.rb', line 9
def initialize(samples:, max_voices: 8, release: 0.0, one_shot: false, choke_group: nil,
context: Deftones.context)
super(context: context)
@samples = samples.transform_keys(&:to_s)
@max_voices = max_voices
@release = release.to_f
@one_shot = !!one_shot
@choke_group = choke_group
@voices = []
rebuild_root_note_cache
end
|
Instance Attribute Details
#choke_group ⇒ Object
Returns the value of attribute choke_group.
6
7
8
|
# File 'lib/deftones/instrument/sampler.rb', line 6
def choke_group
@choke_group
end
|
#one_shot ⇒ Object
Also known as:
oneShot
Returns the value of attribute one_shot.
7
8
9
|
# File 'lib/deftones/instrument/sampler.rb', line 7
def one_shot
@one_shot
end
|
#release ⇒ Object
Returns the value of attribute release.
6
7
8
|
# File 'lib/deftones/instrument/sampler.rb', line 6
def release
@release
end
|
#samples ⇒ Object
Returns the value of attribute samples.
6
7
8
|
# File 'lib/deftones/instrument/sampler.rb', line 6
def samples
@samples
end
|
#voices ⇒ Object
Returns the value of attribute voices.
6
7
8
|
# File 'lib/deftones/instrument/sampler.rb', line 6
def voices
@voices
end
|
Instance Method Details
#add(note, buffer) ⇒ Object
58
59
60
61
62
|
# File 'lib/deftones/instrument/sampler.rb', line 58
def add(note, buffer)
@samples[note.to_s] = buffer.is_a?(Deftones::IO::Buffer) ? buffer : Deftones::IO::Buffer.load(buffer)
rebuild_root_note_cache
self
end
|
#choke_matching_voices(time) ⇒ Object
115
116
117
118
119
120
121
122
123
124
125
|
# File 'lib/deftones/instrument/sampler.rb', line 115
def choke_matching_voices(time)
return unless @choke_group
@voices.delete_if do |voice|
next false unless voice[:choke_group] == @choke_group
voice[:player].stop(time)
voice[:player].dispose
true
end
end
|
#closest_sample(note) ⇒ Object
97
98
99
100
101
102
103
104
|
# File 'lib/deftones/instrument/sampler.rb', line 97
def closest_sample(note)
raise ArgumentError, "Sampler requires at least one sample" if @samples.empty?
target_midi = Deftones::Music::Note.to_midi(note)
@samples.min_by do |sample_note, _|
(@root_note_cache.fetch(sample_note) - target_midi).abs
end
end
|
#dispose ⇒ Object
84
85
86
87
88
|
# File 'lib/deftones/instrument/sampler.rb', line 84
def dispose
release_all(context.current_time, force: true)
@voices.clear
super
end
|
#get(note) ⇒ Object
64
65
66
|
# File 'lib/deftones/instrument/sampler.rb', line 64
def get(note)
@samples[note.to_s]
end
|
#has?(note) ⇒ Boolean
68
69
70
|
# File 'lib/deftones/instrument/sampler.rb', line 68
def has?(note)
@samples.key?(note.to_s)
end
|
#loaded? ⇒ Boolean
Also known as:
loaded
80
81
82
|
# File 'lib/deftones/instrument/sampler.rb', line 80
def loaded?
!disposed?
end
|
#play(notes, duration: "8n", at: nil, velocity: 1.0) ⇒ Object
21
22
23
24
25
26
27
|
# File 'lib/deftones/instrument/sampler.rb', line 21
def play(notes, duration: "8n", at: nil, velocity: 1.0)
Array(notes).each do |note|
trigger_attack(note, at, velocity)
trigger_release(note, resolve_time(at) + Deftones::Music::Time.parse(duration))
end
self
end
|
#rebuild_root_note_cache ⇒ Object
127
128
129
130
131
|
# File 'lib/deftones/instrument/sampler.rb', line 127
def rebuild_root_note_cache
@root_note_cache = @samples.each_key.to_h do |sample_note|
[sample_note, Deftones::Music::Note.to_midi(sample_note)]
end
end
|
#release_all(time = nil, force: false) ⇒ Object
Also known as:
releaseAll
72
73
74
75
76
77
78
|
# File 'lib/deftones/instrument/sampler.rb', line 72
def release_all(time = nil, force: false)
scheduled_time = resolve_time(time)
return self if @one_shot && !force
@voices.each { |voice| voice[:player].stop(scheduled_time) }
self
end
|
#resolve_time(time) ⇒ Object
133
134
135
136
137
|
# File 'lib/deftones/instrument/sampler.rb', line 133
def resolve_time(time)
return context.current_time if time.nil?
Deftones::Music::Time.parse(time)
end
|
#steal_oldest_voice(time) ⇒ Object
106
107
108
109
110
111
112
113
|
# File 'lib/deftones/instrument/sampler.rb', line 106
def steal_oldest_voice(time)
stolen = @voices.shift
return unless stolen
player = stolen[:player]
player.stop(time)
player.dispose
end
|
#trigger_attack(note, time = nil, velocity = 1.0) ⇒ Object
29
30
31
32
33
34
35
36
37
38
39
40
41
|
# File 'lib/deftones/instrument/sampler.rb', line 29
def trigger_attack(note, time = nil, velocity = 1.0)
buffer_note, buffer = closest_sample(note)
scheduled_time = resolve_time(time)
choke_matching_voices(scheduled_time)
playback_rate = Deftones::Music::Note.to_frequency(note) / Deftones::Music::Note.to_frequency(buffer_note)
player = Source::Player.new(buffer: buffer, playback_rate: playback_rate, fade_out: @release, context: context)
gain = Core::Gain.new(gain: velocity, context: context)
player >> gain >> @output
player.start(scheduled_time)
@voices << { note: note, player: player, choke_group: @choke_group }
steal_oldest_voice(scheduled_time) if @voices.length > @max_voices
self
end
|
#trigger_attack_release(note, duration, time = nil, velocity = 1.0) ⇒ Object
Also known as:
triggerAttackRelease
51
52
53
54
55
56
|
# File 'lib/deftones/instrument/sampler.rb', line 51
def trigger_attack_release(note, duration, time = nil, velocity = 1.0)
scheduled_time = resolve_time(time)
trigger_attack(note, scheduled_time, velocity)
trigger_release(note, scheduled_time + Deftones::Music::Time.parse(duration))
self
end
|
#trigger_release(note, time = nil) ⇒ Object
43
44
45
46
47
48
49
|
# File 'lib/deftones/instrument/sampler.rb', line 43
def trigger_release(note, time = nil)
return self if @one_shot
voice = @voices.find { |entry| entry[:note] == note }
voice&.fetch(:player)&.stop(resolve_time(time))
self
end
|