Ableton Control Surface for Roland TD-27KV2 Drum Kit
This script provides a basic mapping for the Roland TD-27KV2 drum kit.
TD27.py
Save TD27.py in \Resources\MIDI Remote Scripts\TD27\
from __future__ import absolute_import, print_function, unicode_literals
from _Framework.ControlSurface import ControlSurface
from _Framework.InputControlElement import MIDI_NOTE_TYPE, MIDI_CC_TYPE
from _Framework.ButtonElement import ButtonElement
from _Framework.EncoderElement import EncoderElement
from _Framework.TransportComponent import TransportComponent
from _Framework.DeviceComponent import DeviceComponent
from _Framework.MidiMap import MidiMap
from _Framework.Layer import Layer
class TD27(ControlSurface):
def __init__(self, c_instance):
ControlSurface.__init__(self, c_instance)
self.log_message("Roland TD-27 Control Surface Initialized")
with self.component_guard():
self._setup_midi_map()
self._setup_transport_control()
self._setup_device_control()
def _setup_midi_map(self):
self._drum_pads = {
"Kick_Drum": ButtonElement(True, MIDI_NOTE_TYPE, 9, 36),
"Snare_Drum": ButtonElement(True, MIDI_NOTE_TYPE, 9, 38),
"Snare_Rim": ButtonElement(True, MIDI_NOTE_TYPE, 9, 40),
"Snare_Brush": ButtonElement(True, MIDI_NOTE_TYPE, 9, 37),
"Snare_CrossStick": ButtonElement(True, MIDI_NOTE_TYPE, 9, 39),
"Tom1_Drum": ButtonElement(True, MIDI_NOTE_TYPE, 9, 48),
"Tom1_Rim": ButtonElement(True, MIDI_NOTE_TYPE, 9, 50),
"Tom2_Drum": ButtonElement(True, MIDI_NOTE_TYPE, 9, 45),
"Tom2_Rim": ButtonElement(True, MIDI_NOTE_TYPE, 9, 47),
"Tom3_Drum": ButtonElement(True, MIDI_NOTE_TYPE, 9, 43),
"Tom3_Rim": ButtonElement(True, MIDI_NOTE_TYPE, 9, 58),
"HiHat_Bow": ButtonElement(True, MIDI_NOTE_TYPE, 9, 46),
"HiHat_Edge": ButtonElement(True, MIDI_NOTE_TYPE, 9, 26),
"HiHat_ClosedEdge": ButtonElement(True, MIDI_NOTE_TYPE, 9, 42),
"HiHat_Pedal": ButtonElement(True, MIDI_NOTE_TYPE, 9, 44),
"Ride_Bow": ButtonElement(True, MIDI_NOTE_TYPE, 9, 51),
"Ride_Edge": ButtonElement(True, MIDI_NOTE_TYPE, 9, 59),
"Ride_Bell": ButtonElement(True, MIDI_NOTE_TYPE, 9, 53),
"Crash1_Bow": ButtonElement(True, MIDI_NOTE_TYPE, 9, 49),
"Crash1_Edge": ButtonElement(True, MIDI_NOTE_TYPE, 9, 57),
"Crash2_Bow": ButtonElement(True, MIDI_NOTE_TYPE, 9, 81),
"Crash2_Edge": ButtonElement(True, MIDI_NOTE_TYPE, 9, 82),
"Ride_Choke": ButtonElement(True, MIDI_NOTE_TYPE, 9, 51),
"Crash1_Choke": ButtonElement(True, MIDI_NOTE_TYPE, 9, 49),
"Crash2_Choke": ButtonElement(True, MIDI_NOTE_TYPE, 9, 57),
}
self._positional_controls = {
"Snare_Position": EncoderElement(MIDI_CC_TYPE, 9, 1, MidiMap.MapMode.absolute),
"Tom1_Position": EncoderElement(MIDI_CC_TYPE, 9, 18, MidiMap.MapMode.absolute),
"Tom2_Position": EncoderElement(MIDI_CC_TYPE, 9, 19, MidiMap.MapMode.absolute),
"Tom3_Position": EncoderElement(MIDI_CC_TYPE, 9, 11, MidiMap.MapMode.absolute),
"HiHat_Pedal": EncoderElement(MIDI_CC_TYPE, 9, 4, MidiMap.MapMode.absolute),
"HiHat_LR_Position": EncoderElement(MIDI_CC_TYPE, 9, 16, MidiMap.MapMode.absolute),
"Ride_Position": EncoderElement(MIDI_CC_TYPE, 9, 11, MidiMap.MapMode.absolute),
}
self._other_controls = {
"Modulation": ButtonElement(True, MIDI_CC_TYPE, 9, 1),
"Breath_Controller": ButtonElement(True, MIDI_CC_TYPE, 9, 2),
"Foot_Controller": ButtonElement(True, MIDI_CC_TYPE, 9, 4),
"Expression": ButtonElement(True, MIDI_CC_TYPE, 9, 11),
"General_Purpose_Controller_1": ButtonElement(True, MIDI_CC_TYPE, 9, 16),
"General_Purpose_Controller_2": ButtonElement(True, MIDI_CC_TYPE, 9, 17),
"General_Purpose_Controller_3": ButtonElement(True, MIDI_CC_TYPE, 9, 18),
"General_Purpose_Controller_4": ButtonElement(True, MIDI_CC_TYPE, 9, 19),
"General_Purpose_Controller_5": ButtonElement(True, MIDI_CC_TYPE, 9, 80),
"General_Purpose_Controller_6": ButtonElement(True, MIDI_CC_TYPE, 9, 81),
"General_Purpose_Controller_7": ButtonElement(True, MIDI_CC_TYPE, 9, 82),
"General_Purpose_Controller_8": ButtonElement(True, MIDI_CC_TYPE, 9, 83),
"High_Resolution_Velocity": ButtonElement(True, MIDI_CC_TYPE, 9, 88),
}
def _setup_transport_control(self):
self._transport = TransportComponent()
self._transport.layer = Layer(
play_button=self._drum_pads["Kick_Drum"],
stop_button=self._drum_pads["Snare_Drum"],
)
def _setup_device_control(self):
self._device = DeviceComponent()
self._device.layer = Layer(
parameter_controls=[
self._positional_controls["Snare_Position"],
self._positional_controls["HiHat_Pedal"],
self._positional_controls["Ride_Position"],
self._other_controls["Modulation"],
self._other_controls["Breath_Controller"],
self._other_controls["Foot_Controller"],
self._other_controls["Expression"],
self._other_controls["General_Purpose_Controller_1"],
self._other_controls["General_Purpose_Controller_2"],
self._other_controls["General_Purpose_Controller_3"],
self._other_controls["General_Purpose_Controller_4"],
self._other_controls["General_Purpose_Controller_5"],
self._other_controls["General_Purpose_Controller_6"],
self._other_controls["General_Purpose_Controller_7"],
self._other_controls["General_Purpose_Controller_8"],
]
)
def disconnect(self):
self.log_message("Roland TD-27 Control Surface Disconnected")
ControlSurface.disconnect(self)
_ init.py
Save _init.py_ to \Resources\MIDI Remote Scripts\TD27\
from __future__ import absolute_import, print_function, unicode_literals
from .TD27 import TD27
def create_instance(c_instance):
return TD27(c_instance)
We can extend the above with a Kontakt script to enhance the expressiveness of the Roland TD-27KV2 control surface.
on init
message("Roland TD-27KV2 Kontakt Script Initialized")
declare const $KICK_NOTE := 36
declare const $SNARE_NOTE := 38
declare const $SNARE_RIM_NOTE := 40
declare const $HH_CLOSED_NOTE := 42
declare const $HH_PEDAL_NOTE := 44
declare const $HH_OPEN_NOTE := 46
declare const $TOM1_NOTE := 48
declare const $TOM2_NOTE := 45
declare const $TOM3_NOTE := 43
declare const $CRASH1_NOTE := 49
declare const $CRASH2_NOTE := 57
declare const $RIDE_BOW_NOTE := 51
declare const $RIDE_BELL_NOTE := 53
declare $velocity
declare $position
declare $hh_openness
declare ui_knob $snare_pos_sens (0, 100, 1)
set_knob_unit($snare_pos_sens, $KNOB_UNIT_PERCENT)
set_knob_defval($snare_pos_sens, 50)
declare ui_knob $cymbal_choke_time (0, 1000, 1)
set_knob_unit($cymbal_choke_time, $KNOB_UNIT_MS)
set_knob_defval($cymbal_choke_time, 50)
declare ui_switch $use_cc_hihat
set_text($use_cc_hihat, "Use CC for Hi-Hat")
end on
on note
$velocity := $EVENT_VELOCITY
select ($EVENT_NOTE)
case $SNARE_NOTE
$position := get_controller(16) // Assuming CC 16 for snare position
$velocity := $velocity + (($position - 64) * $snare_pos_sens / 100)
$velocity := max(1, min(127, $velocity))
case $HH_CLOSED_NOTE, $HH_OPEN_NOTE
if ($use_cc_hihat = 1)
$hh_openness := get_controller(4) // Assuming CC 4 for hi-hat pedal
$velocity := $velocity * (128 - $hh_openness) / 128
end if
case $CRASH1_NOTE, $CRASH2_NOTE, $RIDE_BOW_NOTE, $RIDE_BELL_NOTE
start_timer($cymbal_choke_time) // Start choke timer for cymbals
end select
set_event_par($EVENT_ID, $EVENT_PAR_VOLUME, $velocity * 1000 / 127)
end on
on controller
if ($CC_NUM = 4 and $use_cc_hihat = 1) // Hi-hat pedal CC
$hh_openness := $CC_VALUE
set_engine_par($ENGINE_PAR_CUTOFF, $hh_openness * 1000 / 127, 0, 0, -1)
end if
end on
on timer
// Implement cymbal choking
fade_out(0, 10000, 1) // Fade out all groups over 10ms
end on
on ui_control($use_cc_hihat)
if ($use_cc_hihat = 1)
message("Hi-Hat control set to CC mode")
else
message("Hi-Hat control set to velocity mode")
end if
end on
Buy me a coffee
Don’t be shy; if you found this useful, say Hi!