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.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/CHANGELOG.md +12 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +197 -0
  6. data/Rakefile +8 -0
  7. data/examples/poly_chord.rb +14 -0
  8. data/examples/render_sampler.rb +16 -0
  9. data/examples/render_sequence.rb +13 -0
  10. data/examples/render_synth.rb +18 -0
  11. data/lib/deftones/analysis/analyser.rb +162 -0
  12. data/lib/deftones/analysis/dc_meter.rb +56 -0
  13. data/lib/deftones/analysis/fft.rb +128 -0
  14. data/lib/deftones/analysis/meter.rb +83 -0
  15. data/lib/deftones/analysis/waveform.rb +93 -0
  16. data/lib/deftones/component/amplitude_envelope.rb +8 -0
  17. data/lib/deftones/component/biquad_filter.rb +7 -0
  18. data/lib/deftones/component/channel.rb +109 -0
  19. data/lib/deftones/component/compressor.rb +64 -0
  20. data/lib/deftones/component/convolver.rb +99 -0
  21. data/lib/deftones/component/cross_fade.rb +67 -0
  22. data/lib/deftones/component/envelope.rb +160 -0
  23. data/lib/deftones/component/eq3.rb +73 -0
  24. data/lib/deftones/component/feedback_comb_filter.rb +75 -0
  25. data/lib/deftones/component/filter.rb +75 -0
  26. data/lib/deftones/component/follower.rb +55 -0
  27. data/lib/deftones/component/frequency_envelope.rb +24 -0
  28. data/lib/deftones/component/gate.rb +46 -0
  29. data/lib/deftones/component/lfo.rb +88 -0
  30. data/lib/deftones/component/limiter.rb +11 -0
  31. data/lib/deftones/component/lowpass_comb_filter.rb +43 -0
  32. data/lib/deftones/component/merge.rb +45 -0
  33. data/lib/deftones/component/mid_side_compressor.rb +43 -0
  34. data/lib/deftones/component/mid_side_merge.rb +53 -0
  35. data/lib/deftones/component/mid_side_split.rb +54 -0
  36. data/lib/deftones/component/mono.rb +8 -0
  37. data/lib/deftones/component/multiband_compressor.rb +70 -0
  38. data/lib/deftones/component/multiband_split.rb +133 -0
  39. data/lib/deftones/component/one_pole_filter.rb +71 -0
  40. data/lib/deftones/component/pan_vol.rb +26 -0
  41. data/lib/deftones/component/panner.rb +75 -0
  42. data/lib/deftones/component/panner3d.rb +322 -0
  43. data/lib/deftones/component/solo.rb +56 -0
  44. data/lib/deftones/component/split.rb +47 -0
  45. data/lib/deftones/component/volume.rb +31 -0
  46. data/lib/deftones/context.rb +213 -0
  47. data/lib/deftones/core/audio_block.rb +82 -0
  48. data/lib/deftones/core/audio_node.rb +262 -0
  49. data/lib/deftones/core/clock.rb +91 -0
  50. data/lib/deftones/core/computed_signal.rb +69 -0
  51. data/lib/deftones/core/delay.rb +44 -0
  52. data/lib/deftones/core/effect.rb +66 -0
  53. data/lib/deftones/core/emitter.rb +51 -0
  54. data/lib/deftones/core/gain.rb +39 -0
  55. data/lib/deftones/core/instrument.rb +109 -0
  56. data/lib/deftones/core/param.rb +31 -0
  57. data/lib/deftones/core/signal.rb +452 -0
  58. data/lib/deftones/core/signal_operator_methods.rb +73 -0
  59. data/lib/deftones/core/signal_operators.rb +138 -0
  60. data/lib/deftones/core/signal_shapers.rb +83 -0
  61. data/lib/deftones/core/source.rb +213 -0
  62. data/lib/deftones/core/synced_signal.rb +88 -0
  63. data/lib/deftones/destination.rb +132 -0
  64. data/lib/deftones/draw.rb +100 -0
  65. data/lib/deftones/dsp/biquad.rb +129 -0
  66. data/lib/deftones/dsp/delay_line.rb +41 -0
  67. data/lib/deftones/dsp/helpers.rb +25 -0
  68. data/lib/deftones/effect/auto_filter.rb +92 -0
  69. data/lib/deftones/effect/auto_panner.rb +57 -0
  70. data/lib/deftones/effect/auto_wah.rb +98 -0
  71. data/lib/deftones/effect/bit_crusher.rb +38 -0
  72. data/lib/deftones/effect/chebyshev.rb +36 -0
  73. data/lib/deftones/effect/chorus.rb +73 -0
  74. data/lib/deftones/effect/distortion.rb +22 -0
  75. data/lib/deftones/effect/feedback_delay.rb +38 -0
  76. data/lib/deftones/effect/freeverb.rb +11 -0
  77. data/lib/deftones/effect/frequency_shifter.rb +89 -0
  78. data/lib/deftones/effect/jc_reverb.rb +11 -0
  79. data/lib/deftones/effect/modulation_control.rb +159 -0
  80. data/lib/deftones/effect/phaser.rb +72 -0
  81. data/lib/deftones/effect/ping_pong_delay.rb +40 -0
  82. data/lib/deftones/effect/pitch_shift.rb +156 -0
  83. data/lib/deftones/effect/reverb.rb +71 -0
  84. data/lib/deftones/effect/stereo_widener.rb +34 -0
  85. data/lib/deftones/effect/tremolo.rb +52 -0
  86. data/lib/deftones/effect/vibrato.rb +47 -0
  87. data/lib/deftones/event/callback_behavior.rb +61 -0
  88. data/lib/deftones/event/loop.rb +53 -0
  89. data/lib/deftones/event/part.rb +51 -0
  90. data/lib/deftones/event/pattern.rb +94 -0
  91. data/lib/deftones/event/sequence.rb +87 -0
  92. data/lib/deftones/event/tone_event.rb +77 -0
  93. data/lib/deftones/event/transport.rb +276 -0
  94. data/lib/deftones/instrument/am_synth.rb +56 -0
  95. data/lib/deftones/instrument/duo_synth.rb +68 -0
  96. data/lib/deftones/instrument/fm_synth.rb +60 -0
  97. data/lib/deftones/instrument/membrane_synth.rb +60 -0
  98. data/lib/deftones/instrument/metal_synth.rb +61 -0
  99. data/lib/deftones/instrument/mono_synth.rb +88 -0
  100. data/lib/deftones/instrument/noise_synth.rb +56 -0
  101. data/lib/deftones/instrument/pluck_synth.rb +41 -0
  102. data/lib/deftones/instrument/poly_synth.rb +96 -0
  103. data/lib/deftones/instrument/sampler.rb +97 -0
  104. data/lib/deftones/instrument/synth.rb +60 -0
  105. data/lib/deftones/io/buffer.rb +352 -0
  106. data/lib/deftones/io/buffers.rb +77 -0
  107. data/lib/deftones/io/recorder.rb +89 -0
  108. data/lib/deftones/listener.rb +120 -0
  109. data/lib/deftones/music/frequency.rb +128 -0
  110. data/lib/deftones/music/midi.rb +206 -0
  111. data/lib/deftones/music/note.rb +58 -0
  112. data/lib/deftones/music/ticks.rb +106 -0
  113. data/lib/deftones/music/time.rb +209 -0
  114. data/lib/deftones/music/transport_time.rb +94 -0
  115. data/lib/deftones/music/unit_helpers.rb +30 -0
  116. data/lib/deftones/offline_context.rb +46 -0
  117. data/lib/deftones/portaudio_support.rb +112 -0
  118. data/lib/deftones/source/am_oscillator.rb +42 -0
  119. data/lib/deftones/source/fat_oscillator.rb +49 -0
  120. data/lib/deftones/source/fm_oscillator.rb +47 -0
  121. data/lib/deftones/source/grain_player.rb +198 -0
  122. data/lib/deftones/source/karplus_strong.rb +51 -0
  123. data/lib/deftones/source/noise.rb +99 -0
  124. data/lib/deftones/source/omni_oscillator.rb +175 -0
  125. data/lib/deftones/source/oscillator.rb +74 -0
  126. data/lib/deftones/source/player.rb +228 -0
  127. data/lib/deftones/source/players.rb +133 -0
  128. data/lib/deftones/source/pulse_oscillator.rb +38 -0
  129. data/lib/deftones/source/pwm_oscillator.rb +49 -0
  130. data/lib/deftones/source/tone_buffer_source.rb +136 -0
  131. data/lib/deftones/source/tone_oscillator_node.rb +65 -0
  132. data/lib/deftones/source/user_media.rb +519 -0
  133. data/lib/deftones/version.rb +5 -0
  134. data/lib/deftones.rb +542 -0
  135. metadata +221 -0
