Can BTT send MIDI Output?

You can right-click the action and choose "copy apple script". However the escaping might make it look complicated. It will also work with simpler escaping:



tell application "BetterTouchTool"
	trigger_action "{
  BTTPredefinedActionType: 462,
  BTTPredefinedActionName: 'Send MIDI Command',
  BTTAdditionalActionData: {
      BTTMidiCommandType:159, 
     BTTMidiCommandEndpoint: \";;;;Bome MIDI Translator 1\",
     BTTMidiCommandChannel:2,
     BTTMidiCommandNote:60,
     BTTMidiCommandVelocity:2}

}"
	
	
end tell
1 Like

Thank you! That's exactly what I was trying to do for a while now. Glad to get help from you!

Little addition - in MIDI triggers it should be possible to have a note number as a variable input for scripting and triggering. Now it is only possible to use velocity as an input value for scripting. And maybe there should be an option to have "Any note" as a trigger. By the way - let users make it all themselves by adding an input analyzer with custom script - you already have almost everything needed in the MIDI event viewer.

Latest BTT alpha crashed a lot of time when triggering any configured MIDI trigger with async AppleScript as configured action. But I deleted this trigger and somehow it does not crash now.

I spent whole day trying to figure out how to use variables with this scripts. Figured it out:

on bttWidgetSliderMoved(sliderValue)
    tell application "BetterTouchTool"
        set_string_variable "sliderCC" to ((round (sliderValue * 127)) as string)
        set ccValueString to get_string_variable("sliderCC")
        
        trigger_action "{    
    BTTPredefinedActionType : 462,
    BTTPredefinedActionName : 'Send MIDI Command',
    BTTAdditionalActionData : '{\\\"BTTMidiCommandType\\\":191,\\\"BTTMidiCommandEndpoint\\\":\\\";;;;Bome MIDI Translator 1\\\",\\\"BTTMidiCommandChannel\\\":1,\\\"BTTMidiCommandValue\\\":" & ccValueString & ",\\\"BTTMidiCommandControllerNumber\\\":1}'
    }"
    end tell
end bttWidgetSliderMoved

Tell me if it could be optimised more.

upd:
Another addition is that would be good if MIDI input could specify MIDI channel. I remember that you told it is hard but now you implemented channels for MIDI output, so maybe something have changed.

And very rare case but should be fixed I guess - I have two identical MIDI controllers and BTT doesn't differentiate them. You can see my screenshot above - FL studio identify first K-Board as it is and second as K-Board #2

