Class: LaunchpadMk2::Device

Inherits:
Object
  • Object
show all
Includes:
Logging, MidiCodes
Defined in:
lib/launchpad_mk2/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_mk2/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 collapse

MK2_DEVICE_NAME =
'Launchpad MK2 MIDI 1'
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
SYSEX_HEADER =
[240, 0, 32, 41, 2, 24]
[247]

Instance Method Summary collapse

Methods included from Logging

#logger, #logger=

Constructor Details

#initialize(opts = nil) ⇒ Device

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



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

def initialize(opts = nil)
  @input = nil
  @output = 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]
end

Instance Method Details

#change(type, opts = nil) ⇒ Object

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

color

color of the LED (value between 0 and 127 inclusive) optional, defaults to :off

Errors raised:

Launchpad::NoValidGridCoordinatesError

when coordinates aren’t within the valid range

Launchpad::NoValidColorError

when color value isn’t within the valid range

Launchpad::NoOutputAllowedError

when output is not enabled



154
155
156
157
158
# File 'lib/launchpad_mk2/device.rb', line 154

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

#closeObject

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



113
114
115
116
117
118
119
# File 'lib/launchpad_mk2/device.rb', line 113

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

#closed?Boolean

Determines whether this device has been closed.

Returns:

  • (Boolean)


122
123
124
# File 'lib/launchpad_mk2/device.rb', line 122

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

#flash1(x, y, color_key) ⇒ Object



175
176
177
178
# File 'lib/launchpad_mk2/device.rb', line 175

def flash1(x, y, color_key)
  note = note(:grid, {:x => x, :y => y})
  output_sysex(SYSEX_HEADER + [35, 0, note, color_key] + SYSEX_FOOTER)
end

#flashn(notes, color_key) ⇒ Object



180
181
182
183
184
185
# File 'lib/launchpad_mk2/device.rb', line 180

def flashn(notes, color_key)
  notes.each { |coord|
    note = note(:grid, {:x => coord[0], :y => coord[1]})
    output_sysex(SYSEX_HEADER + [35, 0, note, color_key, 0] + SYSEX_FOOTER)
  }
end

#input_enabled?Boolean

Determines whether this device can be used to read input.

Returns:

  • (Boolean)


127
128
129
# File 'lib/launchpad_mk2/device.rb', line 127

def input_enabled?
  !@input.nil?
end

#light1_column(column_key, color_key) ⇒ Object



217
218
219
# File 'lib/launchpad_mk2/device.rb', line 217

def light1_column(column_key, color_key)
  output_sysex(SYSEX_HEADER + [12, column_key, color_key] + SYSEX_FOOTER)
end

#light1_row(row_key, color_key) ⇒ Object



227
228
229
# File 'lib/launchpad_mk2/device.rb', line 227

def light1_row(row_key, color_key)
  output_sysex(SYSEX_HEADER + [13, row_key, color_key] + SYSEX_FOOTER)
end

#light_all(color_key) ⇒ Object



203
204
205
# File 'lib/launchpad_mk2/device.rb', line 203

def light_all(color_key)
  output_sysex(SYSEX_HEADER + [14, color_key] + SYSEX_FOOTER)
end

#lightn_column(column_keys, color_key) ⇒ Object



211
212
213
214
215
# File 'lib/launchpad_mk2/device.rb', line 211

def lightn_column(column_keys, color_key)
  column_keys.each { |column_key|
    output_sysex(SYSEX_HEADER + [12, column_key, color_key] + SYSEX_FOOTER)
  }
end

#lightn_row(rows_keys, color_key) ⇒ Object



221
222
223
224
225
# File 'lib/launchpad_mk2/device.rb', line 221

def lightn_row(rows_keys, color_key)
  rows_keys.each { |row_key|
  output_sysex(SYSEX_HEADER + [13, row_key, color_key] + SYSEX_FOOTER)
  }
end

#output_enabled?Boolean

Determines whether this device can be used to output data.

Returns:

  • (Boolean)


132
133
134
# File 'lib/launchpad_mk2/device.rb', line 132

def output_enabled?
  !@output.nil?
end

#pulse1(x, y, color_key) ⇒ Object



163
164
165
166
# File 'lib/launchpad_mk2/device.rb', line 163

def pulse1(x, y, color_key)
  note = note(:grid, {:x => x, :y => y})
  output_sysex(SYSEX_HEADER + [40, 0, note, color_key] + SYSEX_FOOTER)
end

#pulsen(notes, color_key) ⇒ Object



168
169
170
171
172
173
# File 'lib/launchpad_mk2/device.rb', line 168

def pulsen(notes, color_key)
  notes.each { |coord|
    note = note(:grid, {:x => coord[0], :y => coord[1]})
    output_sysex(SYSEX_HEADER + [40, 0, note, color_key] + SYSEX_FOOTER)
  }
end

#read_pending_actionsObject

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



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/launchpad_mk2/device.rb', line 247

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 % 10) - 1
      data[:y] = (note / 10) - 1
    end
    data
  end
end

#reset_allObject



207
208
209
# File 'lib/launchpad_mk2/device.rb', line 207

def reset_all()
  light_all(0)
end

#scroll(color_key, text, mode) ⇒ Object



187
188
189
# File 'lib/launchpad_mk2/device.rb', line 187

def scroll(color_key, text, mode)
  output_sysex(SYSEX_HEADER + [20, color_key, mode] + text.chars.map(&:ord) + SYSEX_FOOTER)
end

#scroll_forever(color_key, text) ⇒ Object



191
192
193
# File 'lib/launchpad_mk2/device.rb', line 191

def scroll_forever(color_key, text)
  scroll(color_key, text, 1)
end

#scroll_once(color_key, text) ⇒ Object



195
196
197
# File 'lib/launchpad_mk2/device.rb', line 195

def scroll_once(color_key, text)
  scroll(color_key, text, 0)
end

#scroll_stopObject



199
200
201
# File 'lib/launchpad_mk2/device.rb', line 199

def scroll_stop()
  output_sysex(SYSEX_HEADER + [20] + SYSEX_FOOTER)
end