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!