From BlenderWiki

Jump to: navigation, search
HID Mapper
Maps HID devices (e.g. MIDI devices) to custom blender functions.
UI location View Text Editor > Templates > HID Mapping
Usage Create a HID Mapping script similar to the provided template and run it. Then you can control blender with your MIDI device like specified in your mapping.
Version 0.2 (2012-06-06) Author(s) David Gnedt, Manuel Steiner, Christian Voglhuber
Blender >= 2.61 (except 2.63/2.63a), not:2.79 License GPL
Category System Distribution Extern
Note(s) Doesn't run with Blender 2.63/2.63a because of broken multiprocessing module. Also doesn't run in 2.79 and later (releases 2.64-2.78 not tested).

Executable information
File name
Current version download
Python modules atexit, functools, inspect, threading, multiprocessing, subprocess
External Python Modules or dependencies amidi executable (can be found in alsa-utils package)

Warning Currently only tested on Linux with ALSA

Sample mapping

This mapping is also provided within Blender under Text Editor > Templates > HID Mapping.

# Functions:
#   reset_mapper()
# Constructors/Factories:
#   AMidiSubsystem.create(device=<Device>, name=<Device Name>, debug=<True/False*>)
#   MidiMessageType(status=<Status>, control=<Control>)
# Mapping class decorators:
#   register_mapping(<subsystem>)
# Mapping method decorators:
#   map_message(<MessageType>)
#   switch_pressed(value=<Pressed Value/0x7F*>)
#   switch_released(value=<Released Value/0x00*>)
#   relative_value(max=<Max Value/0x80*>, break=<Break Point Value/0x40*>)
#   merge(type=<MergeType.LAST*/MergeType.SUM>)
# MIDI message methods:
#   msg.get_status()
#   msg.get_control()
#   msg.get_value()
import bpy
from system_hid_mapper import *
@register_mapping(AMidiSubsystem.create(name='TotalTrack Control MIDI 1', debug=True))
class VSEMapping(object):
    @map_message(MidiMessageType(status=144, control=67)) # play left
    def play(self, msg):
        ''' play '''
    @map_message(MidiMessageType(status=144, control=51)) # pause left
    def pause(self, msg):
        ''' pause '''
    def seek(self, value):
        ''' move current frame '''
        bpy.context.scene.frame_current = bpy.context.scene.frame_current + value
    @map_message(MidiMessageType(status=144, control=73)) # loop in left
    def seek_prev(self, msg):
        ''' move to prev frame ''', -1)
    @map_message(MidiMessageType(status=144, control=74)) # loop out left
    def seek_next(self, msg):
        ''' move to next frame ''', 1)
    @map_message(MidiMessageType(status=176, control=25)) # jog left
    def seek_jog(self, msg):
        ''' move current frame ''', msg.get_value())
    @map_message(MidiMessageType(status=144, control=77)) # loop in right
    def jump_keyframe_prev(self, msg):
        ''' jump to prev keyframe '''
        # requires Jump to Cut Addon
    @map_message(MidiMessageType(status=144, control=78)) # loop out right
    def jump_keyframe_next(self, msg):
        ''' jump to next keyframe '''
        # requires Jump to Cut Addon
    @map_message(MidiMessageType(status=144, control=75)) # load track left
    def strip_toggle_mute(self, msg):
        ''' toggle mute of selected clip '''
        sqe = bpy.context.scene.sequence_editor
        if sqe is not None and sqe.active_strip is not None:
            sqe.active_strip.mute = not sqe.active_strip.mute
    @map_message(MidiMessageType(status=176, control=8)) # volume left
    def strip_volume_keyframe_insert(self, msg):
        ''' set key-framed volume of selected sound clip '''
        sqe = bpy.context.scene.sequence_editor
        if (sqe is not None and sqe.active_strip is not None and
            sqe.active_strip.type == 'SOUND'):
            sqe.active_strip.volume = msg.get_value() / 127.0