mrjoy-launchpad 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.travis.yml +8 -0
- data/Gemfile +6 -0
- data/LICENSE +20 -0
- data/README.rdoc +136 -0
- data/Rakefile +10 -0
- data/examples/binary_clock.rb +29 -0
- data/examples/color_picker.rb +96 -0
- data/examples/colors.rb +21 -0
- data/examples/doodle.rb +68 -0
- data/examples/double_buffering.rb +104 -0
- data/examples/drawing_board.rb +25 -0
- data/examples/feedback.rb +34 -0
- data/examples/reset.rb +6 -0
- data/launchpad.gemspec +34 -0
- data/lib/launchpad.rb +34 -0
- data/lib/launchpad/device.rb +574 -0
- data/lib/launchpad/errors.rb +37 -0
- data/lib/launchpad/interaction.rb +336 -0
- data/lib/launchpad/logging.rb +27 -0
- data/lib/launchpad/midi_codes.rb +53 -0
- data/lib/launchpad/version.rb +3 -0
- data/monitor.rb +88 -0
- data/test/helper.rb +44 -0
- data/test/test_device.rb +530 -0
- data/test/test_interaction.rb +456 -0
- data/testbed.rb +48 -0
- metadata +146 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f8c2eaea477fc7c3dd5587186a3ee2846705f14e
|
4
|
+
data.tar.gz: a5e36f0a19dd060bb7a48fd2414d4c05796981b8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4435b65556c71612909b4cd6ff980f506085d8a3fff825619d4e7ce72e9627b346bfae8f9865c86c9cb1c36580a37485991cc74331051aaf5ce8437d0b0062b5
|
7
|
+
data.tar.gz: c93a479be6b78023c09c9deedc2eb5818577a6cd7facb50cca3dd3fb77a6c5d8a5156ba312dc5dd30285a80d27354566318b027b3490cd32aea48ff1d9c99166
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Thomas Jachmann
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
= launchpad
|
2
|
+
|
3
|
+
{<img src="https://travis-ci.org/thomasjachmann/launchpad.png?branch=master" alt="Build Status" />}[https://travis-ci.org/thomasjachmann/launchpad]
|
4
|
+
|
5
|
+
This gem provides a ruby interface to access novation's launchpad programmatically. LEDs can be lighted and button presses can be responded to. Internally, launchpad's MIDI input/output is used to accomplish this.
|
6
|
+
|
7
|
+
The interfaces should be rather stable now (sorry, I changed quite a bit since the last release), so experiment with them and comment on their usability. This still is work in progress. If you need anything or think the interfaces could be improved in any way, please contact me.
|
8
|
+
|
9
|
+
Sometimes, the launchpad won't react to anything or react to/light up the wrong LEDs. Don't despair, just dis- and reconnect the thing. It seems that some (unexpected) MIDI signals make it hickup.
|
10
|
+
|
11
|
+
== This Fork
|
12
|
+
|
13
|
+
* Added ability to handle inputs without spawning a thread per input.
|
14
|
+
* Modify to support for LaunchPad Mk 2. Note that this breaks Mk 1 support!
|
15
|
+
* Recognize identity string from this model.
|
16
|
+
* Fix X/Y coordinates for buttons.
|
17
|
+
* Add support for RGB colors.
|
18
|
+
|
19
|
+
|
20
|
+
== More Info
|
21
|
+
|
22
|
+
If you don't know what launchpad is, visit:
|
23
|
+
|
24
|
+
* Novation's site at http://de.novationmusic.com/products/midi_controller/launchpad
|
25
|
+
* my demo videos for this library at http://www.youtube.com/thomasjachmann
|
26
|
+
* other demos on youtube http://www.youtube.com/results?search_query=novation+launchpad
|
27
|
+
|
28
|
+
If you're into other languages or want to know what goes on behind the scenes MIDI wise, have a look at:
|
29
|
+
|
30
|
+
* Novation's MIDI programmer's reference at {www.novationmusic.com/support/launchpad}[http://www.novationmusic.com/support/launchpad/] (bottom of the page)
|
31
|
+
* Tobi Tobes' port of my gem to processing at http://github.com/rngtng/launchpad
|
32
|
+
|
33
|
+
|
34
|
+
== Requirements
|
35
|
+
|
36
|
+
* Roger B. Dannenberg's {portmidi library}[http://sourceforge.net/projects/portmedia/]
|
37
|
+
* Jan Krutisch's {portmidi gem}[http://github.com/halfbyte/portmidi]
|
38
|
+
|
39
|
+
|
40
|
+
== Compatibility
|
41
|
+
|
42
|
+
The gem is known to be compatible with the following ruby versions:
|
43
|
+
|
44
|
+
* MRI 1.8.7
|
45
|
+
* MRI 1.9.3
|
46
|
+
* MRI 2.0.0
|
47
|
+
* MRI 2.2.2
|
48
|
+
|
49
|
+
|
50
|
+
== Installation
|
51
|
+
|
52
|
+
The gem is hosted on RubyGems[https://rubygems.org/], so in order to use it, you're gonna gem install it:
|
53
|
+
|
54
|
+
gem install launchpad
|
55
|
+
|
56
|
+
|
57
|
+
== Usage
|
58
|
+
|
59
|
+
There are two main entry points:
|
60
|
+
|
61
|
+
* require 'launchpad/device', providing Launchpad::Device, which handles all the basic input/output stuff
|
62
|
+
* require 'launchpad/interaction' or just 'launchpad', additionally providing Launchpad::Interaction, which lets you respond to actions (button presses/releases)
|
63
|
+
|
64
|
+
This is a simple example (only requiring the device for output) that switches on all LEDs (for testing), resets the launchpad again and then lights the grid button at position 4/4 (from top left).
|
65
|
+
|
66
|
+
require 'launchpad/device'
|
67
|
+
|
68
|
+
device = Launchpad::Device.new
|
69
|
+
device.test_leds
|
70
|
+
sleep 1
|
71
|
+
device.reset
|
72
|
+
sleep 1
|
73
|
+
device.change :grid, :x => 4, :y => 4, :red => :high, :green => :low
|
74
|
+
|
75
|
+
This is an interaction example lighting all grid buttons in red when pressed and keeping them lit.
|
76
|
+
|
77
|
+
require 'launchpad'
|
78
|
+
|
79
|
+
interaction = Launchpad::Interaction.new
|
80
|
+
interaction.response_to(:grid, :down) do |interaction, action|
|
81
|
+
interaction.device.change(:grid, action.merge(:red => :high))
|
82
|
+
end
|
83
|
+
interaction.response_to(:mixer, :down) do |interaction, action|
|
84
|
+
interaction.stop
|
85
|
+
end
|
86
|
+
|
87
|
+
interaction.start
|
88
|
+
|
89
|
+
|
90
|
+
For more details, see the examples. examples/color_picker.rb is the most complex example with interaction.
|
91
|
+
|
92
|
+
|
93
|
+
== Future plans
|
94
|
+
|
95
|
+
* bitmap rendering
|
96
|
+
* internal tracking of LED states for both buffers
|
97
|
+
|
98
|
+
|
99
|
+
== Changelog
|
100
|
+
|
101
|
+
=== v.0.3.0
|
102
|
+
|
103
|
+
* logging
|
104
|
+
* reworked multi threading for action handling
|
105
|
+
* compatibility with ruby 1.8.7 and 2.0.0
|
106
|
+
* interaction responses for presses on single grid buttons/button areas/columns/rows
|
107
|
+
|
108
|
+
=== v.0.2.2
|
109
|
+
|
110
|
+
* single threading fix: prevent ThreadError when Launchpad::Interaction#stop is called within an action response
|
111
|
+
|
112
|
+
=== v.0.2.1
|
113
|
+
|
114
|
+
* Launchpad::Interaction#close now properly stops interaction first
|
115
|
+
* multi threading: Launchpad::Interaction#start method can be called with :detached => true to allow calling thread to continue
|
116
|
+
|
117
|
+
=== v.0.2.0
|
118
|
+
|
119
|
+
* double buffering (see Launchpad::Device#buffering_mode)
|
120
|
+
* don't update grid button 0,0 before change_all (in order to reset rapid update pointer), use MIDI message without visual effect
|
121
|
+
* (at least) doubled the speed of change_all by not sending each message individually but sending them in one go (as an array)
|
122
|
+
|
123
|
+
=== v0.1.1
|
124
|
+
|
125
|
+
* ability to close device/interaction to free portmidi resources
|
126
|
+
* ability to initialize devices using device ids as well as device names
|
127
|
+
* complete documentation for http://rdoc.info/projects/thomasjachmann/launchpad
|
128
|
+
|
129
|
+
=== v0.1.0
|
130
|
+
|
131
|
+
* first feature complete version with kinda stable API
|
132
|
+
|
133
|
+
|
134
|
+
== Copyright
|
135
|
+
|
136
|
+
Copyright (c) 2009 Thomas Jachmann. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'launchpad'
|
2
|
+
|
3
|
+
device = Launchpad::Device.new
|
4
|
+
|
5
|
+
on = { :red => :high, :green => :off }
|
6
|
+
off = { :red => :off, :green => :lo }
|
7
|
+
|
8
|
+
digit_map = [
|
9
|
+
[off, off, off, off],
|
10
|
+
[on , off, off, off],
|
11
|
+
[off, on , off, off],
|
12
|
+
[on , on , off, off],
|
13
|
+
[off, off, on , off],
|
14
|
+
[on , off, on , off],
|
15
|
+
[off, on , on , off],
|
16
|
+
[on , on , on , off],
|
17
|
+
[off, off, off, on ],
|
18
|
+
[on , off, off, on ]
|
19
|
+
]
|
20
|
+
|
21
|
+
while true do
|
22
|
+
Time.now.strftime('%H%M%S').split('').each_with_index do |digit, x|
|
23
|
+
digit_map[digit.to_i].each_with_index do |color, y|
|
24
|
+
device.change :grid, color.merge(:x => x, :y => (7 - y))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
sleep 0.25
|
29
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'launchpad'
|
2
|
+
|
3
|
+
interaction = Launchpad::Interaction.new
|
4
|
+
|
5
|
+
# build color arrays for color display views
|
6
|
+
colors_single = [
|
7
|
+
[ 0, 1, 2, 3, 0, 0, 0, 0],
|
8
|
+
[16, 17, 18, 19, 0, 0, 0, 0],
|
9
|
+
[32, 33, 34, 35, 0, 0, 0, 0],
|
10
|
+
[48, 49, 50, 51, 0, 0, 0, 0],
|
11
|
+
[0] * 8,
|
12
|
+
[0] * 8,
|
13
|
+
[0] * 8,
|
14
|
+
[0] * 8,
|
15
|
+
[0] * 8
|
16
|
+
]
|
17
|
+
colors_double = [
|
18
|
+
[ 0, 0, 1, 1, 2, 2, 3, 3],
|
19
|
+
[ 0, 0, 1, 1, 2, 2, 3, 3],
|
20
|
+
[16, 16, 17, 17, 18, 18, 19, 19],
|
21
|
+
[16, 16, 17, 17, 18, 18, 19, 19],
|
22
|
+
[32, 32, 33, 33, 34, 34, 35, 35],
|
23
|
+
[32, 32, 33, 33, 34, 34, 35, 35],
|
24
|
+
[48, 48, 49, 49, 50, 50, 51, 51],
|
25
|
+
[48, 48, 49, 49, 50, 50, 51, 51],
|
26
|
+
[0] * 8
|
27
|
+
]
|
28
|
+
colors_mirrored = [
|
29
|
+
[ 0, 1, 2, 3, 3, 2, 1, 0],
|
30
|
+
[16, 17, 18, 19, 19, 18, 17, 16],
|
31
|
+
[32, 33, 34, 35, 35, 34, 33, 32],
|
32
|
+
[48, 49, 50, 51, 51, 50, 49, 48],
|
33
|
+
[48, 49, 50, 51, 51, 50, 49, 48],
|
34
|
+
[32, 33, 34, 35, 35, 34, 33, 32],
|
35
|
+
[16, 17, 18, 19, 19, 18, 17, 16],
|
36
|
+
[ 0, 1, 2, 3, 3, 2, 1, 0],
|
37
|
+
[0] * 8
|
38
|
+
]
|
39
|
+
|
40
|
+
# setup color display views
|
41
|
+
def display_color_view(colors)
|
42
|
+
lambda do |interaction, action|
|
43
|
+
# set color
|
44
|
+
interaction.device.change_all(colors)
|
45
|
+
# register mute interactor on scene buttons
|
46
|
+
interaction.response_to(%w(scene1 scene2 scene3 scene4 scene5 scene6 scene7 scene8), :down, :exclusive => true, &@mute)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
interaction.response_to(:up, :down, &display_color_view(colors_single + [48, 16, 16, 16]))
|
50
|
+
interaction.response_to(:down, :down, &display_color_view(colors_double + [16, 48, 16, 16]))
|
51
|
+
interaction.response_to(:left, :down, &display_color_view(colors_mirrored + [16, 16, 48, 16]))
|
52
|
+
|
53
|
+
# setup color picker view
|
54
|
+
def display_color(opts)
|
55
|
+
lambda do |interaction, action|
|
56
|
+
@red = opts[:red] if opts[:red]
|
57
|
+
@green = opts[:green] if opts[:green]
|
58
|
+
colors = [(@green * 16 + @red)] * 64
|
59
|
+
scenes = [@red == 3 ? 51 : 3, @red == 2 ? 51 : 2, @red == 1 ? 51 : 1, @red == 0 ? 51 : 0, @green == 3 ? 51 : 48, @green == 2 ? 51 : 32, @green == 1 ? 51 : 16, @green == 0 ? 51 : 0]
|
60
|
+
interaction.device.change_all(colors + scenes + [16, 16, 16, 48])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
interaction.response_to(:right, :down) do |interaction, action|
|
64
|
+
@red = 0
|
65
|
+
@green = 0
|
66
|
+
# register color picker interactors on scene buttons
|
67
|
+
interaction.response_to(:scene1, :down, :exclusive => true, &display_color(:red => 3))
|
68
|
+
interaction.response_to(:scene2, :down, :exclusive => true, &display_color(:red => 2))
|
69
|
+
interaction.response_to(:scene3, :down, :exclusive => true, &display_color(:red => 1))
|
70
|
+
interaction.response_to(:scene4, :down, :exclusive => true, &display_color(:red => 0))
|
71
|
+
interaction.response_to(:scene5, :down, :exclusive => true, &display_color(:green => 3))
|
72
|
+
interaction.response_to(:scene6, :down, :exclusive => true, &display_color(:green => 2))
|
73
|
+
interaction.response_to(:scene7, :down, :exclusive => true, &display_color(:green => 1))
|
74
|
+
interaction.response_to(:scene8, :down, :exclusive => true, &display_color(:green => 0))
|
75
|
+
# display color
|
76
|
+
interaction.respond_to(:scene8, :down)
|
77
|
+
end
|
78
|
+
|
79
|
+
# mixer button terminates interaction on button up
|
80
|
+
interaction.response_to(:mixer) do |interaction, action|
|
81
|
+
interaction.device.change(:mixer, :red => action[:state] == :down ? :hi : :off)
|
82
|
+
interaction.stop if action[:state] == :up
|
83
|
+
end
|
84
|
+
|
85
|
+
# setup mute display interactors on all unused buttons
|
86
|
+
@mute = display_color_view([0] * 72 + [16, 16, 16, 16])
|
87
|
+
interaction.response_to(%w(session user1 user2 grid), :down, &@mute)
|
88
|
+
|
89
|
+
# display mute view
|
90
|
+
interaction.respond_to(:session, :down)
|
91
|
+
|
92
|
+
# start interacting
|
93
|
+
interaction.start
|
94
|
+
|
95
|
+
# sleep so that the messages can be sent before the program terminates
|
96
|
+
sleep 0.1
|
data/examples/colors.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'launchpad'
|
2
|
+
|
3
|
+
device = Launchpad::Device.new(:input => false, :output => true)
|
4
|
+
|
5
|
+
pos_x = pos_y = 0
|
6
|
+
4.times do |red|
|
7
|
+
4.times do |green|
|
8
|
+
device.change :grid, :x => pos_x, :y => pos_y, :red => red, :green => green
|
9
|
+
device.change :grid, :x => 7 - pos_x, :y => pos_y, :red => red, :green => green
|
10
|
+
device.change :grid, :x => pos_x, :y => 7 - pos_y, :red => red, :green => green
|
11
|
+
device.change :grid, :x => 7 - pos_x, :y => 7 - pos_y, :red => red, :green => green
|
12
|
+
pos_y += 1
|
13
|
+
# sleep, otherwise the connection drops some messages - WTF?
|
14
|
+
sleep 0.01
|
15
|
+
end
|
16
|
+
pos_x += 1
|
17
|
+
pos_y = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
# sleep so that the messages can be sent before the program terminates
|
21
|
+
sleep 0.1
|
data/examples/doodle.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'launchpad'
|
2
|
+
|
3
|
+
interaction = Launchpad::Interaction.new
|
4
|
+
|
5
|
+
current_color = {
|
6
|
+
:red => :hi,
|
7
|
+
:green => :hi,
|
8
|
+
:mode => :normal
|
9
|
+
}
|
10
|
+
|
11
|
+
def update_scene_buttons(d, color)
|
12
|
+
on = {:red => :hi, :green => :hi}
|
13
|
+
d.change(:scene1, color[:red] == :hi ? on : {:red => :hi})
|
14
|
+
d.change(:scene2, color[:red] == :med ? on : {:red => :med})
|
15
|
+
d.change(:scene3, color[:red] == :lo ? on : {:red => :lo})
|
16
|
+
d.change(:scene4, color[:red] == :off ? on : {:red => :off})
|
17
|
+
d.change(:scene5, color[:green] == :hi ? on : {:green => :hi})
|
18
|
+
d.change(:scene6, color[:green] == :med ? on : {:green => :med})
|
19
|
+
d.change(:scene7, color[:green] == :lo ? on : {:green => :lo})
|
20
|
+
d.change(:scene8, color[:green] == :off ? on : {:green => :off})
|
21
|
+
d.change(:user1, :green => color[:mode] == :normal ? :lo : :hi, :mode => :flashing)
|
22
|
+
d.change(:user2, :green => color[:mode] == :normal ? :hi : :lo)
|
23
|
+
end
|
24
|
+
|
25
|
+
def choose_color(color, opts)
|
26
|
+
lambda do |interaction, action|
|
27
|
+
color.update(opts)
|
28
|
+
update_scene_buttons(interaction.device, color)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# register color picker interactors on scene buttons
|
33
|
+
interaction.response_to(:scene1, :down, &choose_color(current_color, :red => :hi))
|
34
|
+
interaction.response_to(:scene2, :down, &choose_color(current_color, :red => :med))
|
35
|
+
interaction.response_to(:scene3, :down, &choose_color(current_color, :red => :lo))
|
36
|
+
interaction.response_to(:scene4, :down, &choose_color(current_color, :red => :off))
|
37
|
+
interaction.response_to(:scene5, :down, &choose_color(current_color, :green => :hi))
|
38
|
+
interaction.response_to(:scene6, :down, &choose_color(current_color, :green => :med))
|
39
|
+
interaction.response_to(:scene7, :down, &choose_color(current_color, :green => :lo))
|
40
|
+
interaction.response_to(:scene8, :down, &choose_color(current_color, :green => :off))
|
41
|
+
|
42
|
+
# register mode picker interactors on user buttons
|
43
|
+
interaction.response_to(:user1, :down, &choose_color(current_color, :mode => :flashing))
|
44
|
+
interaction.response_to(:user2, :down, &choose_color(current_color, :mode => :normal))
|
45
|
+
|
46
|
+
# update scene buttons and start flashing
|
47
|
+
update_scene_buttons(interaction.device, current_color)
|
48
|
+
interaction.device.flashing_auto
|
49
|
+
|
50
|
+
# feedback for grid buttons
|
51
|
+
interaction.response_to(:grid, :down) do |interaction, action|
|
52
|
+
#coord = 16 * action[:y] + action[:x]
|
53
|
+
#brightness = flags[coord] ? :off : :hi
|
54
|
+
#flags[coord] = !flags[coord]
|
55
|
+
interaction.device.change(:grid, action.merge(current_color))
|
56
|
+
end
|
57
|
+
|
58
|
+
# mixer button terminates interaction on button up
|
59
|
+
interaction.response_to(:mixer) do |interaction, action|
|
60
|
+
interaction.device.change(:mixer, :red => action[:state] == :down ? :hi : :off)
|
61
|
+
interaction.stop if action[:state] == :up
|
62
|
+
end
|
63
|
+
|
64
|
+
# start interacting
|
65
|
+
interaction.start
|
66
|
+
|
67
|
+
# sleep so that the messages can be sent before the program terminates
|
68
|
+
sleep 0.1
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'launchpad'
|
2
|
+
|
3
|
+
interaction = Launchpad::Interaction.new
|
4
|
+
|
5
|
+
# store and change button states, ugly but well...
|
6
|
+
@button_states = [
|
7
|
+
[false, false, false, false, false, false, false, false],
|
8
|
+
[false, false, false, false, false, false, false, false],
|
9
|
+
[[false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false]],
|
10
|
+
[[false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false]],
|
11
|
+
[[false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false]],
|
12
|
+
[[false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false]],
|
13
|
+
[[false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false]],
|
14
|
+
[[false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false], [false, false]]
|
15
|
+
]
|
16
|
+
def change_button_state(action)
|
17
|
+
if action[:y] > 1
|
18
|
+
which = @active_buffer_button == :user2 ? 1 : 0
|
19
|
+
@button_states[action[:y]][action[:x]][which] = !@button_states[action[:y]][action[:x]][which]
|
20
|
+
else
|
21
|
+
@button_states[action[:y]][action[:x]] = !@button_states[action[:y]][action[:x]]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# setup grid buttons to:
|
26
|
+
# * set LEDs in normal mode on the first row
|
27
|
+
# * set LEDs in flashing mode on the second row
|
28
|
+
# * set LEDs in buffering mode on all other rows
|
29
|
+
interaction.response_to(:grid, :down) do |interaction, action|
|
30
|
+
color = change_button_state(action) ? @color : {}
|
31
|
+
case action[:y]
|
32
|
+
when 0
|
33
|
+
interaction.device.change(:grid, action.merge(color))
|
34
|
+
when 1
|
35
|
+
interaction.device.buffering_mode(:flashing => false, :display_buffer => 1, :update_buffer => 0)
|
36
|
+
interaction.device.change(:grid, action.merge(color).merge(:mode => :flashing))
|
37
|
+
interaction.respond_to(@active_buffer_button, :down)
|
38
|
+
else
|
39
|
+
interaction.device.change(:grid, action.merge(color).merge(:mode => :buffering))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# green feedback for buffer buttons
|
44
|
+
interaction.response_to([:session, :user1, :user2], :down) do |interaction, action|
|
45
|
+
case @active_buffer_button = action[:type]
|
46
|
+
when :session
|
47
|
+
interaction.device.buffering_mode(:flashing => true)
|
48
|
+
when :user1
|
49
|
+
interaction.device.buffering_mode(:display_buffer => 0, :update_buffer => 0)
|
50
|
+
when :user2
|
51
|
+
interaction.device.buffering_mode(:display_buffer => 1, :update_buffer => 1)
|
52
|
+
end
|
53
|
+
interaction.device.change(:session, :red => @active_buffer_button == :session ? :hi : :lo, :green => @active_buffer_button == :session ? :hi : :lo)
|
54
|
+
interaction.device.change(:user1, :red => @active_buffer_button == :user1 ? :hi : :lo, :green => @active_buffer_button == :user1 ? :hi : :lo)
|
55
|
+
interaction.device.change(:user2, :red => @active_buffer_button == :user2 ? :hi : :lo, :green => @active_buffer_button == :user2 ? :hi : :lo)
|
56
|
+
end
|
57
|
+
|
58
|
+
# setup color picker
|
59
|
+
def display_color(opts)
|
60
|
+
lambda do |interaction, action|
|
61
|
+
@red = opts[:red] if opts[:red]
|
62
|
+
@green = opts[:green] if opts[:green]
|
63
|
+
if @red == 0 && @green == 0
|
64
|
+
@red = 1 if opts[:red]
|
65
|
+
@green = 1 if opts[:green]
|
66
|
+
end
|
67
|
+
@color = {:red => @red, :green => @green}
|
68
|
+
on = {:red => 3, :green => 3}
|
69
|
+
interaction.device.change(:scene1, @red == 3 ? on : {:red => 3})
|
70
|
+
interaction.device.change(:scene2, @red == 2 ? on : {:red => 2})
|
71
|
+
interaction.device.change(:scene3, @red == 1 ? on : {:red => 1})
|
72
|
+
interaction.device.change(:scene4, @red == 0 ? on : {:red => 0})
|
73
|
+
interaction.device.change(:scene5, @green == 3 ? on : {:green => 3})
|
74
|
+
interaction.device.change(:scene6, @green == 2 ? on : {:green => 2})
|
75
|
+
interaction.device.change(:scene7, @green == 1 ? on : {:green => 1})
|
76
|
+
interaction.device.change(:scene8, @green == 0 ? on : {:green => 0})
|
77
|
+
end
|
78
|
+
end
|
79
|
+
# register color picker interactors on scene buttons
|
80
|
+
interaction.response_to(:scene1, :down, :exclusive => true, &display_color(:red => 3))
|
81
|
+
interaction.response_to(:scene2, :down, :exclusive => true, &display_color(:red => 2))
|
82
|
+
interaction.response_to(:scene3, :down, :exclusive => true, &display_color(:red => 1))
|
83
|
+
interaction.response_to(:scene4, :down, :exclusive => true, &display_color(:red => 0))
|
84
|
+
interaction.response_to(:scene5, :down, :exclusive => true, &display_color(:green => 3))
|
85
|
+
interaction.response_to(:scene6, :down, :exclusive => true, &display_color(:green => 2))
|
86
|
+
interaction.response_to(:scene7, :down, :exclusive => true, &display_color(:green => 1))
|
87
|
+
interaction.response_to(:scene8, :down, :exclusive => true, &display_color(:green => 0))
|
88
|
+
# pick green
|
89
|
+
interaction.respond_to(:scene5, :down)
|
90
|
+
|
91
|
+
# mixer button terminates interaction on button up
|
92
|
+
interaction.response_to(:mixer) do |interaction, action|
|
93
|
+
interaction.device.change(:mixer, :red => action[:state] == :down ? :hi : :off)
|
94
|
+
interaction.stop if action[:state] == :up
|
95
|
+
end
|
96
|
+
|
97
|
+
# start in auto flashing mode
|
98
|
+
interaction.respond_to(:session, :down)
|
99
|
+
|
100
|
+
# start interacting
|
101
|
+
interaction.start
|
102
|
+
|
103
|
+
# sleep so that the messages can be sent before the program terminates
|
104
|
+
sleep 0.1
|