Class: Launchpad::Device

Inherits:
Object
  • Object
show all
Includes:
Logging, MidiCodes
Defined in:
lib/launchpad/device.rb

Overview

This class is used to exchange data with the launchpad. It provides methods to light LEDs and to get information about button presses/releases.

Example:

require 'launchpad/device'

device = Launchpad::Device.new
device.test_leds
sleep 1
device.reset
sleep 1
device.change :grid, :x => 4, :y => 4, :red => :high, :green => :low

Constant Summary

CODE_NOTE_TO_DATA_TYPE =
{
  [Status::ON, SceneButton::SCENE1]     => :scene1,
  [Status::ON, SceneButton::SCENE2]     => :scene2,
  [Status::ON, SceneButton::SCENE3]     => :scene3,
  [Status::ON, SceneButton::SCENE4]     => :scene4,
  [Status::ON, SceneButton::SCENE5]     => :scene5,
  [Status::ON, SceneButton::SCENE6]     => :scene6,
  [Status::ON, SceneButton::SCENE7]     => :scene7,
  [Status::ON, SceneButton::SCENE8]     => :scene8,
  [Status::CC, ControlButton::UP]       => :up,
  [Status::CC, ControlButton::DOWN]     => :down,
  [Status::CC, ControlButton::LEFT]     => :left,
  [Status::CC, ControlButton::RIGHT]    => :right,
  [Status::CC, ControlButton::SESSION]  => :session,
  [Status::CC, ControlButton::USER1]    => :user1,
  [Status::CC, ControlButton::USER2]    => :user2,
  [Status::CC, ControlButton::MIXER]    => :mixer
}.freeze
TYPE_TO_NOTE =
{
  :up       => ControlButton::UP,
  :down     => ControlButton::DOWN,
  :left     => ControlButton::LEFT,
  :right    => ControlButton::RIGHT,
  :session  => ControlButton::SESSION,
  :user1    => ControlButton::USER1,
  :user2    => ControlButton::USER2,
  :mixer    => ControlButton::MIXER,
  :scene1   => SceneButton::SCENE1,
  :scene2   => SceneButton::SCENE2,
  :scene3   => SceneButton::SCENE3,
  :scene4   => SceneButton::SCENE4,
  :scene5   => SceneButton::SCENE5,
  :scene6   => SceneButton::SCENE6,
  :scene7   => SceneButton::SCENE7,
  :scene8   => SceneButton::SCENE8
}.freeze

Instance Method Summary (collapse)

Methods included from Logging

#logger, #logger=

Constructor Details

- (Device) initialize(opts = nil)

Initializes the launchpad device. When output capabilities are requested, the launchpad will be reset.

Optional options hash:

:input

whether to use MIDI input for user interaction, true/false, optional, defaults to true

:output

whether to use MIDI output for data display, true/false, optional, defaults to true

:input_device_id

ID of the MIDI input device to use, optional, :device_name will be used if omitted

:output_device_id

ID of the MIDI output device to use, optional, :device_name will be used if omitted

:device_name

Name of the MIDI device to use, optional, defaults to “Launchpad”

:logger
Logger

to be used by this device instance, can be changed afterwards

Errors raised:

Launchpad::NoSuchDeviceError

when device with ID or name specified does not exist

Launchpad::DeviceBusyError

when device with ID or name specified is busy



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/launchpad/device.rb', line 87

def initialize(opts = nil)
  opts = {
    :input        => true,
    :output       => true
  }.merge(opts || {})
  
  self.logger = opts[:logger]
  logger.debug "initializing Launchpad::Device##{object_id} with #{opts.inspect}"

  Portmidi.start
  
  @input = create_device!(Portmidi.input_devices, Portmidi::Input,
    :id => opts[:input_device_id],
    :name => opts[:device_name]
  ) if opts[:input]
  @output = create_device!(Portmidi.output_devices, Portmidi::Output,
    :id => opts[:output_device_id],
    :name => opts[:device_name]
  ) if opts[:output]

  reset if output_enabled?
end

Instance Method Details

- (Object) buffering_mode(opts = nil)

Controls the two buffers.

Optional options hash:

:display_buffer

which buffer to use for display, defaults to 0

:update_buffer

which buffer to use for updates when :mode is set to :buffering, defaults to 0 (see change)

:copy

whether to copy the LEDs states from the new display_buffer over to the new update_buffer, true/false, defaults to false

:flashing

whether to start flashing by automatically switching between the two buffers for display, true/false, defaults to false

Errors raised:

Launchpad::NoOutputAllowedError

when output is not enabled



268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/launchpad/device.rb', line 268

def buffering_mode(opts = nil)
  opts = {
    :display_buffer => 0,
    :update_buffer => 0,
    :copy => false,
    :flashing => false
  }.merge(opts || {})
  data = opts[:display_buffer] + 4 * opts[:update_buffer] + 32
  data += 16 if opts[:copy]
  data += 8 if opts[:flashing]
  output(Status::CC, Status::NIL, data)
end

- (Object) change(type, opts = nil)

Changes a single LED.

Parameters (see Launchpad for values):

type

type of the button to change

Optional options hash (see Launchpad for values):

:x

x coordinate

:y

y coordinate

:red

brightness of red LED

:green

brightness of green LED

:mode

button mode, defaults to :normal, one of:

<tt>:normal/tt>

updates the LED for all circumstances (the new value will be written to both buffers)

<tt>:flashing/tt>

updates the LED for flashing (the new value will be written to buffer 0 while the LED will be off in buffer 1, see buffering_mode)

<tt>:buffering/tt>

updates the LED for the current update_buffer only

Errors raised:

Launchpad::NoValidGridCoordinatesError

when coordinates aren't within the valid range

Launchpad::NoValidBrightnessError

