surface_master 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b3c8e66c72e0225a04e8fbe61bbffc2d477de6c6
4
- data.tar.gz: c3ac84410c8799b5b345c9692f99ccd91ec562a6
3
+ metadata.gz: 94debb23931c0d4acfc807e8c537442ebc4f34bf
4
+ data.tar.gz: bf26b6479e46056fd7ca580464cca8c2b9b98e80
5
5
  SHA512:
6
- metadata.gz: 03da9f7ecd866d2133fc46b57fa4ad295c46edbe93588c221ce73a8ca11d1d9a3e2de748872769fab960888219d2df3bac9c0e45ff245d864da1d2ced9e51a41
7
- data.tar.gz: fcf81c4609204ffdcc882c68c4187f0992ba7f3d9f2a65f2c134798b34557cc74d63550f6f818364e33c6d8bc4070e84dece0480e41bf0c2ece55dfa74210917
6
+ metadata.gz: af1db6281a6c2802bcdf177452788c047bbb59358db6d5695ce8b5020522d22859c7622d76444351bd394d9f565e76f58fa98cd1a3126f2448949b2794cd9621
7
+ data.tar.gz: d4ccfa6aed322a129725ba6600c643c398b121d34f1ab7e5e4937e2b67cf2f70193b0632eded87f0b017ef95a3e3f2b36d96db131d40ea7c18af79f8219bb50f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changes
2
2
 
3
+ ## v0.5.0
4
+
5
+ * Make all addressing for Numark Orbit be zero-based.
6
+ * Switch to grid addressing for Numark Orbit (backwards incompatible change!).
7
+
8
+
3
9
  ## v0.4.1
4
10
 
5
11
  * Add a simple driver for the TouchOSC Bridge.
@@ -7,17 +7,17 @@ require "surface_master"
7
7
 
8
8
  SurfaceMaster.init!
9
9
  interaction = SurfaceMaster::Orbit::Interaction.new
10
- interaction.response_to(:pad, :down) do |_inter, action|
10
+ interaction.response_to(:grid, :down) do |_inter, action|
11
11
  puts "PAD DOWN: #{action.inspect}"
12
12
  end
13
- interaction.response_to(:pad, :up) do |_inter, action|
13
+ interaction.response_to(:grid, :up) do |_inter, action|
14
14
  puts "PAD UP: #{action.inspect}"
15
15
  end
16
- interaction.response_to(:pad, :up, button: 1..4) do |_inter, action|
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(:pad, :up, button: 5..8, bank: 4, exclusive: true) do |_inter, action|
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: 4, vknob: 1) do |_inter, action|
33
- puts "KNOB 1, BANK 4 TURNED: #{action.inspect}"
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, offset: 0x03, use_read: true, read_delay: 0.1 },
30
- wired: { delay: 0.1, offset: 0x01, use_read: false, read_delay: 0 } }
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,
@@ -76,7 +76,7 @@ module SurfaceMaster
76
76
  protected
77
77
 
78
78
  def expand(list)
79
- list.map { |ll| ll.respond_to?(:to_a) ? ll.to_a : ll }.flatten
79
+ Array(list).map { |ll| ll.respond_to?(:to_a) ? ll.to_a : ll }.flatten
80
80
  end
81
81
 
82
82
  def guard_input_and_reset_at_end!(&block)
@@ -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
- # TODO: It appears that accessing `buffer` is HIGHLY unsafe! We may
27
- # TODO: be OK if everyone's waiting on us to come back from this
28
- # TODO: method before they begin clamoring for input, but that's just
29
- # TODO: a guess right now.
30
- if @input.buffer.length == 0
31
- elapsed = Time.now.to_f - started_at
32
- if elapsed > 4.0
33
- logger.warn { "Timeout fetching state of Numark Orbit!" }
34
- break
35
- elsif elapsed > (1.0 * attempts)
36
- logger.warn { "Asking for current state of Numark Orbit again!" }
37
- attempts += 1
38
- @output.puts(READ_STATE)
39
- next
40
- end
41
- sleep 0.01
42
- next
43
- end
44
- raw = @input.gets
45
- current_state = raw.find { |ii| ii[:data][0] == 0xF0 }
46
- break unless current_state.nil?
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
- logger.error { "UH OH! Numark Orbit state didn't match what we sent!" }
55
- logger.error { "Expected: #{expected_state.inspect}" }
56
- logger.error { "Got: #{current_state.inspect}" }
57
- else
58
- logger.debug { "Your Numark Orbit should be in the right state now." }
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 decode_pad(decoded, note, _velocity)
163
- decoded[:control] = decoded[:control].merge(button: note + 1)
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 + 1)
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 :pad then decoded = decode_pad(decoded, note, velocity)
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? ? [1..4] : [opts[:vknob]]
20
- banks = opts[:bank].nil? ? [1..4] : [opts[:bank]]
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? ? [1..4] : [opts[:button]]
31
+ buttons = opts[:button].nil? ? [0..3] : [opts[:button]]
25
32
 
26
33
  expand(buttons).map { |b| [:"#{type}-#{b}"] }
27
- when :pad
28
- banks = opts[:bank].nil? ? [1..4] : [opts[:bank]]
29
- buttons = opts[:button].nil? ? [1..16] : [opts[:button]]
30
-
31
- expand(buttons).product(expand(banks)).map { |p, b| :"#{type}-#{p}-#{b}" }
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: :pad, state: :down, control: { bank: 1 } },
10
- 0x01 => { type: :pad, state: :down, control: { bank: 2 } },
11
- 0x02 => { type: :pad, state: :down, control: { bank: 3 } },
12
- 0x03 => { type: :pad, state: :down, control: { bank: 4 } },
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: :pad, state: :up, control: { bank: 1 } },
15
- 0x01 => { type: :pad, state: :up, control: { bank: 2 } },
16
- 0x02 => { type: :pad, state: :up, control: { bank: 3 } },
17
- 0x03 => { type: :pad, state: :up, control: { bank: 4 } },
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: 1 } },
20
- 0x01 => { type: :vknob, state: :update, control: { vknob: 2 } },
21
- 0x02 => { type: :vknob, state: :update, control: { vknob: 3 } },
22
- 0x03 => { type: :vknob, state: :update, control: { vknob: 4 } },
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
@@ -1,4 +1,4 @@
1
1
  #
2
2
  module SurfaceMaster
3
- VERSION = "0.4.1"
3
+ VERSION = "0.5.0"
4
4
  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.1
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-13 00:00:00.000000000 Z
11
+ date: 2015-09-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: portmidi