surface_master 0.4.1 → 0.5.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/examples/orbit_interaction.rb +7 -7
- data/examples/orbit_playground.rb +2 -2
- data/lib/surface_master/interaction.rb +1 -1
- data/lib/surface_master/orbit/device.rb +49 -46
- data/lib/surface_master/orbit/interaction.rb +33 -8
- data/lib/surface_master/orbit/midi_codes.rb +12 -12
- data/lib/surface_master/touch_osc/device.rb +1 -6
- data/lib/surface_master/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94debb23931c0d4acfc807e8c537442ebc4f34bf
|
4
|
+
data.tar.gz: bf26b6479e46056fd7ca580464cca8c2b9b98e80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af1db6281a6c2802bcdf177452788c047bbb59358db6d5695ce8b5020522d22859c7622d76444351bd394d9f565e76f58fa98cd1a3126f2448949b2794cd9621
|
7
|
+
data.tar.gz: d4ccfa6aed322a129725ba6600c643c398b121d34f1ab7e5e4937e2b67cf2f70193b0632eded87f0b017ef95a3e3f2b36d96db131d40ea7c18af79f8219bb50f
|
data/CHANGELOG.md
CHANGED
@@ -7,17 +7,17 @@ require "surface_master"
|
|
7
7
|
|
8
8
|
SurfaceMaster.init!
|
9
9
|
interaction = SurfaceMaster::Orbit::Interaction.new
|
10
|
-
interaction.response_to(:
|
10
|
+
interaction.response_to(:grid, :down) do |_inter, action|
|
11
11
|
puts "PAD DOWN: #{action.inspect}"
|
12
12
|
end
|
13
|
-
interaction.response_to(:
|
13
|
+
interaction.response_to(:grid, :up) do |_inter, action|
|
14
14
|
puts "PAD UP: #{action.inspect}"
|
15
15
|
end
|
16
|
-
interaction.response_to(:
|
16
|
+
interaction.response_to(:grid, :up, x: 0) do |_inter, action|
|
17
17
|
puts "LEFT COLUMN PAD UP: #{action.inspect}"
|
18
18
|
end
|
19
|
-
interaction.response_to(:
|
20
|
-
puts "SECOND-FROM-LEFT COLUMN PAD UP: #{action.inspect}"
|
19
|
+
interaction.response_to(:grid, :up, x: 1, y: 0..3, bank: 3, exclusive: true) do |_inter, action|
|
20
|
+
puts "SECOND-FROM-LEFT COLUMN, LAST BANK, PAD UP: #{action.inspect}"
|
21
21
|
end
|
22
22
|
|
23
23
|
interaction.response_to(:vknob, :update) do |_inter, action|
|
@@ -29,8 +29,8 @@ end
|
|
29
29
|
interaction.response_to(:vknob, :update, bank: 2, exclusive: true) do |_inter, action|
|
30
30
|
puts "ANY KNOB, BANK 2 TURNED: #{action.inspect}"
|
31
31
|
end
|
32
|
-
interaction.response_to(:vknob, :update, bank:
|
33
|
-
puts "KNOB 1, BANK
|
32
|
+
interaction.response_to(:vknob, :update, bank: 1, vknob: 1) do |_inter, action|
|
33
|
+
puts "KNOB 1, BANK 1 TURNED: #{action.inspect}"
|
34
34
|
end
|
35
35
|
|
36
36
|
interaction.response_to(:accelerometer, :tilt) do |_inter, action|
|
@@ -26,8 +26,8 @@ device = SurfaceMaster::Orbit::Device.new
|
|
26
26
|
# TODO: Can we safely get input simultaneously?
|
27
27
|
MODE = :wired
|
28
28
|
|
29
|
-
CONFIGS = { wireless: { delay: 0.75,
|
30
|
-
wired: { delay: 0.1, offset: 0x01, use_read: false,
|
29
|
+
CONFIGS = { wireless: { delay: 0.75, offset: 0x03, use_read: true, read_delay: 0.1 },
|
30
|
+
wired: { delay: 0.1, offset: 0x01, use_read: false, read_delay: 0 } }
|
31
31
|
MAPPINGS = [0x03, 0x01, 0x70,
|
32
32
|
|
33
33
|
0x00, 0x00, 0x00,
|
@@ -11,52 +11,55 @@ module SurfaceMaster
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def reset!
|
14
|
+
# Hack to get around apparent portmidi message truncation.
|
15
|
+
return
|
16
|
+
|
14
17
|
# Skip Sysex begin, vendor header, command code, aaaaand sysex end --
|
15
18
|
# this will let us compare command vs. response payloads to determine
|
16
19
|
# if the state of the device is what we want. Of course, sometimes it
|
17
20
|
# lies, but we can't do much about that.
|
18
|
-
expected_state = MAPPINGS[6..-2]
|
19
|
-
sysex!(MAPPINGS)
|
20
|
-
sleep 0.1
|
21
|
-
sysex!(READ_STATE)
|
22
|
-
current_state = nil
|
23
|
-
started_at = Time.now.to_f
|
24
|
-
attempts = 1
|
25
|
-
loop do
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
return unless current_state
|
50
|
-
|
51
|
-
current_state = current_state[:data][6..-2].dup
|
52
|
-
logger.debug { "Got state info from Numark Orbit!" }
|
53
|
-
if expected_state != current_state
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
else
|
58
|
-
|
59
|
-
end
|
21
|
+
# expected_state = MAPPINGS[6..-2]
|
22
|
+
# sysex!(MAPPINGS)
|
23
|
+
# sleep 0.1
|
24
|
+
# sysex!(READ_STATE)
|
25
|
+
# current_state = nil
|
26
|
+
# started_at = Time.now.to_f
|
27
|
+
# attempts = 1
|
28
|
+
# loop do
|
29
|
+
# # TODO: It appears that accessing `buffer` is HIGHLY unsafe! We may
|
30
|
+
# # TODO: be OK if everyone's waiting on us to come back from this
|
31
|
+
# # TODO: method before they begin clamoring for input, but that's just
|
32
|
+
# # TODO: a guess right now.
|
33
|
+
# if @input.buffer.length == 0
|
34
|
+
# elapsed = Time.now.to_f - started_at
|
35
|
+
# if elapsed > 4.0
|
36
|
+
# logger.warn { "Timeout fetching state of Numark Orbit!" }
|
37
|
+
# break
|
38
|
+
# elsif elapsed > (1.0 * attempts)
|
39
|
+
# logger.warn { "Asking for current state of Numark Orbit again!" }
|
40
|
+
# attempts += 1
|
41
|
+
# @output.puts(READ_STATE)
|
42
|
+
# next
|
43
|
+
# end
|
44
|
+
# sleep 0.01
|
45
|
+
# next
|
46
|
+
# end
|
47
|
+
# raw = @input.gets
|
48
|
+
# current_state = raw.find { |ii| ii[:data][0] == 0xF0 }
|
49
|
+
# break unless current_state.nil?
|
50
|
+
# end
|
51
|
+
|
52
|
+
# return unless current_state
|
53
|
+
|
54
|
+
# current_state = current_state[:data][6..-2].dup
|
55
|
+
# logger.debug { "Got state info from Numark Orbit!" }
|
56
|
+
# if expected_state != current_state
|
57
|
+
# logger.error { "UH OH! Numark Orbit state didn't match what we sent!" }
|
58
|
+
# logger.error { "Expected: #{expected_state.inspect}" }
|
59
|
+
# logger.error { "Got: #{current_state.inspect}" }
|
60
|
+
# else
|
61
|
+
# logger.debug { "Your Numark Orbit should be in the right state now." }
|
62
|
+
# end
|
60
63
|
end
|
61
64
|
|
62
65
|
def read
|
@@ -159,13 +162,13 @@ module SurfaceMaster
|
|
159
162
|
decoded
|
160
163
|
end
|
161
164
|
|
162
|
-
def
|
163
|
-
decoded[:control] = decoded[:control].merge(
|
165
|
+
def decode_grid(decoded, note, _velocity)
|
166
|
+
decoded[:control] = decoded[:control].merge(x: note / 4, y: note % 4)
|
164
167
|
decoded
|
165
168
|
end
|
166
169
|
|
167
170
|
def decode_knob(decoded, note, velocity)
|
168
|
-
decoded[:control] = decoded[:control].merge(bank: note
|
171
|
+
decoded[:control] = decoded[:control].merge(bank: note)
|
169
172
|
decoded[:value] = velocity
|
170
173
|
decoded
|
171
174
|
end
|
@@ -184,7 +187,7 @@ module SurfaceMaster
|
|
184
187
|
def enrich_decoded_message(decoded, note, velocity, timestamp)
|
185
188
|
case decoded[:type]
|
186
189
|
when :shoulder then decoded = decode_shoulder(decoded, note, velocity)
|
187
|
-
when :
|
190
|
+
when :grid then decoded = decode_grid(decoded, note, velocity)
|
188
191
|
when :vknob then decoded = decode_knob(decoded, note, velocity)
|
189
192
|
when :accelerometer then decoded = decode_accelerometer(decoded, note, velocity)
|
190
193
|
else decoded = decode_control(decoded, note, velocity)
|
@@ -9,6 +9,13 @@ module SurfaceMaster
|
|
9
9
|
|
10
10
|
protected
|
11
11
|
|
12
|
+
def grid_range(range)
|
13
|
+
return [0..3] if range.nil?
|
14
|
+
Array(range).flatten.map do |pos|
|
15
|
+
pos.respond_to?(:to_a) ? pos.to_a : pos
|
16
|
+
end.flatten.uniq
|
17
|
+
end
|
18
|
+
|
12
19
|
def combined_types(type, opts = nil)
|
13
20
|
tmp = case type
|
14
21
|
when :shoulder
|
@@ -16,19 +23,20 @@ module SurfaceMaster
|
|
16
23
|
when :accelerometer
|
17
24
|
[:"#{type}-#{opts[:axis]}"]
|
18
25
|
when :vknob
|
19
|
-
knobs = opts[:vknob].nil? ? [
|
20
|
-
banks = opts[:bank].nil? ? [
|
26
|
+
knobs = opts[:vknob].nil? ? [0..3] : [opts[:vknob]]
|
27
|
+
banks = opts[:bank].nil? ? [0..3] : [opts[:bank]]
|
21
28
|
|
22
29
|
expand(knobs).product(expand(banks)).map { |k, b| :"#{type}-#{k}-#{b}" }
|
23
30
|
when :vknobs, :banks
|
24
|
-
buttons = opts[:button].nil? ? [
|
31
|
+
buttons = opts[:button].nil? ? [0..3] : [opts[:button]]
|
25
32
|
|
26
33
|
expand(buttons).map { |b| [:"#{type}-#{b}"] }
|
27
|
-
when :
|
28
|
-
banks
|
29
|
-
|
30
|
-
|
31
|
-
|
34
|
+
when :grid
|
35
|
+
banks = expand(opts[:bank] || [0..3])
|
36
|
+
x = expand(grid_range(opts[:x]))
|
37
|
+
y = expand(grid_range(opts[:y]))
|
38
|
+
# return [:grid] if x.nil? && y.nil? # whole grid
|
39
|
+
x.product(y).product(banks).map { |xx, (yy, b)| :"#{type}-#{xx}-#{yy}-#{b}" }
|
32
40
|
else
|
33
41
|
[type]
|
34
42
|
end
|
@@ -63,11 +71,28 @@ module SurfaceMaster
|
|
63
71
|
combined_types = combined_types(action[:type].to_sym, action[:control])
|
64
72
|
state = action[:state].to_sym
|
65
73
|
actions = []
|
74
|
+
if action[:type] == :grid
|
75
|
+
actions += mappings_for_grid_action(state, action[:control])
|
76
|
+
end
|
66
77
|
actions += combined_types.map { |ct| responses[ct][state] }
|
67
78
|
actions += responses[:all][state]
|
68
79
|
actions.flatten.compact
|
69
80
|
end
|
70
81
|
|
82
|
+
def mappings_for_grid_action(state, control)
|
83
|
+
x = control[:x]
|
84
|
+
y = control[:y]
|
85
|
+
bank = control[:bank]
|
86
|
+
actions = []
|
87
|
+
actions += responses[:"grid-#{x}-#{y}-#{bank}"][state]
|
88
|
+
actions += responses[:"grid-#{x}--#{bank}"][state]
|
89
|
+
actions += responses[:"grid--#{y}-#{bank}"][state]
|
90
|
+
actions += responses[:"grid-#{x}-#{y}-"][state]
|
91
|
+
actions += responses[:"grid-#{x}--"][state]
|
92
|
+
actions += responses[:"grid--#{y}-"][state]
|
93
|
+
actions
|
94
|
+
end
|
95
|
+
|
71
96
|
def expand_states(state)
|
72
97
|
case state
|
73
98
|
when :both then %i(down up)
|
@@ -6,20 +6,20 @@ module SurfaceMaster
|
|
6
6
|
module MIDICodes
|
7
7
|
# TODO: Use a lib to do a deep-freeze.
|
8
8
|
# rubocop:disable Metrics/LineLength
|
9
|
-
CONTROLS = { 0x90 => { 0x00 => { type: :
|
10
|
-
0x01 => { type: :
|
11
|
-
0x02 => { type: :
|
12
|
-
0x03 => { type: :
|
9
|
+
CONTROLS = { 0x90 => { 0x00 => { type: :grid, state: :down, control: { bank: 0 } },
|
10
|
+
0x01 => { type: :grid, state: :down, control: { bank: 1 } },
|
11
|
+
0x02 => { type: :grid, state: :down, control: { bank: 2 } },
|
12
|
+
0x03 => { type: :grid, state: :down, control: { bank: 3 } },
|
13
13
|
0x0F => { type: :shoulder, state: :down, control: {} } },
|
14
|
-
0x80 => { 0x00 => { type: :
|
15
|
-
0x01 => { type: :
|
16
|
-
0x02 => { type: :
|
17
|
-
0x03 => { type: :
|
14
|
+
0x80 => { 0x00 => { type: :grid, state: :up, control: { bank: 0 } },
|
15
|
+
0x01 => { type: :grid, state: :up, control: { bank: 1 } },
|
16
|
+
0x02 => { type: :grid, state: :up, control: { bank: 2 } },
|
17
|
+
0x03 => { type: :grid, state: :up, control: { bank: 3 } },
|
18
18
|
0x0F => { type: :shoulder, state: :up, control: {} } },
|
19
|
-
0xB0 => { 0x00 => { type: :vknob, state: :update, control: { vknob:
|
20
|
-
0x01 => { type: :vknob, state: :update, control: { vknob:
|
21
|
-
0x02 => { type: :vknob, state: :update, control: { vknob:
|
22
|
-
0x03 => { type: :vknob, state: :update, control: { vknob:
|
19
|
+
0xB0 => { 0x00 => { type: :vknob, state: :update, control: { vknob: 0 } },
|
20
|
+
0x01 => { type: :vknob, state: :update, control: { vknob: 1 } },
|
21
|
+
0x02 => { type: :vknob, state: :update, control: { vknob: 2 } },
|
22
|
+
0x03 => { type: :vknob, state: :update, control: { vknob: 3 } },
|
23
23
|
0x0C => { type: :accelerometer, state: :tilt, control: { axis: :x } },
|
24
24
|
0x0D => { type: :accelerometer, state: :tilt, control: { axis: :y } },
|
25
25
|
0x0F => { state: :down } } }.freeze
|
@@ -8,8 +8,7 @@ module SurfaceMaster
|
|
8
8
|
@mapper = mapper || proc { |input| input }
|
9
9
|
end
|
10
10
|
|
11
|
-
def reset
|
12
|
-
end
|
11
|
+
def reset!; end
|
13
12
|
|
14
13
|
def read
|
15
14
|
super
|
@@ -20,10 +19,6 @@ module SurfaceMaster
|
|
20
19
|
def write(messages)
|
21
20
|
@output.write(Array(messages))
|
22
21
|
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
|
26
|
-
# def sysex_prefix; @sysex_prefix ||= super + []; end
|
27
22
|
end
|
28
23
|
end
|
29
24
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: surface_master
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Frisby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: portmidi
|