upd:
One more interesting trigger that outputs MIDI CC1 based on trackpad position after double clicking fn key (now it emulates pointer position lock and sends MIDI CC to Bome MIDI Translator port, because BTT doesn't have one yet):

[
  {
    "BTTActionCategory" : 0,
    "BTTLastUpdatedAt" : 1719013798.0404119,
    "BTTTriggerType" : 624,
    "BTTTriggerTypeDescriptionReadOnly" : "Please Select a Trigger ",
    "BTTTriggerClass" : "BTTTriggerTypeKeySequence",
    "BTTUUID" : "2251D720-8DA1-4735-819E-5BDD891F0A28",
    "BTTPredefinedActionType" : 366,
    "BTTPredefinedActionName" : "Empty Placeholder",
    "BTTEnabled" : 1,
    "BTTEnabled2" : 1,
    "BTTOrder" : 2,
    "BTTAdditionalActions" : [
      {
        "BTTActionCategory" : 0,
        "BTTLastUpdatedAt" : 1719010986.7312651,
        "BTTTriggerParentUUID" : "2251D720-8DA1-4735-819E-5BDD891F0A28",
        "BTTIsPureAction" : true,
        "BTTTriggerClass" : "BTTTriggerTypeKeySequence",
        "BTTUUID" : "8EA8723D-5070-42D3-A537-ABEDEADB96A7",
        "BTTPredefinedActionType" : 154,
        "BTTPredefinedActionName" : "Save Current Mouse Position",
        "BTTEnabled" : 1,
        "BTTEnabled2" : 1,
        "BTTOrder" : 1
      },
      {
        "BTTActionCategory" : 0,
        "BTTLastUpdatedAt" : 1719011851.856514,
        "BTTTriggerParentUUID" : "2251D720-8DA1-4735-819E-5BDD891F0A28",
        "BTTIsPureAction" : true,
        "BTTTriggerClass" : "BTTTriggerTypeKeySequence",
        "BTTUUID" : "562946A4-7A15-4A54-A836-7F30ADFFED3A",
        "BTTPredefinedActionType" : 195,
        "BTTPredefinedActionName" : "Run Apple Script (async in background)",
        "BTTAdditionalActionData" : {
          "BTTScriptType" : 0,
          "BTTAppleScriptRunInBackground" : true,
          "BTTTouchBarAppleScriptString" : "on run\n    tell application \"BetterTouchTool\"\n        set isTracking to get_string_variable(\"isTrackingTouchpad\")\n        if isTracking is \"true\" then\n            set_string_variable \"isTrackingTouchpad\" to \"false\"\n            return \"Stopped tracking touchpad\"\n        else\n            set_string_variable \"isTrackingTouchpad\" to \"true\"\n            set lastValue to -1 -- Initialize with an impossible value\n            repeat\n                set isStillTracking to get_string_variable(\"isTrackingTouchpad\")\n                if isStillTracking is not \"true\" then exit repeat\n                \n                -- Изменяем диапазон с 10% до 90% вместо 0% до 100%\n                set rawValue to get_number_variable(\"rightmost_touch_y_percent\")\n                set adjustedValue to (rawValue - 30) * (100 \/ 40)\n                \n                -- Ограничиваем значение между 0 и 100\n                if adjustedValue < 0 then\n                    set adjustedValue to 0\n                else if adjustedValue > 100 then\n                    set adjustedValue to 100\n                end if\n                \n                set currentValue to round (adjustedValue \/ 100 * 127)\n                \n                trigger_action \"{\n  BTTActionCategory: 0,\n  BTTPredefinedActionType: 155,\n  BTTPredefinedActionName: 'Restore Saved Mouse Position',\n  BTTEnabled2: 1,\n}\"\n                \n                if currentValue ≠ lastValue then\n                    set ccValueString to currentValue as string\n                    \n                    trigger_action \"{    \n                    BTTPredefinedActionType : 462,\n                    BTTPredefinedActionName : 'Send MIDI Command',\n                    BTTAdditionalActionData : '{\\\\\\\"BTTMidiCommandType\\\\\\\":191,\\\\\\\"BTTMidiCommandEndpoint\\\\\\\":\\\\\\\";;;;Bome MIDI Translator 1\\\\\\\",\\\\\\\"BTTMidiCommandChannel\\\\\\\":1,\\\\\\\"BTTMidiCommandValue\\\\\\\":\" & ccValueString & \",\\\\\\\"BTTMidiCommandControllerNumber\\\\\\\":1}'\n                    }\"\n\n                    set lastValue to currentValue\n                end if\n                \n                delay 0.01 -- Small delay to prevent excessive CPU usage\n            end repeat\n            return \"Started tracking touchpad\"\n        end if\n    end tell\nend run\n",
          "BTTTouchBarAppleScriptUsePath" : false
        },
        "BTTInlineAppleScript" : "on run\n    tell application \"BetterTouchTool\"\n        set isTracking to get_string_variable(\"isTrackingTouchpad\")\n        if isTracking is \"true\" then\n            set_string_variable \"isTrackingTouchpad\" to \"false\"\n            return \"Stopped tracking touchpad\"\n        else\n            set_string_variable \"isTrackingTouchpad\" to \"true\"\n            set lastValue to -1 -- Initialize with an impossible value\n            repeat\n                set isStillTracking to get_string_variable(\"isTrackingTouchpad\")\n                if isStillTracking is not \"true\" then exit repeat\n                \n                -- Изменяем диапазон с 10% до 90% вместо 0% до 100%\n                set rawValue to get_number_variable(\"rightmost_touch_y_percent\")\n                set adjustedValue to (rawValue - 30) * (100 \/ 40)\n                \n                -- Ограничиваем значение между 0 и 100\n                if adjustedValue < 0 then\n                    set adjustedValue to 0\n                else if adjustedValue > 100 then\n                    set adjustedValue to 100\n                end if\n                \n                set currentValue to round (adjustedValue \/ 100 * 127)\n                \n                trigger_action \"{\n  BTTActionCategory: 0,\n  BTTPredefinedActionType: 155,\n  BTTPredefinedActionName: 'Restore Saved Mouse Position',\n  BTTEnabled2: 1,\n}\"\n                \n                if currentValue ≠ lastValue then\n                    set ccValueString to currentValue as string\n                    \n                    trigger_action \"{    \n                    BTTPredefinedActionType : 462,\n                    BTTPredefinedActionName : 'Send MIDI Command',\n                    BTTAdditionalActionData : '{\\\\\\\"BTTMidiCommandType\\\\\\\":191,\\\\\\\"BTTMidiCommandEndpoint\\\\\\\":\\\\\\\";;;;Bome MIDI Translator 1\\\\\\\",\\\\\\\"BTTMidiCommandChannel\\\\\\\":1,\\\\\\\"BTTMidiCommandValue\\\\\\\":\" & ccValueString & \",\\\\\\\"BTTMidiCommandControllerNumber\\\\\\\":1}'\n                    }\"\n\n                    set lastValue to currentValue\n                end if\n                \n                delay 0.01 -- Small delay to prevent excessive CPU usage\n            end repeat\n            return \"Started tracking touchpad\"\n        end if\n    end tell\nend run\n",
        "BTTEnabled" : 1,
        "BTTEnabled2" : 1,
        "BTTOrder" : 2
      }
    ],
    "BTTKeySequence" : {
      "BTTPauseBetween" : 0.29999999999999999,
      "BTTKeyCount" : 8,
      "BTTKeySequenceDownKeys" : [
        {
          "BTTKEYCode" : 63,
          "BTTKEYDown" : 1,
          "BTTKEYOrderRelevant" : 1,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCharacter" : " 􀆪 Globe Key",
          "BTTKEYCode" : 179,
          "BTTKEYDown" : 1,
          "BTTKEYOrderRelevant" : 1,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCode" : 63,
          "BTTKEYDown" : 1,
          "BTTKEYOrderRelevant" : 1,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCharacter" : " 􀆪 Globe Key",
          "BTTKEYCode" : 179,
          "BTTKEYDown" : 1,
          "BTTKEYOrderRelevant" : 1,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        }
      ],
      "BTTKeySequenceMixedKeys" : [
        {
          "BTTKEYCode" : 63,
          "BTTKEYDown" : 1,
          "BTTKEYOrderRelevant" : 1,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCode" : 63,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCharacter" : " 􀆪 Globe Key",
          "BTTKEYCode" : 179,
          "BTTKEYDown" : 1,
          "BTTKEYOrderRelevant" : 1,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCharacter" : " 􀆪 Globe Key",
          "BTTKEYCode" : 179,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCode" : 63,
          "BTTKEYDown" : 1,
          "BTTKEYOrderRelevant" : 1,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCode" : 63,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCharacter" : " 􀆪 Globe Key",
          "BTTKEYCode" : 179,
          "BTTKEYDown" : 1,
          "BTTKEYOrderRelevant" : 1,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCharacter" : " 􀆪 Globe Key",
          "BTTKEYCode" : 179,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        }
      ],
      "BTTKeySequenceUpKeys" : [
        {
          "BTTKEYCode" : 63,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCharacter" : " 􀆪 Globe Key",
          "BTTKEYCode" : 179,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCode" : 63,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        },
        {
          "BTTKEYCharacter" : " 􀆪 Globe Key",
          "BTTKEYCode" : 179,
          "BTTKEYRequired" : 1,
          "BTTKEYTime" : 740699456
        }
      ]
    }
  }
]

Virtual ports would be a nice addition, but I think the virtual ports that Apple offers via IAC in Audio Midi Settings is enough for transmitting midi between apps and daws.

IMHO, it would be better to start improving the "Midi triggers" section and the "Send Midi" action.

1 Like

Can you please provide some info on how to set up IAC to send MIDI from BTT to a DAW?

Oh, found it. IAC just need to be turned on.

Perfect you find it, Andrei :+1:

I use IAC for a long time ago, and IMHO it is the best option to use virtual midi ports in macos, as you can change of apps and always use the same virtual ports.

In the other hand, if you use the virtual ports of an specific midi app and you change of midi app, you will need to change the ports in all midi devices and in all the DAWs.

There are some important things in the Midi Configuration of Audio Midi Setup:

  • There is a drop-down menu for saving configurations. It is recommended to save your midi configuration with your custom name. This configuration is saved in the users folder and it is useful to recover it in the case of changing or formatting a computer. Everytime you modify the midi setup, the modification is saved automatically.

  • The icons in the bar are useful, mainly the keyboard icon to test the midi configuration.

1 Like