surface_master 0.2.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 +7 -0
- data/.gitignore +4 -0
- data/.travis.yml +8 -0
- data/Gemfile +13 -0
- data/LICENSE +21 -0
- data/README.md +48 -0
- data/Rakefile +10 -0
- data/debug_tools/Numark_Orbit_Pad_Coloring.mmon +98 -0
- data/debug_tools/OrbitLightingExample.json +662 -0
- data/debug_tools/Orbit_Color_Test.json +662 -0
- data/debug_tools/Orbit_Colors_And_Reset.1.raw +0 -0
- data/debug_tools/Orbit_Colors_And_Reset.1.txt +82 -0
- data/debug_tools/Orbit_Colors_And_Reset.2.raw +0 -0
- data/debug_tools/Orbit_Colors_And_Reset.2.txt +2 -0
- data/debug_tools/Orbit_Colors_And_Reset.3.raw +0 -0
- data/debug_tools/Orbit_Colors_And_Reset.3.txt +82 -0
- data/debug_tools/Orbit_Colors_And_Reset.mmon +93 -0
- data/debug_tools/Orbit_Preset.1.raw +0 -0
- data/debug_tools/Orbit_Preset.1.txt +82 -0
- data/debug_tools/Orbit_Preset.2.raw +0 -0
- data/debug_tools/Orbit_Preset.2.txt +2 -0
- data/debug_tools/Orbit_Preset.mmon +72 -0
- data/debug_tools/compare.sh +12 -0
- data/debug_tools/decode.rb +14 -0
- data/debug_tools/extract_midi_monitor_sample.sh +33 -0
- data/docs/Numark_Orbit_QuickRef.md +50 -0
- data/examples/launchpad_testbed.rb +141 -0
- data/examples/monitor.rb +61 -0
- data/examples/orbit_testbed.rb +62 -0
- data/lib/control_center.rb +26 -0
- data/lib/surface_master/device.rb +90 -0
- data/lib/surface_master/errors.rb +27 -0
- data/lib/surface_master/interaction.rb +133 -0
- data/lib/surface_master/launchpad/device.rb +159 -0
- data/lib/surface_master/launchpad/errors.rb +11 -0
- data/lib/surface_master/launchpad/interaction.rb +86 -0
- data/lib/surface_master/launchpad/midi_codes.rb +51 -0
- data/lib/surface_master/logging.rb +15 -0
- data/lib/surface_master/orbit/device.rb +160 -0
- data/lib/surface_master/orbit/interaction.rb +29 -0
- data/lib/surface_master/orbit/midi_codes.rb +31 -0
- data/lib/surface_master/version.rb +3 -0
- data/mappings/Orbit_Preset.json +662 -0
- data/surface_master.gemspec +26 -0
- data/test/helper.rb +44 -0
- data/test/test_device.rb +530 -0
- data/test/test_interaction.rb +456 -0
- metadata +121 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "surface_master/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "surface_master"
|
7
|
+
s.version = SurfaceMaster::VERSION
|
8
|
+
s.authors = ["Jon Frisby"]
|
9
|
+
s.email = ["jfrisby@mrjoy.com"]
|
10
|
+
s.homepage = "https://github.com/MrJoy/surface_master"
|
11
|
+
s.summary = %q{A gem for accessing various MIDI control surfaces programmatically.}
|
12
|
+
s.description = %q{This gem provides an interface to access Novation's LaunchPad Mark 2, and Numark's Orbit programmatically. LEDs can be lit and button presses can be read.}
|
13
|
+
# TODO: Update docs to give credit to Thomas Jachmann (self@thomasjachmann.com) for his `launchpad` gem.
|
14
|
+
|
15
|
+
s.required_ruby_version = ">= 2.2.0"
|
16
|
+
|
17
|
+
s.add_dependency "portmidi", ">= 0.0.6"
|
18
|
+
s.add_dependency "ffi"
|
19
|
+
|
20
|
+
# s.has_rdoc = true
|
21
|
+
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
25
|
+
s.require_paths = ["lib"]
|
26
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'minitest/reporters'
|
6
|
+
MiniTest::Reporters.use!
|
7
|
+
rescue LoadError
|
8
|
+
# ignore when it's not there - must be ruby 1.8
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'mocha/setup'
|
12
|
+
|
13
|
+
require 'launchpad'
|
14
|
+
|
15
|
+
# mock Portmidi for tests
|
16
|
+
module Portmidi
|
17
|
+
|
18
|
+
class Input
|
19
|
+
attr_accessor :device_id
|
20
|
+
def initialize(device_id)
|
21
|
+
self.device_id = device_id
|
22
|
+
end
|
23
|
+
def read(*args); nil; end
|
24
|
+
def close; nil; end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Output
|
28
|
+
attr_accessor :device_id
|
29
|
+
def initialize(device_id)
|
30
|
+
self.device_id = device_id
|
31
|
+
end
|
32
|
+
def write(*args); nil; end
|
33
|
+
def close; nil; end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.input_devices; mock_devices; end
|
37
|
+
def self.output_devices; mock_devices; end
|
38
|
+
def self.start; end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def mock_devices(opts = {})
|
43
|
+
[Portmidi::Device.new(opts[:id] || 1, 0, 0, opts[:name] || 'Launchpad MK2')]
|
44
|
+
end
|
data/test/test_device.rb
ADDED
@@ -0,0 +1,530 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
describe SurfaceMaster::Launchpad::Device do
|
4
|
+
|
5
|
+
CONTROL_BUTTONS = {
|
6
|
+
:up => 0x68,
|
7
|
+
:down => 0x69,
|
8
|
+
:left => 0x6A,
|
9
|
+
:right => 0x6B,
|
10
|
+
:session => 0x6C,
|
11
|
+
:user1 => 0x6D,
|
12
|
+
:user2 => 0x6E,
|
13
|
+
:mixer => 0x6F
|
14
|
+
}
|
15
|
+
SCENE_BUTTONS = {
|
16
|
+
:scene1 => 0x08,
|
17
|
+
:scene2 => 0x18,
|
18
|
+
:scene3 => 0x28,
|
19
|
+
:scene4 => 0x38,
|
20
|
+
:scene5 => 0x48,
|
21
|
+
:scene6 => 0x58,
|
22
|
+
:scene7 => 0x68,
|
23
|
+
:scene8 => 0x78
|
24
|
+
}
|
25
|
+
COLORS = {
|
26
|
+
nil => 0, 0 => 0, :off => 0,
|
27
|
+
1 => 1, :lo => 1, :low => 1,
|
28
|
+
2 => 2, :med => 2, :medium => 2,
|
29
|
+
3 => 3, :hi => 3, :high => 3
|
30
|
+
}
|
31
|
+
STATES = {
|
32
|
+
:down => 127,
|
33
|
+
:up => 0
|
34
|
+
}
|
35
|
+
|
36
|
+
def expects_output(device, *args)
|
37
|
+
args = [args] unless args.first.is_a?(Array)
|
38
|
+
messages = args.collect {|data| {:message => data, :timestamp => 0}}
|
39
|
+
device.instance_variable_get('@output').expects(:write).with(messages)
|
40
|
+
end
|
41
|
+
|
42
|
+
def stub_input(device, *args)
|
43
|
+
device.instance_variable_get('@input').stubs(:read).returns(args)
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#initialize' do
|
47
|
+
|
48
|
+
it 'tries to initialize both input and output when not specified' do
|
49
|
+
Portmidi.expects(:input_devices).returns(mock_devices)
|
50
|
+
Portmidi.expects(:output_devices).returns(mock_devices)
|
51
|
+
d = Launchpad::Device.new
|
52
|
+
refute_nil d.instance_variable_get('@input')
|
53
|
+
refute_nil d.instance_variable_get('@output')
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'does not try to initialize input when set to false' do
|
57
|
+
Portmidi.expects(:input_devices).never
|
58
|
+
d = Launchpad::Device.new(:input => false)
|
59
|
+
assert_nil d.instance_variable_get('@input')
|
60
|
+
refute_nil d.instance_variable_get('@output')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'does not try to initialize output when set to false' do
|
64
|
+
Portmidi.expects(:output_devices).never
|
65
|
+
d = Launchpad::Device.new(:output => false)
|
66
|
+
refute_nil d.instance_variable_get('@input')
|
67
|
+
assert_nil d.instance_variable_get('@output')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'does not try to initialize any of both when set to false' do
|
71
|
+
Portmidi.expects(:input_devices).never
|
72
|
+
Portmidi.expects(:output_devices).never
|
73
|
+
d = Launchpad::Device.new(:input => false, :output => false)
|
74
|
+
assert_nil d.instance_variable_get('@input')
|
75
|
+
assert_nil d.instance_variable_get('@output')
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'initializes the correct input output devices when specified by name' do
|
79
|
+
Portmidi.stubs(:input_devices).returns(mock_devices(:id => 4, :name => 'Launchpad Name'))
|
80
|
+
Portmidi.stubs(:output_devices).returns(mock_devices(:id => 5, :name => 'Launchpad Name'))
|
81
|
+
d = Launchpad::Device.new(:device_name => 'Launchpad Name')
|
82
|
+
assert_equal Portmidi::Input, (input = d.instance_variable_get('@input')).class
|
83
|
+
assert_equal 4, input.device_id
|
84
|
+
assert_equal Portmidi::Output, (output = d.instance_variable_get('@output')).class
|
85
|
+
assert_equal 5, output.device_id
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'initializes the correct input output devices when specified by id' do
|
89
|
+
Portmidi.stubs(:input_devices).returns(mock_devices(:id => 4))
|
90
|
+
Portmidi.stubs(:output_devices).returns(mock_devices(:id => 5))
|
91
|
+
d = Launchpad::Device.new(:input_device_id => 4, :output_device_id => 5, :device_name => 'nonexistant')
|
92
|
+
assert_equal Portmidi::Input, (input = d.instance_variable_get('@input')).class
|
93
|
+
assert_equal 4, input.device_id
|
94
|
+
assert_equal Portmidi::Output, (output = d.instance_variable_get('@output')).class
|
95
|
+
assert_equal 5, output.device_id
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'raises NoSuchDeviceError when requested input device does not exist' do
|
99
|
+
assert_raises Launchpad::NoSuchDeviceError do
|
100
|
+
Portmidi.stubs(:input_devices).returns(mock_devices(:name => 'Launchpad Input'))
|
101
|
+
Launchpad::Device.new
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'raises NoSuchDeviceError when requested output device does not exist' do
|
106
|
+
assert_raises Launchpad::NoSuchDeviceError do
|
107
|
+
Portmidi.stubs(:output_devices).returns(mock_devices(:name => 'Launchpad Output'))
|
108
|
+
Launchpad::Device.new
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'raises DeviceBusyError when requested input device is busy' do
|
113
|
+
assert_raises Launchpad::DeviceBusyError do
|
114
|
+
Portmidi::Input.stubs(:new).raises(RuntimeError)
|
115
|
+
Launchpad::Device.new
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'raises DeviceBusyError when requested output device is busy' do
|
120
|
+
assert_raises Launchpad::DeviceBusyError do
|
121
|
+
Portmidi::Output.stubs(:new).raises(RuntimeError)
|
122
|
+
Launchpad::Device.new
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'stores the logger given' do
|
127
|
+
logger = Logger.new(nil)
|
128
|
+
device = Launchpad::Device.new(:logger => logger)
|
129
|
+
assert_same logger, device.logger
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '#close' do
|
135
|
+
|
136
|
+
it 'does not fail when neither input nor output are there' do
|
137
|
+
Launchpad::Device.new(:input => false, :output => false).close
|
138
|
+
end
|
139
|
+
|
140
|
+
describe 'with input and output devices' do
|
141
|
+
|
142
|
+
before do
|
143
|
+
Portmidi::Input.stubs(:new).returns(@input = mock('input'))
|
144
|
+
Portmidi::Output.stubs(:new).returns(@output = mock('output', :write => nil))
|
145
|
+
@device = Launchpad::Device.new
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'closes input/output and raise NoInputAllowedError/NoOutputAllowedError on subsequent read/write accesses' do
|
149
|
+
@input.expects(:close)
|
150
|
+
@output.expects(:close)
|
151
|
+
@device.close
|
152
|
+
assert_raises Launchpad::NoInputAllowedError do
|
153
|
+
@device.read_pending_actions
|
154
|
+
end
|
155
|
+
assert_raises Launchpad::NoOutputAllowedError do
|
156
|
+
@device.change(:session)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
describe '#closed?' do
|
165
|
+
|
166
|
+
it 'returns true when neither input nor output are there' do
|
167
|
+
assert Launchpad::Device.new(:input => false, :output => false).closed?
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'returns false when initialized with input' do
|
171
|
+
assert !Launchpad::Device.new(:input => true, :output => false).closed?
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'returns false when initialized with output' do
|
175
|
+
assert !Launchpad::Device.new(:input => false, :output => true).closed?
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'returns false when initialized with both but true after calling close' do
|
179
|
+
d = Launchpad::Device.new
|
180
|
+
assert !d.closed?
|
181
|
+
d.close
|
182
|
+
assert d.closed?
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
{
|
188
|
+
:reset => [0xB0, 0x00, 0x00],
|
189
|
+
:flashing_on => [0xB0, 0x00, 0x20],
|
190
|
+
:flashing_off => [0xB0, 0x00, 0x21],
|
191
|
+
:flashing_auto => [0xB0, 0x00, 0x28]
|
192
|
+
}.each do |method, codes|
|
193
|
+
describe "##{method}" do
|
194
|
+
|
195
|
+
it 'raises NoOutputAllowedError when not initialized with output' do
|
196
|
+
assert_raises Launchpad::NoOutputAllowedError do
|
197
|
+
Launchpad::Device.new(:output => false).send(method)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
it "sends #{codes.inspect}" do
|
202
|
+
d = Launchpad::Device.new
|
203
|
+
expects_output(d, *codes)
|
204
|
+
d.send(method)
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe '#test_leds' do
|
211
|
+
|
212
|
+
it 'raises NoOutputAllowedError when not initialized with output' do
|
213
|
+
assert_raises Launchpad::NoOutputAllowedError do
|
214
|
+
Launchpad::Device.new(:output => false).test_leds
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe 'initialized with output' do
|
219
|
+
|
220
|
+
before do
|
221
|
+
@device = Launchpad::Device.new(:input => false)
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'returns nil' do
|
225
|
+
assert_nil @device.test_leds
|
226
|
+
end
|
227
|
+
|
228
|
+
COLORS.merge(nil => 3).each do |name, value|
|
229
|
+
if value == 0
|
230
|
+
it "sends 0xB0, 0x00, 0x00 when given #{name}" do
|
231
|
+
expects_output(@device, 0xB0, 0x00, 0x00)
|
232
|
+
@device.test_leds(value)
|
233
|
+
end
|
234
|
+
else
|
235
|
+
it "sends 0xB0, 0x00, 0x7C + #{value} when given #{name}" do
|
236
|
+
d = Launchpad::Device.new
|
237
|
+
expects_output(@device, 0xB0, 0x00, 0x7C + value)
|
238
|
+
value.nil? ? @device.test_leds : @device.test_leds(value)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
|
247
|
+
describe '#change' do
|
248
|
+
|
249
|
+
it 'raises NoOutputAllowedError when not initialized with output' do
|
250
|
+
assert_raises Launchpad::NoOutputAllowedError do
|
251
|
+
Launchpad::Device.new(:output => false).change(:up)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
describe 'initialized with output' do
|
256
|
+
|
257
|
+
before do
|
258
|
+
@device = Launchpad::Device.new(:input => false)
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'returns nil' do
|
262
|
+
assert_nil @device.change(:up)
|
263
|
+
end
|
264
|
+
|
265
|
+
describe 'control buttons' do
|
266
|
+
CONTROL_BUTTONS.each do |type, value|
|
267
|
+
it "sends 0xB0, #{value}, 12 when given #{type}" do
|
268
|
+
expects_output(@device, 0xB0, value, 12)
|
269
|
+
@device.change(type)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
describe 'scene buttons' do
|
275
|
+
SCENE_BUTTONS.each do |type, value|
|
276
|
+
it "sends 0x90, #{value}, 12 when given #{type}" do
|
277
|
+
expects_output(@device, 0x90, value, 12)
|
278
|
+
@device.change(type)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
describe 'grid buttons' do
|
284
|
+
8.times do |x|
|
285
|
+
8.times do |y|
|
286
|
+
it "sends 0x90, #{16 * y + x}, 12 when given :grid, :x => #{x}, :y => #{y}" do
|
287
|
+
expects_output(@device, 0x90, 16 * y + x, 12)
|
288
|
+
@device.change(:grid, :x => x, :y => y)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'raises NoValidGridCoordinatesError if x is not specified' do
|
294
|
+
assert_raises Launchpad::NoValidGridCoordinatesError do
|
295
|
+
@device.change(:grid, :y => 1)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
it 'raises NoValidGridCoordinatesError if x is below 0' do
|
300
|
+
assert_raises Launchpad::NoValidGridCoordinatesError do
|
301
|
+
@device.change(:grid, :x => -1, :y => 1)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'raises NoValidGridCoordinatesError if x is above 7' do
|
306
|
+
assert_raises Launchpad::NoValidGridCoordinatesError do
|
307
|
+
@device.change(:grid, :x => 8, :y => 1)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'raises NoValidGridCoordinatesError if y is not specified' do
|
312
|
+
assert_raises Launchpad::NoValidGridCoordinatesError do
|
313
|
+
@device.change(:grid, :x => 1)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'raises NoValidGridCoordinatesError if y is below 0' do
|
318
|
+
assert_raises Launchpad::NoValidGridCoordinatesError do
|
319
|
+
@device.change(:grid, :x => 1, :y => -1)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
it 'raises NoValidGridCoordinatesError if y is above 7' do
|
324
|
+
assert_raises Launchpad::NoValidGridCoordinatesError do
|
325
|
+
@device.change(:grid, :x => 1, :y => 8)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
end
|
330
|
+
|
331
|
+
describe 'colors' do
|
332
|
+
COLORS.each do |red_key, red_value|
|
333
|
+
COLORS.each do |green_key, green_value|
|
334
|
+
it "sends 0x90, 0, #{16 * green_value + red_value + 12} when given :red => #{red_key}, :green => #{green_key}" do
|
335
|
+
expects_output(@device, 0x90, 0, 16 * green_value + red_value + 12)
|
336
|
+
@device.change(:grid, :x => 0, :y => 0, :red => red_key, :green => green_key)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
it 'raises NoValidBrightnessError if red is below 0' do
|
342
|
+
assert_raises Launchpad::NoValidBrightnessError do
|
343
|
+
@device.change(:grid, :x => 0, :y => 0, :red => -1)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
it 'raises NoValidBrightnessError if red is above 3' do
|
348
|
+
assert_raises Launchpad::NoValidBrightnessError do
|
349
|
+
@device.change(:grid, :x => 0, :y => 0, :red => 4)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'raises NoValidBrightnessError if red is an unknown symbol' do
|
354
|
+
assert_raises Launchpad::NoValidBrightnessError do
|
355
|
+
@device.change(:grid, :x => 0, :y => 0, :red => :unknown)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
it 'raises NoValidBrightnessError if green is below 0' do
|
360
|
+
assert_raises Launchpad::NoValidBrightnessError do
|
361
|
+
@device.change(:grid, :x => 0, :y => 0, :green => -1)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'raises NoValidBrightnessError if green is above 3' do
|
366
|
+
assert_raises Launchpad::NoValidBrightnessError do
|
367
|
+
@device.change(:grid, :x => 0, :y => 0, :green => 4)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'raises NoValidBrightnessError if green is an unknown symbol' do
|
372
|
+
assert_raises Launchpad::NoValidBrightnessError do
|
373
|
+
@device.change(:grid, :x => 0, :y => 0, :green => :unknown)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
end
|
378
|
+
|
379
|
+
describe 'mode' do
|
380
|
+
|
381
|
+
it 'sends color + 12 when nothing given' do
|
382
|
+
expects_output(@device, 0x90, 0, 12)
|
383
|
+
@device.change(:grid, :x => 0, :y => 0, :red => 0, :green => 0)
|
384
|
+
end
|
385
|
+
|
386
|
+
it 'sends color + 12 when given :normal' do
|
387
|
+
expects_output(@device, 0x90, 0, 12)
|
388
|
+
@device.change(:grid, :x => 0, :y => 0, :red => 0, :green => 0, :mode => :normal)
|
389
|
+
end
|
390
|
+
|
391
|
+
it 'sends color + 8 when given :flashing' do
|
392
|
+
expects_output(@device, 0x90, 0, 8)
|
393
|
+
@device.change(:grid, :x => 0, :y => 0, :red => 0, :green => 0, :mode => :flashing)
|
394
|
+
end
|
395
|
+
|
396
|
+
it 'sends color when given :buffering' do
|
397
|
+
expects_output(@device, 0x90, 0, 0)
|
398
|
+
@device.change(:grid, :x => 0, :y => 0, :red => 0, :green => 0, :mode => :buffering)
|
399
|
+
end
|
400
|
+
|
401
|
+
end
|
402
|
+
|
403
|
+
end
|
404
|
+
|
405
|
+
end
|
406
|
+
|
407
|
+
describe '#change_all' do
|
408
|
+
|
409
|
+
it 'raises NoOutputAllowedError when not initialized with output' do
|
410
|
+
assert_raises Launchpad::NoOutputAllowedError do
|
411
|
+
Launchpad::Device.new(:output => false).change_all
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
describe 'initialized with output' do
|
416
|
+
|
417
|
+
before do
|
418
|
+
@device = Launchpad::Device.new(:input => false)
|
419
|
+
end
|
420
|
+
|
421
|
+
it 'returns nil' do
|
422
|
+
assert_nil @device.change_all([0])
|
423
|
+
end
|
424
|
+
|
425
|
+
it 'fills colors with 0, set grid layout to XY and flush colors' do
|
426
|
+
expects_output(@device, 0xB0, 0, 0x01)
|
427
|
+
expects_output(@device, *([[0x92, 17, 17]] * 20 + [[0x92, 12, 12]] * 20))
|
428
|
+
@device.change_all([5] * 40)
|
429
|
+
end
|
430
|
+
|
431
|
+
it 'cuts off exceeding colors, set grid layout to XY and flush colors' do
|
432
|
+
expects_output(@device, 0xB0, 0, 0x01)
|
433
|
+
expects_output(@device, *([[0x92, 17, 17]] * 40))
|
434
|
+
@device.change_all([5] * 100)
|
435
|
+
end
|
436
|
+
|
437
|
+
end
|
438
|
+
|
439
|
+
end
|
440
|
+
|
441
|
+
describe '#buffering_mode' do
|
442
|
+
|
443
|
+
it 'raises NoOutputAllowedError when not initialized with output' do
|
444
|
+
assert_raises Launchpad::NoOutputAllowedError do
|
445
|
+
Launchpad::Device.new(:output => false).buffering_mode
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
{
|
450
|
+
nil => [0xB0, 0x00, 0x20],
|
451
|
+
{} => [0xB0, 0x00, 0x20],
|
452
|
+
{:display_buffer => 1} => [0xB0, 0x00, 0x21],
|
453
|
+
{:update_buffer => 1} => [0xB0, 0x00, 0x24],
|
454
|
+
{:copy => true} => [0xB0, 0x00, 0x30],
|
455
|
+
{:flashing => true} => [0xB0, 0x00, 0x28],
|
456
|
+
{
|
457
|
+
:display_buffer => 1,
|
458
|
+
:update_buffer => 1,
|
459
|
+
:copy => true,
|
460
|
+
:flashing => true
|
461
|
+
} => [0xB0, 0x00, 0x3D]
|
462
|
+
}.each do |opts, codes|
|
463
|
+
it "sends #{codes.inspect} when called with #{opts.inspect}" do
|
464
|
+
d = Launchpad::Device.new
|
465
|
+
expects_output(d, *codes)
|
466
|
+
d.buffering_mode(opts)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
end
|
471
|
+
|
472
|
+
describe '#read_pending_actions' do
|
473
|
+
|
474
|
+
it 'raises NoInputAllowedError when not initialized with input' do
|
475
|
+
assert_raises Launchpad::NoInputAllowedError do
|
476
|
+
Launchpad::Device.new(:input => false).read_pending_actions
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
describe 'initialized with input' do
|
481
|
+
|
482
|
+
before do
|
483
|
+
@device = Launchpad::Device.new(:output => false)
|
484
|
+
end
|
485
|
+
|
486
|
+
describe 'control buttons' do
|
487
|
+
CONTROL_BUTTONS.each do |type, value|
|
488
|
+
STATES.each do |state, velocity|
|
489
|
+
it "builds proper action for control button #{type}, #{state}" do
|
490
|
+
stub_input(@device, {:timestamp => 0, :message => [0xB0, value, velocity]})
|
491
|
+
assert_equal [{:timestamp => 0, :state => state, :type => type}], @device.read_pending_actions
|
492
|
+
end
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
describe 'scene buttons' do
|
498
|
+
SCENE_BUTTONS.each do |type, value|
|
499
|
+
STATES.each do |state, velocity|
|
500
|
+
it "builds proper action for scene button #{type}, #{state}" do
|
501
|
+
stub_input(@device, {:timestamp => 0, :message => [0x90, value, velocity]})
|
502
|
+
assert_equal [{:timestamp => 0, :state => state, :type => type}], @device.read_pending_actions
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
describe '#grid buttons' do
|
509
|
+
8.times do |x|
|
510
|
+
8.times do |y|
|
511
|
+
STATES.each do |state, velocity|
|
512
|
+
it "builds proper action for grid button #{x},#{y}, #{state}" do
|
513
|
+
stub_input(@device, {:timestamp => 0, :message => [0x90, 16 * y + x, velocity]})
|
514
|
+
assert_equal [{:timestamp => 0, :state => state, :type => :grid, :x => x, :y => y}], @device.read_pending_actions
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
it 'builds proper actions for multiple pending actions' do
|
522
|
+
stub_input(@device, {:timestamp => 1, :message => [0x90, 0, 127]}, {:timestamp => 2, :message => [0xB0, 0x68, 0]})
|
523
|
+
assert_equal [{:timestamp => 1, :state => :down, :type => :grid, :x => 0, :y => 0}, {:timestamp => 2, :state => :up, :type => :up}], @device.read_pending_actions
|
524
|
+
end
|
525
|
+
|
526
|
+
end
|
527
|
+
|
528
|
+
end
|
529
|
+
|
530
|
+
end
|