Module: SonicPiAkaiApcMini::API
- Defined in:
- lib/sonic-pi-akai-apc-mini/api.rb
Constant Summary collapse
- DEFAULT_TARGET =
default ‘target` is 0-0.999 instead of 0.1 because many parameters have [0,1) as range and throw an error when passed 1 (e.g. tb303 synth’s res). It’s not the most common usecase, but for the common use case it makes no difference so I think it’s a good default.
(0..0.999).freeze
Instance Method Summary collapse
- #attach_fader(n, node, property, target = DEFAULT_TARGET) ⇒ Object
- #fader(n, target = DEFAULT_TARGET) ⇒ Object
- #free_play(row, col, notes, options = {}) ⇒ Object
- #initialize_akai(model) ⇒ Object
- #loop_rows(duration, rows) ⇒ Object
- #loop_rows_synth(duration, rows, notes, options = {}) ⇒ Object
- #reset_free_play(row, col, size) ⇒ Object
- #selector(row, col, values) ⇒ Object
- #set_fader(n, target = DEFAULT_TARGET, &block) ⇒ Object
- #switch?(row, col) ⇒ Boolean
Instance Method Details
#attach_fader(n, node, property, target = DEFAULT_TARGET) ⇒ Object
22 23 24 25 26 |
# File 'lib/sonic-pi-akai-apc-mini/api.rb', line 22 def attach_fader(n, node, property, target = DEFAULT_TARGET) set_fader(n, target) do |value| control node, property => value end end |
#fader(n, target = DEFAULT_TARGET) ⇒ Object
13 14 15 16 17 18 19 20 |
# File 'lib/sonic-pi-akai-apc-mini/api.rb', line 13 def fader(n, target = DEFAULT_TARGET) # TODO: Try to optimize speed, there is some latency because the # controller send a lot of events (too much granularity). It is in theory # possible to save some of it by `get`ting the value directly instead of # waiting for all the events to be processed. value = get("fader_#{n}", 0) Helpers.normalize(value, target) end |
#free_play(row, col, notes, options = {}) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/sonic-pi-akai-apc-mini/api.rb', line 72 def free_play(row, col, notes, = {}) Helpers.key_range(row, col, notes.size).each.with_index do |key, i| midi_note_on key, Controller.model.light_yellow set "free_play_#{key}", notes[i] end use_real_time = sync(:free_play) note_control = play [:note], { sustain: 9999 }.merge() set "free_play_playing_#{[:key]}", note_control end |
#initialize_akai(model) ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/sonic-pi-akai-apc-mini/api.rb', line 97 def initialize_akai(model) Controller.model = model # This loop manages faders. Whenever they change, the new value is stored via set, # and the corresponding light is turned on/off. live_loop :faders do use_real_time note_number, value = sync(Controller.model.midi_event(:control_change)) fader_number = note_number - Controller.model.fader_offset set "fader_#{fader_number}", value if Controller.model.fader_light_offset light_note_number = note_number + Controller.model.fader_light_offset midi_note_on light_note_number, value.zero? ? Controller.model.light_off : Controller.model.light_red end end # Manages the buttons in the grid, both as switches, selectors, and to # "free play". Whenever one is pressed, we check if that row is being used # to "free play". If it is, we play. If it's not, we check if its used as # a selector and manage it. Otherwise, we manage it as a switch. live_loop :switches_and_freeplay do use_real_time n, _vel = sync(Controller.model.midi_event(:note_on)) if note = get("free_play_#{n}") cue :free_play, note: note, key: n elsif keys = get("selector_keys_#{n}") keys.each do |k| midi_note_on k, 3 end midi_note_on n, 1 set "selector_current_value_#{keys.first}..#{keys.last}", n - keys.first else new_value = !get("switch_#{n}", false) set "switch_#{n}", new_value midi_note_on n, (new_value ? 1 : 0) end end live_loop :free_play_note_offs do use_real_time n, _vel = sync(Controller.model.midi_event(:note_off)) if note_control = get("free_play_playing_#{n}") release = note_control.args['release'] || note_control.info.arg_defaults[:release] control note_control, amp: 0, amp_slide: release at(release) { note_control.kill } end end end |
#loop_rows(duration, rows) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/sonic-pi-akai-apc-mini/api.rb', line 39 def loop_rows(duration, rows) first_row = rows.keys.max Controller.model.grid_columns.times do |beat| prev = (beat - 1) % 8 prev_key = Helpers.key(first_row, prev) beat_key = Helpers.key(first_row, beat) midi_note_on prev_key, get("switch_#{prev_key}") ? Controller.model.light_green : Controller.model.light_off midi_note_on beat_key, Controller.model.light_yellow rows.each do |row, sound| in_thread(&sound) if switch?(row, beat) end sleep duration.to_f / Controller.model.grid_columns end end |
#loop_rows_synth(duration, rows, notes, options = {}) ⇒ Object
54 55 56 57 58 59 60 61 62 |
# File 'lib/sonic-pi-akai-apc-mini/api.rb', line 54 def loop_rows_synth(duration, rows, notes, = {}) rows = rows.map.with_index do |row, i| [row, lambda do opts = .respond_to?(:call) ? .call : play(notes[i], opts) end] end.to_h loop_rows(duration, rows) end |
#reset_free_play(row, col, size) ⇒ Object
64 65 66 67 68 69 70 |
# File 'lib/sonic-pi-akai-apc-mini/api.rb', line 64 def reset_free_play(row, col, size) size = size.size unless size.is_a?(Integer) # so we can pass the same ring Helpers.key_range(row, col, size).each do |key| midi_note_on key, Controller.model.light_off set "free_play_#{key}", nil end end |
#selector(row, col, values) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/sonic-pi-akai-apc-mini/api.rb', line 85 def selector(row, col, values) # TODO: selector is quite messy. It can use a refactor and proper reset/cleanup (like free_play's). krange = Helpers.key_range(row, col, values.size) set "selector_values_#{krange}", values.ring set "selector_current_value_#{krange}", 0 if get("selector_current_value_#{krange}").nil? krange.each.with_index do |key, i| set "selector_keys_#{key}", krange.to_a midi_note_on key, i == get("selector_current_value_#{krange}") ? 1 : 3 end values[get("selector_current_value_#{krange}")] end |
#set_fader(n, target = DEFAULT_TARGET, &block) ⇒ Object
28 29 30 31 32 33 34 35 36 37 |
# File 'lib/sonic-pi-akai-apc-mini/api.rb', line 28 def set_fader(n, target = DEFAULT_TARGET, &block) # first we just call the block with the current value, or 0 block.call(Helpers.normalize(get("fader_#{n}", 0), target)) # and set a loop that will cal it again on every change live_loop "global_fader_#{n}" do use_real_time value = sync("fader_#{n}") block.call(Helpers.normalize(value, target)) end end |