@@ -0,0 +1,276 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Event
5
+ class Transport
6
+ attr_accessor :loop, :loop_start, :loop_end, :swing
7
+ attr_reader :ppq, :state, :time_signature
8
+
9
+ TimingContext = Struct.new(:sample_rate) do
10
+ def current_time
11
+ 0.0
12
+ end
13
+ end
14
+
15
+ def initialize(bpm: 120.0, time_signature: [4, 4], ppq: 192)
16
+ @bpm = Core::Signal.new(
17
+ value: bpm,
18
+ units: :number,
19
+ context: TimingContext.new(Deftones::Context::DEFAULT_SAMPLE_RATE)
20
+ )
21
+ @ppq = ppq.to_i
22
+ @state = :stopped
23
+ self.time_signature = time_signature
24
+ @loop = false
25
+ @loop_start = 0.0
26
+ @loop_end = 0.0
27
+ @swing = 0.0
28
+ @swing_subdivision = "8n"
29
+ @timeline = {}
30
+ @next_id = 0
31
+ @started_at = 0.0
32
+ @position_seconds = 0.0
33
+ end
34
+
35
+ def bpm
36
+ @bpm.value
37
+ end
38
+
39
+ def bpm=(value)
40
+ @bpm.value = value
41
+ end
42
+
43
+ def swing_subdivision
44
+ @swing_subdivision
45
+ end
46
+
47
+ def swing_subdivision=(value)
48
+ @swing_subdivision = value
49
+ end
50
+
51
+ def ppq=(value)
52
+ @ppq = [value.to_i, 1].max
53
+ end
54
+
55
+ def start(time = nil)
56
+ @state = :started
57
+ @started_at = resolve_time(time)
58
+ self
59
+ end
60
+
61
+ def stop(time = nil)
62
+ @state = :stopped
63
+ @position_seconds = time.nil? ? seconds : resolve_time(time)
64
+ self
65
+ end
66
+
67
+ def pause(time = nil)
68
+ @state = :paused
69
+ @position_seconds = time.nil? ? seconds : resolve_time(time)
70
+ self
71
+ end
72
+
73
+ def position
74
+ seconds_to_position(@position_seconds)
75
+ end
76
+
77
+ def position=(value)
78
+ @position_seconds = resolve_time(value)
79
+ end
80
+
81
+ def seconds=(value)
82
+ @position_seconds = resolve_time(value)
83
+ end
84
+
85
+ def ticks
86
+ seconds_to_ticks(@position_seconds)
87
+ end
88
+
89
+ def ticks=(value)
90
+ parsed_ticks = Deftones::Music::Ticks.parse(value, bpm: bpm, time_signature: time_signature, ppq: @ppq)
91
+ @position_seconds = ticks_to_seconds(parsed_ticks)
92
+ end
93
+
94
+ def seconds
95
+ return @position_seconds unless @state == :started
96
+
97
+ [Deftones.now - @started_at, 0.0].max
98
+ end
99
+
100
+ def schedule(time, &block)
101
+ add_event(kind: :once, time: resolve_time(time), callback: block)
102
+ end
103
+
104
+ def schedule_once(time, &block)
105
+ schedule(time, &block)
106
+ end
107
+
108
+ def schedule_repeat(interval, start_time: 0, duration: nil, &block)
109
+ add_event(
110
+ kind: :repeat,
111
+ interval: resolve_time(interval),
112
+ start_time: resolve_time(start_time),
113
+ duration: duration.nil? ? nil : resolve_time(duration),
114
+ callback: block
115
+ )
116
+ end
117
+
118
+ def clear(event_id)
119
+ cancel(event_id: event_id)
120
+ end
121
+
122
+ def cancel(after_time = 0, event_id: nil)
123
+ return @timeline.delete(event_id) if event_id
124
+
125
+ threshold = resolve_time(after_time)
126
+ @timeline.delete_if do |_id, event|
127
+ event_time = event[:kind] == :repeat ? event[:start_time] : event[:time]
128
+ event_time >= threshold
129
+ end
130
+ self
131
+ end
132
+
133
+ def set_loop_points(start_time, end_time)
134
+ @loop_start = resolve_time(start_time)
135
+ @loop_end = resolve_time(end_time)
136
+ self
137
+ end
138
+
139
+ def toggle(time = nil)
140
+ @state == :started ? pause(time) : start(time)
141
+ end
142
+
143
+ def immediate
144
+ seconds
145
+ end
146
+
147
+ def progress
148
+ return nil unless @loop
149
+
150
+ loop_start_seconds = resolve_time(@loop_start)
151
+ loop_end_seconds = resolve_time(@loop_end)
152
+ span = loop_end_seconds - loop_start_seconds
153
+ return nil unless span.positive?
154
+
155
+ ((seconds - loop_start_seconds) % span) / span
156
+ end
157
+
158
+ def next_subdivision(subdivision)
159
+ interval = resolve_time(subdivision)
160
+ return nil unless interval.positive?
161
+
162
+ current = seconds
163
+ (((current / interval).floor) + 1) * interval
164
+ end
165
+
166
+ def time_signature=(signature)
167
+ @time_signature =
168
+ case signature
169
+ when Array then signature.map(&:to_i)
170
+ else [signature.to_i, 4]
171
+ end
172
+ end
173
+
174
+ def timeSignature
175
+ time_signature
176
+ end
177
+
178
+ def timeSignature=(signature)
179
+ self.time_signature = signature
180
+ end
181
+
182
+ def swingSubdivision
183
+ swing_subdivision
184
+ end
185
+
186
+ def swingSubdivision=(value)
187
+ self.swing_subdivision = value
188
+ end
189
+
190
+ def prepare_render(duration)
191
+ render_duration = resolve_time(duration)
192
+ due_events(render_duration).each do |event|
193
+ event[:callback].call(event[:time])
194
+ end
195
+ self
196
+ end
197
+
198
+ private
199
+
200
+ def add_event(payload)
201
+ event_id = @next_id
202
+ @timeline[event_id] = payload
203
+ @next_id += 1
204
+ event_id
205
+ end
206
+
207
+ def due_events(duration)
208
+ events = @timeline.flat_map do |_id, event|
209
+ event[:kind] == :repeat ? materialize_repeat_event(event, duration) : materialize_one_shot(event, duration)
210
+ end
211
+ events.sort_by { |event| event[:time] }
212
+ end
213
+
214
+ def materialize_one_shot(event, duration)
215
+ return [] if event[:time] > duration
216
+
217
+ [{ time: apply_swing(event[:time], event[:time]), callback: event[:callback] }]
218
+ end
219
+
220
+ def materialize_repeat_event(event, duration)
221
+ interval = [event[:interval], 1.0e-6].max
222
+ limit = event[:duration] ? [event[:start_time] + event[:duration], duration].min : duration
223
+ events = []
224
+ occurrence = 0
225
+ current_time = event[:start_time]
226
+
227
+ while current_time <= limit
228
+ actual_time = apply_swing(current_time, interval, occurrence)
229
+ events << { time: actual_time, callback: event[:callback] }
230
+ current_time += interval
231
+ occurrence += 1
232
+ end
233
+
234
+ events
235
+ end
236
+
237
+ def apply_swing(time, interval, occurrence = 0)
238
+ return time if @swing.zero?
239
+ return time if resolve_time(@swing_subdivision) != interval
240
+ return time if occurrence.even?
241
+
242
+ time + (interval * 0.5 * @swing)
243
+ end
244
+
245
+ def resolve_time(value)
246
+ return @position_seconds if value.nil?
247
+
248
+ Deftones::Music::Time.parse(value, bpm: bpm, time_signature: time_signature, ppq: @ppq)
249
+ end
250
+
251
+ def seconds_to_position(seconds)
252
+ beats_per_measure = Array(@time_signature).first || 4
253
+ beat_duration = 60.0 / bpm
254
+ total_beats = seconds.to_f / beat_duration
255
+ bars = (total_beats / beats_per_measure).floor
256
+ beats = (total_beats % beats_per_measure).floor
257
+ sixteenths = (((total_beats - total_beats.floor) / 0.25).round) % 4
258
+ "#{bars}:#{beats}:#{sixteenths}"
259
+ end
260
+
261
+ def seconds_to_ticks(seconds)
262
+ ((seconds.to_f / (60.0 / bpm)) * @ppq).round
263
+ end
264
+
265
+ def ticks_to_seconds(ticks)
266
+ (ticks.to_f / @ppq) * (60.0 / bpm)
267
+ end
268
+
269
+ public :seconds_to_position, :seconds_to_ticks, :ticks_to_seconds
270
+ alias scheduleOnce schedule_once
271
+ alias scheduleRepeat schedule_repeat
272
+ alias setLoopPoints set_loop_points
273
+ alias nextSubdivision next_subdivision
274
+ end
275
+ end
276
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Instrument
5
+ class AMSynth < Core::Instrument
6
+ attr_reader :oscillator, :envelope
7
+
8
+ def initialize(harmonicity: 2.0, attack: 0.01, decay: 0.08, sustain: 0.4, release: 0.3,
9
+ context: Deftones.context, &block)
10
+ super(context: context)
11
+ @oscillator = Source::AMOscillator.new(harmonicity: harmonicity, context: context)
12
+ @envelope = Component::AmplitudeEnvelope.new(
13
+ attack: attack,
14
+ decay: decay,
15
+ sustain: sustain,
16
+ release: release,
17
+ context: context
18
+ )
19
+ @oscillator.start(0.0)
20
+ @oscillator >> @envelope >> @output
21
+ block&.call(self)
22
+ end
23
+
24
+ def play(note, duration: "8n", at: nil, velocity: 1.0)
25
+ trigger_attack_release(note, duration, at, velocity)
26
+ end
27
+
28
+ def trigger_attack(note, time = nil, velocity = 1.0)
29
+ scheduled_time = resolve_time(time)
30
+ @oscillator.frequency.set_value_at_time(note, scheduled_time)
31
+ @envelope.trigger_attack(scheduled_time, velocity)
32
+ self
33
+ end
34
+
35
+ def trigger_release(time = nil)
36
+ @envelope.trigger_release(resolve_time(time))
37
+ self
38
+ end
39
+
40
+ def trigger_attack_release(note, duration, time = nil, velocity = 1.0)
41
+ scheduled_time = resolve_time(time)
42
+ trigger_attack(note, scheduled_time, velocity)
43
+ trigger_release(scheduled_time + Deftones::Music::Time.parse(duration))
44
+ self
45
+ end
46
+
47
+ private
48
+
49
+ def resolve_time(time)
50
+ return context.current_time if time.nil?
51
+
52
+ Deftones::Music::Time.parse(time)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Instrument
5
+ class DuoSynth < Core::Instrument
6
+ attr_reader :voice_a, :voice_b, :envelope
7
+
8
+ def initialize(type: :sawtooth, detune: 7.0, harmonicity: 1.5, attack: 0.01, decay: 0.12,
9
+ sustain: 0.45, release: 0.4, context: Deftones.context, &block)
10
+ super(context: context)
11
+ @voice_a = Source::OmniOscillator.new(type: type, context: context)
12
+ @voice_b = Source::OmniOscillator.new(type: type, context: context)
13
+ @detune = detune.to_f
14
+ @harmonicity = harmonicity.to_f
15
+ @envelope = Component::AmplitudeEnvelope.new(
16
+ attack: attack,
17
+ decay: decay,
18
+ sustain: sustain,
19
+ release: release,
20
+ context: context
21
+ )
22
+ @voice_a.start(0.0)
23
+ @voice_b.start(0.0)
24
+ @voice_a >> @envelope
25
+ @voice_b >> @envelope
26
+ @envelope >> @output
27
+ block&.call(self)
28
+ end
29
+
30
+ def play(note, duration: "8n", at: nil, velocity: 1.0)
31
+ trigger_attack_release(note, duration, at, velocity)
32
+ end
33
+
34
+ def trigger_attack(note, time = nil, velocity = 1.0)
35
+ scheduled_time = resolve_time(time)
36
+ frequency = Deftones::Music::Note.to_frequency(note)
37
+ @voice_a.frequency.set_value_at_time(frequency * detune_ratio(-@detune), scheduled_time)
38
+ @voice_b.frequency.set_value_at_time((frequency * @harmonicity) * detune_ratio(@detune), scheduled_time)
39
+ @envelope.trigger_attack(scheduled_time, velocity)
40
+ self
41
+ end
42
+
43
+ def trigger_release(time = nil)
44
+ @envelope.trigger_release(resolve_time(time))
45
+ self
46
+ end
47
+
48
+ def trigger_attack_release(note, duration, time = nil, velocity = 1.0)
49
+ scheduled_time = resolve_time(time)
50
+ trigger_attack(note, scheduled_time, velocity)
51
+ trigger_release(scheduled_time + Deftones::Music::Time.parse(duration))
52
+ self
53
+ end
54
+
55
+ private
56
+
57
+ def detune_ratio(cents)
58
+ 2.0**(cents.to_f / 1200.0)
59
+ end
60
+
61
+ def resolve_time(time)
62
+ return context.current_time if time.nil?
63
+
64
+ Deftones::Music::Time.parse(time)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Instrument
5
+ class FMSynth < Core::Instrument
6
+ attr_reader :oscillator, :envelope
7
+
8
+ def initialize(harmonicity: 2.0, modulation_index: 6.0, attack: 0.01, decay: 0.1,
9
+ sustain: 0.4, release: 0.4, context: Deftones.context, &block)
10
+ super(context: context)
11
+ @oscillator = Source::FMOscillator.new(
12
+ harmonicity: harmonicity,
13
+ modulation_index: modulation_index,
14
+ context: context
15
+ )
16
+ @envelope = Component::AmplitudeEnvelope.new(
17
+ attack: attack,
18
+ decay: decay,
19
+ sustain: sustain,
20
+ release: release,
21
+ context: context
22
+ )
23
+ @oscillator.start(0.0)
24
+ @oscillator >> @envelope >> @output
25
+ block&.call(self)
26
+ end
27
+
28
+ def play(note, duration: "8n", at: nil, velocity: 1.0)
29
+ trigger_attack_release(note, duration, at, velocity)
30
+ end
31
+
32
+ def trigger_attack(note, time = nil, velocity = 1.0)
33
+ scheduled_time = resolve_time(time)
34
+ @oscillator.frequency.set_value_at_time(note, scheduled_time)
35
+ @envelope.trigger_attack(scheduled_time, velocity)
36
+ self
37
+ end
38
+
39
+ def trigger_release(time = nil)
40
+ @envelope.trigger_release(resolve_time(time))
41
+ self
42
+ end
43
+
44
+ def trigger_attack_release(note, duration, time = nil, velocity = 1.0)
45
+ scheduled_time = resolve_time(time)
46
+ trigger_attack(note, scheduled_time, velocity)
47
+ trigger_release(scheduled_time + Deftones::Music::Time.parse(duration))
48
+ self
49
+ end
50
+
51
+ private
52
+
53
+ def resolve_time(time)
54
+ return context.current_time if time.nil?
55
+
56
+ Deftones::Music::Time.parse(time)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Instrument
5
+ class MembraneSynth < Core::Instrument
6
+ attr_reader :oscillator, :envelope
7
+
8
+ def initialize(pitch_decay: 0.05, octaves: 4.0, attack: 0.001, decay: 0.2,
9
+ sustain: 0.0, release: 0.15, context: Deftones.context, &block)
10
+ super(context: context)
11
+ @pitch_decay = pitch_decay.to_f
12
+ @octaves = octaves.to_f
13
+ @oscillator = Source::Oscillator.new(type: :sine, context: context)
14
+ @envelope = Component::AmplitudeEnvelope.new(
15
+ attack: attack,
16
+ decay: decay,
17
+ sustain: sustain,
18
+ release: release,
19
+ context: context
20
+ )
21
+ @oscillator.start(0.0)
22
+ @oscillator >> @envelope >> @output
23
+ block&.call(self)
24
+ end
25
+
26
+ def play(note, duration: "8n", at: nil, velocity: 1.0)
27
+ trigger_attack_release(note, duration, at, velocity)
28
+ end
29
+
30
+ def trigger_attack(note, time = nil, velocity = 1.0)
31
+ scheduled_time = resolve_time(time)
32
+ base_frequency = Deftones::Music::Note.to_frequency(note)
33
+ @oscillator.frequency.set_value_at_time(base_frequency * (2.0**@octaves), scheduled_time)
34
+ @oscillator.frequency.exponential_ramp_to(base_frequency, @pitch_decay)
35
+ @envelope.trigger_attack(scheduled_time, velocity)
36
+ self
37
+ end
38
+
39
+ def trigger_release(time = nil)
40
+ @envelope.trigger_release(resolve_time(time))
41
+ self
42
+ end
43
+
44
+ def trigger_attack_release(note, duration, time = nil, velocity = 1.0)
45
+ scheduled_time = resolve_time(time)
46
+ trigger_attack(note, scheduled_time, velocity)
47
+ trigger_release(scheduled_time + Deftones::Music::Time.parse(duration))
48
+ self
49
+ end
50
+
51
+ private
52
+
53
+ def resolve_time(time)
54
+ return context.current_time if time.nil?
55
+
56
+ Deftones::Music::Time.parse(time)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Instrument
5
+ class MetalSynth < Core::Instrument
6
+ attr_reader :oscillator, :filter, :envelope
7
+
8
+ def initialize(harmonicity: 5.0, modulation_index: 12.0, attack: 0.001, decay: 0.08,
9
+ sustain: 0.0, release: 0.06, context: Deftones.context, &block)
10
+ super(context: context)
11
+ @oscillator = Source::FMOscillator.new(
12
+ harmonicity: harmonicity,
13
+ modulation_index: modulation_index,
14
+ context: context
15
+ )
16
+ @filter = Component::Filter.new(type: :highpass, frequency: 2_500.0, q: 0.9, context: context)
17
+ @envelope = Component::AmplitudeEnvelope.new(
18
+ attack: attack,
19
+ decay: decay,
20
+ sustain: sustain,
21
+ release: release,
22
+ context: context
23
+ )
24
+ @oscillator.start(0.0)
25
+ @oscillator >> @filter >> @envelope >> @output
26
+ block&.call(self)
27
+ end
28
+
29
+ def play(note, duration: "16n", at: nil, velocity: 1.0)
30
+ trigger_attack_release(note, duration, at, velocity)
31
+ end
32
+
33
+ def trigger_attack(note, time = nil, velocity = 1.0)
34
+ scheduled_time = resolve_time(time)
35
+ @oscillator.frequency.set_value_at_time(note, scheduled_time)
36
+ @envelope.trigger_attack(scheduled_time, velocity)
37
+ self
38
+ end
39
+
40
+ def trigger_release(time = nil)
41
+ @envelope.trigger_release(resolve_time(time))
42
+ self
43
+ end
44
+
45
+ def trigger_attack_release(note, duration, time = nil, velocity = 1.0)
46
+ scheduled_time = resolve_time(time)
47
+ trigger_attack(note, scheduled_time, velocity)
48
+ trigger_release(scheduled_time + Deftones::Music::Time.parse(duration))
49
+ self
50
+ end
51
+
52
+ private
53
+
54
+ def resolve_time(time)
55
+ return context.current_time if time.nil?
56
+
57
+ Deftones::Music::Time.parse(time)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deftones
4
+ module Instrument
5
+ class MonoSynth < Core::Instrument
6
+ attr_reader :oscillator, :filter, :envelope, :filter_envelope
7
+
8
+ def initialize(type: :sawtooth, filter_type: :lowpass, filter_frequency: 1_200.0, filter_q: 0.8,
9
+ filter_octaves: 2.0, attack: 0.01, decay: 0.1, sustain: 0.4, release: 0.5,
10
+ context: Deftones.context, &block)
11
+ super(context: context)
12
+ @oscillator = Source::OmniOscillator.new(type: type, context: context)
13
+ @filter = Component::Filter.new(
14
+ type: filter_type,
15
+ frequency: filter_frequency,
16
+ q: filter_q,
17
+ context: context
18
+ )
19
+ @envelope = Component::AmplitudeEnvelope.new(
20
+ attack: attack,
21
+ decay: decay,
22
+ sustain: sustain,
23
+ release: release,
24
+ context: context
25
+ )
26
+ @filter_envelope = Component::FrequencyEnvelope.new(
27
+ base_frequency: filter_frequency,
28
+ octaves: filter_octaves,
29
+ attack: attack,
30
+ decay: decay,
31
+ sustain: sustain,
32
+ release: release,
33
+ context: context
34
+ )
35
+ @oscillator.start(0.0)
36
+ @oscillator >> @filter >> @envelope >> @output
37
+ block&.call(self)
38
+ end
39
+
40
+ def play(note, duration: "8n", at: nil, velocity: 1.0)
41
+ trigger_attack_release(note, duration, at, velocity)
42
+ end
43
+
44
+ def trigger_attack(note, time = nil, velocity = 1.0)
45
+ scheduled_time = resolve_time(time)
46
+ frequency = Deftones::Music::Note.to_frequency(note)
47
+ @oscillator.frequency.set_value_at_time(frequency, scheduled_time)
48
+ shape_filter(scheduled_time, velocity)
49
+ @envelope.trigger_attack(scheduled_time, velocity)
50
+ self
51
+ end
52
+
53
+ def trigger_release(time = nil)
54
+ scheduled_time = resolve_time(time)
55
+ @filter.frequency.linear_ramp_to(@filter_envelope.base_frequency, @envelope.release)
56
+ @envelope.trigger_release(scheduled_time)
57
+ self
58
+ end
59
+
60
+ def trigger_attack_release(note, duration, time = nil, velocity = 1.0)
61
+ scheduled_time = resolve_time(time)
62
+ trigger_attack(note, scheduled_time, velocity)
63
+ trigger_release(scheduled_time + Deftones::Music::Time.parse(duration))
64
+ self
65
+ end
66
+
67
+ def active?
68
+ @envelope.active?
69
+ end
70
+
71
+ private
72
+
73
+ def shape_filter(time, velocity)
74
+ peak = @filter_envelope.base_frequency * (2.0**(@filter_envelope.octaves * velocity))
75
+ sustain_level = @filter_envelope.base_frequency * (1.0 + (@filter_envelope.sustain * velocity))
76
+ @filter.frequency.set_value_at_time(@filter_envelope.base_frequency, time)
77
+ @filter.frequency.linear_ramp_to(peak, @filter_envelope.attack)
78
+ @filter.frequency.linear_ramp_to(sustain_level, @filter_envelope.decay)
79
+ end
80
+
81
+ def resolve_time(time)
82
+ return context.current_time if time.nil?
83
+
84
+ Deftones::Music::Time.parse(time)
85
+ end
86
+ end
87
+ end
88
+ end