Last active
November 3, 2024 05:24
-
-
Save Dinir/5c25c7d5a7ac23ec304978543de885c9 to your computer and use it in GitHub Desktop.
FL Studio can't process endless encoders. Here's a fallback making them into absolute encoders.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# name=Relative Value to Absolute Value | |
# Thanks to NFX (https://forum.image-line.com/viewtopic.php?t=329048#p1973274) | |
# and RoadCrewWorker (https://forum.image-line.com/viewtopic.php?t=328886#p1973550) | |
import device | |
import mixer | |
import midi | |
import ui | |
from fl_classes import FlMidiMsg | |
# when handling the message, `midi.EKRes` will be divided by this value | |
KnobResolution = 211/40 | |
# prepare to handle any CC on any Ch on any port number given to the device | |
PortNumber = device.getPortNumber() | |
# Channel goes from 0 to 15, is displayed on FL as 1 to 16 | |
# CC goes from 0 to 127, is displayed on FL as the same | |
ChMax, CCMax = 16, 128 | |
CCState = [0 for x in range(ChMax*CCMax)] | |
# Control ID is needed to get a corresponding Event ID when the event happens | |
ControlID = [ | |
midi.EncodeRemoteControlID(PortNumber, ch, cc) | |
for ch in range(ChMax) | |
for cc in range(CCMax) | |
] | |
def OnControlChange(msg: FlMidiMsg): | |
# calculate the value | |
index = (msg.midiChan * CCMax) + msg.data1 | |
# adjust this formula for controller protocol | |
delta = msg.data2 - 64 | |
# value being actual middle should never happen | |
if delta == 0: | |
msg.handled = True | |
return | |
eventId = device.findEventID(ControlID[index]) | |
value = CCState[index] + delta | |
value = min(max(value, 0), 127) | |
msg.data2 = CCState[index] = value | |
# execute the message | |
mixer.automateEvent( | |
eventId, | |
delta, | |
midi.REC_MIDIController, | |
0, | |
1, | |
midi.EKRes / KnobResolution | |
) | |
# build hint message | |
try: | |
paramName = device.getLinkedParamName(eventId) | |
linkedValue = device.getLinkedValue(eventId) | |
except RuntimeError: | |
paramName = None | |
linkedValue = None | |
HintMessage = '^w' if delta > 0 else '^v' if delta < 0 else '' | |
HintMessage += 'ch{:0>2} cc{:0>3}'.format(msg.midiChan+1, msg.data1) | |
HintMessage += ' → {}'.format( | |
paramName | |
) if paramName is not None else '' | |
HintMessage += ': {}'.format(value) | |
HintMessage += ' → {}'.format( | |
int(linkedValue * 127) | |
) if linkedValue is not None else '' | |
ui.setHintMsg(HintMessage) | |
msg.handled = True |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Steps for absolute newcomers to apply this script:
Making a virtual environment for Python, covered in the video
https://www.youtube.com/watch?v=6_KdXJIfeoI
This tutorial utilizes VS Code. Do the commands inside its console and it will work better.
You will install things in this folder then copy some folders and the script to FL Studio's folder later.
python -m venv .venv
.pip install mypy
,pip install typing_extensions
. Thenpip install fl-studio-api-stubs
.There are some useful stubs in
fl-studio-api-stubs
that for some reason WON'T be installed iftyping_extensions
is not installed before.Making an actual folder inside FL Studio's Setting Folder
%userprofile%\Documents\Image-Line\FL Studio\Settings\Hardware\
.device_{your device name}.py
.import
ed in the code. Especiallyfl_classes
..\.venv\Lib\site-packages
and copy these folders and a file into the folder you made at step 8. They will stay in the same folder the script file resides:Hopefully it will work.