PySwitch Firmware for PaintAudio MIDI Captain

  • PySwitch is an alternative open source firmware for the PaintAudio MIDI Captain series of foot controllers, to control the Kemper Profiler devices. Currently the Nano 4, Mini 6 and 10-switch versions are supported out of the box, if you need it to be adapted for others, just ask and help developing the project.

    The project has evolved a lot in the last months and is used by lots of forum members already, now it is time to create an own thread for it ;) See the old thread if you like more info.

    Download it from here (click on th green "Code" button at the right and choose an option, for example "Download ZIP"):

    GitHub - Tunetown/PySwitch: Alternative Firmware for MidiCaptain Footswitches to interact with Kemper Profiler
    Alternative Firmware for MidiCaptain Footswitches to interact with Kemper Profiler - Tunetown/PySwitch
    github.com

    Features:

    • Assign every switch, expression pedal or rotary wheel (experimental!) of your MIDI Captain to one or more actions to be performed/monitored on the Kemper. These can be switching effect states, changing rigs/banks, tuner mode and lots more. Missing action definitions can be added easily with some basic python coding skills, such as effect slot states or selecting rigs.
    • Visual feedback about current state of the actions via LEDs and/or the TFT display.
    • Bidirectional communication with the Kemper Player to always show the true states, even if changed from somewhere else
    • Flexible configuration of the TFT display (you can layout it however you want, have additional labels etc.)
    • Routing of MIDI messages from and to the USB and DIN MIDI ports
    • Browser-based Configuration / Emulation tool which can configure the controller via MIDI from the browser

    This is a list of actions which are implemented out of the box and very easy to use:

    • Bank select/Toggle between banks
    • Bank Up/Down
    • Effect Type and On/Off State (colors match the Kemper effect type colors)
    • Effect Buttons I-IIII (no feedback from the Kemper but toggling works)
    • All Looper buttons
    • Morph (Button, Expression Pedals and display of morph state with correct colors) NOTE: This is a bit limited due to a Kemper bug, but it works. See the old thread for details.
    • Rig select/Toggle between rigs (there are many options here)
    • Rig Up/Down
    • Tap Tempo / Display tempo as blinking LEDs
    • Map expression pedals or switch fix values for rig volume, amp gain, ... (a lot is possible, limited just by the Kemper MIDI specification)
    • All pedal types (Volume, Wah, Pitch ...) and parameters can be assigned to expression pedals or the wheel.
    • Show the current rig name.
    • Tuner Mode with a big Note display and a strobe display using all switch LEDs of the controller (optional)

    The support for Expression Pedals and the Wheel Rotary Encoder is still experimental and not tested well, i have never tried this myself as i do not have a MC 10 controller. However some first tests by NickMrChaos have been promising so far, so it basically works. Please report if you have problems.

    There are further mappings you can use, see the README file and the content/ib/pyswitch/clients folder. Any further functionality can be added, either by yourself inside the configuration scripts, or you ask in the forum, and i will include that in a next version.

    Installation goes the same way as the original PaintAudio firmware:

    1. Mount the MIDICAPTAIN drive (see PaintAudio instructions for updating, i think you have to hold Switch 1 during boot)
    2. Delete all files from the MIDICAPTAIN USB drive
    3. Copy all files and folders in the "content" folder of the PySwitch project to the MIDICAPTAIN drive.
    4. Unmount MIDICAPTAIN drive again and reboot the device.

    Configuration is done via python scripts which give you all freedom available (see README for documentation), but normally this is done using the PySwitch Emulator tool, which allows you to create/edit your configurations graphically (and code if you wish) and directly flash it to your device (see here for details on usage):

    Have fun with it :) and if you like, donate (see README) :love:

    Edited 3 times, last by tunetown (June 15, 2025 at 1:52 PM).

  • For the users who already use the previous version of PySwitch (2.2.2), here the new features of version 2.3.0:

    • Added Expression Pedal support, see examples
    • Added mappings for all pedals (Volume, Wah, Delay Mix, Delay Feedback, Reverb Mix, Reverb Time, Output (Monitor) Volume)
    • Added support for the wheel (rotary encoder and push button), all parameters or pedals can be assigned to this. See examples.
    • Added new action definitions:
      • BANK_SELECT: Change/toggle bank while staying at the same rig. Also supports only sending a pre-select command ( patvalley) optionally, see the example for the Nano 4.
      • RIG_UP and RIG_DOWN
      • Looper actions (see example Nano 4 -> tunetown Session with Looper and Pages)
      • Added option to RIG_SELECT and RIG_AND_BANK_SELECT which remembers the current rig in "off" state and switches back to it when disabling again. See example Nano 4 -> tunetown Session.
    • Tuner mode:
      • Disable tuner mode with any switch ( Erikcb)
      • RIG_SELECT: Added support for simulating the morph changes when "Rig Btn Morph" is activated on the Kemper. ( Curryflurry )
      • Added strobe tuner using all available LEDs when in tuner mode (active by default, can be disabled with parameter "strobe" in TunerDisplayCallback / display.py if you do not like to use it)
    • Morph Button: When pushing this, the displayed state will be toggled whatever the Kemper says. Only if the Kemper sends an updated value, it will be updated on the controller, too. ( Arek77) Note: This does only work when morph is triggered from the Controller! When using the Kemper "Rig Btn Morph" option, this will not be reflected.
    • Added Paging: Use class PagerAction to step through multiple pages with individual actions. Also partial pages are possible. The actions are switched via callback, see example Nano 4 -> tunetown Session.with Looper and Pages. Currently, this is pretty cumbersome to include, but in the future the graphical configuration tool can take over the job ;) see below.
    • Tempo Display is now darker by default, and brightness for on and off states can be adjusted by using the "led_brightness_\*" parameters of the SHOW_TEMPO action
    • Default global brightness factors for LEDs and DisplayLabels can now be set optionally in config.py, see comments there.
    • Now supporting file editing from the browser via MIDI using the MidiBridge library. Click here with your device connected to the computer via USB, and it will automatically connect. This needs no USB mounting/unmounting and is useful for quick experimenting and changing settings. Should also serve as proof-of-concept for building a visual editor in the future (!).

    The last point may be the most important one for the future: It enables generating the configuration files completely via a browser based editor. This is already cool, but be prepared for a feature that NO OTHER MANUFACTURER has! I have to experiment more to be more explicit, but the web based editor may even be able to actually run PySwitch itself via a JS emulator, even without any MIDI Captain connected, and actually control the Kemper from the browser (!) before the configuration is "flashed" to the MIDI Captain. Wouldn't that be killer? I really see good chances for this to work, so stay tuned in this thread!

    Now to the bad news: To make space for the new features i had to further optimize RAM usage like hell and squeeze every byte out of it ;) this comes at the price of changes to the configuration files, too. Most of that is under the hood, but the following things have changed for the configuration files:

    • Merged HoldAction into Footswitch controller (put "actionsHold" into the switch definition directly instead, see examples)
    • switches.py is now renamed to inputs.py, and has to contain an "Inputs" instead of a "Switches" list. See examples, as always.
    • All Kemper action pre-definitions are now separated in files. In inputs.py (formerly switches.py, you now have to omit the KemperActionDefinitions. prefixes, and import the action definitions you need separately (see examples) which is a huge memory benefit.
      Implementation Notes: kemper.py code is now way smaller and moved to pyswitch/clients/kemper/__init__.py
    • Hardware implementations are now separated into files for the different MIDI Captains. At the top of inputs.py (formerly switches.py), adjust the import statement to the device you use, see examples.
    • Removed performance dot (remove this from display.py if exists), nobody needs that
    • Merged HierarchicalDisplayElement into DisplayElement (replace HierarchicalDisplayElement with DisplayElement in display.py)
    • Removed DisplaySplitContainer and subtractive layouting (manually set display areas instead in display.py, see examples). This was a nice thing to have, however it took RAM and the layouts are so simple that it is totally OK to just use fix values.
    • Removed some redundant actions for the sake of memory savings:
      • RIG_AND_BANK_SELECT: Use RIG_SELECT instead (which now supports bank and bank_off parameters)
      • RIG_AND_BANK_SELECT_AND_MORPH_STATE: Use RIG_SELECT_AND_MORPH_STATE instead (which now supports bank and bank_off parameters)
      • MORPH_BUTTON_WITH_DISPLAY: Use MORPH_BUTTON instead, setting the color parameter to "kemper".
    • Removed the (always identical) communication.py files from all examples. You can combine any of the routing example communication.py files with any of the examples. The most genuine one is "Control client via USB MIDI".

    There are new examples, here the most important ones:

    • MC10 / Arek77: This replaces the davjunk example as it does the same but better
    • MC10 / Experssion Pedals and Wheel
    • Nano: There are examples for the new Bank operations (direct select, pre-select) and rig operations (up/down) and Looper / Paging (tunetown Session with Looper and Pages)

    Check it out and have a nice time :)

  • Sounds great!!

    I should have some time this week to test it with my MC 10, i don't know when tho, i'll give you some feedback whenever i can test it.

    Thanks for your work!!


    EDIT: I've been using my "example" so far without any issues, which version should i use now? Thanks

  • Sounds great!!

    I should have some time this week to test it with my MC 10, i don't know when tho, i'll give you some feedback whenever i can test it.

    Thanks for your work!!


    EDIT: I've been using my "example" so far without any issues, which version should i use now? Thanks

    Hi Erikcb all examples are updated, please use the new version of your example:)

  • Huzzah! Are config strings likely to change much from here on in?

    I am sorry for changing the format again but as i said, this much features required me to save memory which only worked this way. However i think it will stay now, as the new architecture supports loading only the code needed. The most future development will happen in the graphical web based config tool from now on. Manually tweaking the code will then only be necessary in rare cases.8o

    If you (or anyone else) needs their code adapted, post it here and i translate it for you.

    However, the tehguitarist example is updated so if you used that example you can just use the new one…

    Edited 2 times, last by tunetown (January 29, 2025 at 7:26 AM).

  • FYI: There is a known bug which will be fixed in the next update: When there is no tuner mode switch in the preset, and you enable the tuner on the Kemper, you cannot disable tuner mode with the buttons on the MIDI Captain....just to let you know.

    As a workaround, if you have no tuner mode switch assigned, just add a tuner mode action to a switch which has no other hold action, and set holdTimeMillis to a very high value:

    Code
        {
            "assignment": PA_MIDICAPTAIN_10_SWITCH_UP,
            "actions": [
                BANK_UP()  # Whatever action you want
            ],
            "actionsHold": [
                TUNER_MODE()
            ],
            "holdTimeMillis": 9999999   # Effectively disables the action
        },

    Edited once, last by tunetown (January 30, 2025 at 6:32 PM).

  • I tested it around 30 mins earlier today, it seems to be working properly!

    I had to change the slot names (C and D to DLY and REV) like I had to do with the older version, but it's working like a charm!

    The only "thing" is, now when the tuner is enabled and you press any button, the tuner goes off , but besides that, I'd like the button press to be effective.

    like, let's say I'm on rig 1 with tuner on, and I press the rig 2 button, I'd like it to turn off the tuner and change the rig, you know what I mean right?

    Not sure if it's doable (or it's too much work)...it's not a big issue, it's just what I was used to with my last controller.

    Thanks again!

  • Erikcb ah ok, i have to fix that other bug on the tuner display anyway, so i will set this on my list....next week i have some time i think :)

  • Is it possible to display the actual BPM value as number in the header or footer or in the middle when the Beat Scanner is active?

    Similar to the Tuner when active would be the optimum ;)

    You asked this once before ;) no, actually i just got the beats ticking in as MIDI messages to lighten up/darken the display, so we dont have a number. If its important, you could program your own callback which estimates the BPM from that, but because the processing jitter between update calls is so high on these devices (up to 100ms), this calculation will never be stable....another idea would be averaging then, but this would lag on tempo changes....so, no real solution to that

  • You asked this once before ;) no, actually i just got the beats ticking in as MIDI messages to lighten up/darken the display, so we dont have a number. If its important, you could program your own callback which estimates the BPM from that, but because the processing jitter between update calls is so high on these devices (up to 100ms), this calculation will never be stable....another idea would be averaging then, but this would lag on tempo changes....so, no real solution to that

    Grrrrr sorry for that ….. now I remember 😳

  • I used to use the below to change reverb to be turquoise rather than changing the lib files, is that still possible with the new firmware? I get an error on this one:

  • When I have morph activated for a slot , the morph LED for the switch is highlighted, that's perfect for me. When I change the slot via RIG_SELECT_AND_MORPH_STATE the Morph LED is "reset", that's also perfect because. as Kemper mentioned in another thread, that a slot is always loaded with the basic, non morphed setup. When I do a BANK_DOWN() or BANK_UP() with morph activated for a slot, in my case slot one is selected (as I specified in the settings), but the Morph LED keeps ON. Because a slot is always loaded with it's basic setup would it be better to always set the Morph LED deaktivaed, also when the slot is "selected" with BANK_UP() / Down ?

    Just an idea which maybe wrong ;)