when brightness values aren't within the valid range

Launchpad::NoOutputAllowedError

when output is not enabled



183
184
185
186
187
# File 'lib/launchpad/device.rb', line 183

def change(type, opts = nil)
  opts ||= {}
  status = %w(up down left right session user1 user2 mixer).include?(type.to_s) ? Status::CC : Status::ON
  output(status, note(type, opts), velocity(opts))
end

- (Object) change_all(*colors)

Changes all LEDs in batch mode.

Parameters (see Launchpad for values):

+colors

an array of colors, each either being an integer or a Hash

  • integer: calculated using the formula color = 16 * green + red

  • Hash:

    :red

    brightness of red LED

    :green

    brightness of green LED

    :mode

    button mode, defaults to :normal, one of:

    <tt>:normal/tt>

    updates the LEDs for all circumstances (the new value will be written to both buffers)

    <tt>:flashing/tt>

    updates the LEDs for flashing (the new values will be written to buffer 0 while the LEDs will be off in buffer 1, see buffering_mode)

    <tt>:buffering/tt>

    updates the LEDs for the current update_buffer only

the array consists of 64 colors for the grid buttons, 8 colors for the scene buttons (top to bottom) and 8 colors for the top control buttons (left to right), maximum 80 values - excessive values will be ignored, missing values will be filled with 0

Errors raised:

Launchpad::NoValidBrightnessError

when brightness values aren't within the valid range

Launchpad::NoOutputAllowedError

when output is not enabled



213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/launchpad/device.rb', line 213

def change_all(*colors)
  # ensure that colors is at least and most 80 elements long
  colors = colors.flatten[0..79]
  colors += [0] * (80 - colors.size) if colors.size < 80
  # send normal MIDI message to reset rapid LED change pointer
  # in this case, set mapping mode to x-y layout (the default)
  output(Status::CC, Status::NIL, GridLayout::XY)
  # send colors in slices of 2
  messages = []
  colors.each_slice(2) do |c1, c2|
    messages << message(Status::MULTI, velocity(c1), velocity(c2))
  end
  output_messages(messages)
end

- (Object) close

Closes the device - nothing can be done with the device afterwards.



111
112
113
114
115
116
117
# File 'lib/launchpad/device.rb', line 111

def close
  logger.debug "closing Launchpad::Device##{object_id}"
  @input.close unless @input.nil?
  @input = nil
  @output.close unless @output.nil?
  @output = nil
end

- (Boolean) closed?

Determines whether this device has been closed.



120
121
122
# File 'lib/launchpad/device.rb', line 120

def closed?
  !(input_enabled? || output_enabled?)
end

- (Object) flashing_auto

Starts flashing LEDs marked as flashing automatically. Stop flashing by calling flashing_on or flashing_off.

Errors raised:

Launchpad::NoOutputAllowedError

when output is not enabled



252
253
254
# File 'lib/launchpad/device.rb', line 252

def flashing_auto
  buffering_mode(:flashing => true)
end

- (Object) flashing_off

Switches LEDs marked as flashing off when using custom timer for flashing.

Errors raised:

Launchpad::NoOutputAllowedError

when output is not enabled



242
243
244
# File 'lib/launchpad/device.rb', line 242

def flashing_off
  buffering_mode(:display_buffer => 1)
end

- (Object) flashing_on

Switches LEDs marked as flashing on when using custom timer for flashing.

Errors raised:

Launchpad::NoOutputAllowedError

when output is not enabled



233
234
235
# File 'lib/launchpad/device.rb', line 233

def flashing_on
  buffering_mode(:display_buffer => 0)
end

- (Boolean) input_enabled?

Determines whether this device can be used to read input.



125
126
127
# File 'lib/launchpad/device.rb', line 125

def input_enabled?
  !@input.nil?
end

- (Boolean) output_enabled?

Determines whether this device can be used to output data.



130
131
132
# File 'lib/launchpad/device.rb', line 130

def output_enabled?
  !@output.nil?
end

- (Object) read_pending_actions

Reads user actions (button presses/releases) that haven't been handled yet. This is non-blocking, so when nothing happend yet you'll get an empty array.

Returns:

an array of hashes with (see Launchpad for values):

:timestamp

integer indicating the time when the action occured

:state

state of the button after action

:type

type of the button

:x

x coordinate

:y

y coordinate

Errors raised:

Launchpad::NoInputAllowedError

when input is not enabled



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/launchpad/device.rb', line 297

def read_pending_actions
  Array(input).collect do |midi_message|
    (code, note, velocity) = midi_message[:message]
    data = {
      :timestamp  => midi_message[:timestamp],
      :state      => (velocity == 127 ? :down : :up)
    }
    data[:type] = CODE_NOTE_TO_DATA_TYPE[[code, note]] || :grid
    if data[:type] == :grid
      data[:x] = note % 16
      data[:y] = note / 16
    end
    data
  end
end

- (Object) reset

Resets the launchpad - all settings are reset and all LEDs are switched off.

Errors raised:

Launchpad::NoOutputAllowedError

when output is not enabled



139
140
141
# File 'lib/launchpad/device.rb', line 139

def reset
  output(Status::CC, Status::NIL, Status::NIL)
end

- (Object) test_leds(brightness = :high)

Lights all LEDs (for testing purposes).

Parameters (see Launchpad for values):

brightness

brightness of both LEDs for all buttons

Errors raised:

Launchpad::NoOutputAllowedError

when output is not enabled



152
153
154
155
156
157
158
159
# File 'lib/launchpad/device.rb', line 152

def test_leds(brightness = :high)
  brightness = brightness(brightness)
  if brightness == 0
    reset
  else
    output(Status::CC, Status::NIL, Velocity::TEST_LEDS + brightness)
  end
end