Skip to content

Fl classes

fl_classes

This module contains definitions for FL Studio's built-in types, which can be used to assist with type hinting in your project.

NOTE: This module is not included in FL Studio's runtime, and should be included by initializing fl_typing as a submodule for your project. https://github.com/MiguelGuthridge/fl_typing

# With fl_typing enabled so that the typing module works correctly
from fl_classes import FlMidiMsg

def OnMidiIn(event: FlMidiMsg) -> None:
    ...

FlMidiMsg

A shadow of FL Studio's FlMidiMsg object. Note that although creating these is possible, it should be avoided during runtime as FL Studio's API won't accept it as an argument for any of its functions. It can be used within a testing environment, however.

Note that two sub-types are also included, which allow for type narrowing by separating standard MIDI events and Sysex MIDI events. These will work for FL Studio's types as well.

  • isMidiMsgStandard()

  • isMidiMsgSysex()

Basic type checking is performed when accessing properties of FlMidiMsg objects, to ensure that incorrect properties aren't accessed (for example accessing data1 for a sysex event). These checks won't be performed during runtime for your script, but can help to add more certainty to your tests.

controlNum: int property writable

The control number for a control change event.

This is a shadow of the data1 property. Modifications to this will affect all data1 derived properties.

Note that this property is inaccessible for sysex events.

controlVal: int property writable

The value of a control change event.

This is a shadow of the data2 property. Modifications to this will affect all data2 derived properties

Note that this property is inaccessible for sysex events.

data1: int property writable

The first data byte of a MIDI message.

This is used to determine the control number for CC events, the note number for note events, and various other values.

Note that this property is inaccessible for sysex events.

data2: int property writable

The second data byte of a MIDI message.

This is used to determine the value for CC events, the velocity for note events, and various other values.

Note that this property is inaccessible for sysex events.

handled: bool property writable

Whether the event is considered to be handled by FL Studio.

If this is set to True, the event will stop propagating after this particular callback returns.

You script should set it when an event is processed successfully.

inEv: int property writable

MIDI inEv

HELP WANTED:
  • What is this?

isIncrement: bool property writable

Whether the event should be an increment event

If the script sets this to True, FL Studio will consider it to be a relative event, meaning that it will change values relative to that value, rather than setting them absolutely.

HELP WANTED:
  • Notes on the particular cases where this happens.

midiChan: int property writable

MIDI chan

HELP WANTED:
  • What is this?

  • No, it's not a channel. It always seems to be zero, regardless of the channel of the event.

midiChanEx: int property writable

MIDI chanEx

HELP WANTED:
  • What is this?

midiId: int property writable

MIDI ID

HELP WANTED:
  • What is this?

note: int property writable

The note number of a MIDI note on/off message.

This is a shadow of the data1 property. Modifications to this will affect all data1 derived properties.

Note that this property is inaccessible for sysex events.

outEv: int property writable

MIDI outEv

HELP WANTED:
  • What is this?

pitchBend: int property

MIDI pitch bend value

HELP WANTED:
  • This only ever seems to equal 1. How should it be used?

Note that this property is read-only.

pmeFlags: int property

Flags used by FL Studio to indicate the permissions of the script in the current environment.

These can be used to ensure safety while running the script. If a script ever attempts to execute unsafe behavior, a TypeError will be raised.

TypeError("Operation unsafe at current time")
Flag analysis

The flags can be analyzed by performing bitwise operations to determine the current permissions of the script.

  • 0b000010 (PME_System) System operations allowed (play/pause, etc).

  • 0b000100 (PME_System_Safe) Critical operations allowed (add markers, etc). Things that can't be done when a modal dialog is showing.

  • 0b001000 (PME_PreviewNote) Note events will trigger a preview.

  • 0x010000 (PME_FromHost) FL Studio is being hosted as a VSTi (meaning it's probably a bad idea to do anything meaningful as it could interfere with the behavior of other DAWs). In my testing, using MIDI scripts in the FL Studio VST causes a crash anyway, so I suppose it isn't that important either way.

  • 0x100000 This event was triggered by a MIDI event.

Alternate to flag analysis

It could be considered to be more Pythonic, as well as much simpler to catch this exception rather than checking the flags. The following is a simple decorator that will catch the exception. This does come with the risk that any unsafe behavior that FL Studio misses will cause a system lock-up in FL Studio.

def catchUnsafeOperation(func):
    '''
    Decorator to prevent exceptions due to unsafe operations

    ### Args:
    * `func` (`Callable`): function to decorate
    '''
    def wrapper(*args, **kwargs):
        try:
            func(*args, **kwargs)
        except TypeError as e:
            if e.args != ("Operation unsafe at current time",):
                raise e
    return wrapper

port: int property

The port of the message

HELP WANTED:
  • This value always appears to be zero. How should it be used?

Note that this property is read-only.

pressure: int property writable

The pressure value for a channel after-touch event.

This is a shadow of the data1 property. Modifications to this will affect all data1 derived properties.

Note that this property is inaccessible for sysex events.

progNum: int property writable

The instrument number for a program change event.

This is a shadow of the data1 property. Modifications to this will affect all data1 derived properties.

Note that this property is inaccessible for sysex events.

res: float property writable

MIDI res

HELP WANTED:
  • How is this used?

status: int property writable

The status byte of the event

This can be used to determine the type of MIDI event using the upper nibble, and the channel of the event using the lower nibble.

e_type = event.status & 0xF0
channel = event.status & 0xF

Note that for sysex messages, this property is 0xF0. Other standard event properties are inaccessible.

Event types
  • 0x8 Note off (data1 is note number, data2 is release value)

  • 0x9 Note on (data1 is note number, data2 is velocity)

  • 0xA Note after-touch (data1 is note number, data2 is pressure value)

  • 0xB Control change (CC, data1 is control number as per your controller's documentation, data2 is value)

  • 0xC Program change (used to assign instrument selection, data1 is instrument number)

  • 0xD Channel after-touch (data1 is value, data2 is unused)

  • 0xE Pitch bend (data1 and data2 are value, as per the formula data1 + (data2 << 7), yielding a range of 0 - 16384)

sysex: bytes property writable

Data for a sysex event

Contains the full event data from sysex events.

This property is inaccessible for standard events.

timestamp: int property

The timestamp of the event

HELP WANTED:
  • This seems to only ever be zero. I can't determine what it is for. If you know how it is used, create a pull request with details.

This value is read-only.

velocity: int property writable

The velocity of a MIDI note on/off message.

This is a shadow of the data2 property. Modifications to this will affect all data2 derived properties

Note that this property is inaccessible for sysex events.

__init__(status_sysex, data1=None, data2=None, pmeFlags=46)

Create an FlMidiMsg object.

Note that this object will be incompatible with FL Studio's API, and so cannot be used as a parameter for any API functions during runtime.

Args:
  • status_sysex (int | list[int] | bytes): status byte or sysex data

  • data1 (Optional[int], optional): data1 byte if applicable. Defaults to None.

  • data2 (Optional[int], optional): data2 byte if applicable. Defaults to None.

  • pmeFlags (int, optional): PME flags of event. Defaults to PME_System | PME_System_Safe | PME_PreviewNote | PME_FromMIDI.

Example Usage
# Create a note on event on middle C
msg = FlMidiMsg(0x90, 0x3C, 0x7F)

# Create a CC#10 event
msg = FlMidiMsg(0xB0, 0x0A, 0x00)

# Create a sysex event for a universal device enquiry
msg = FlMidiMsg([0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7])

__range_check(value, prop) staticmethod

Check that the value is within the allowed range, then return it

__standard_check(value, prop) staticmethod

Check that it's a standard event, then return the value

StandardMidiMsg

Bases: FlMidiMsg

An FlMidiMsg object which has been type narrowed to a StandardFlMidiMsg.

Note that as FL Studio events are actually of a different type to these shadow types, you should never use the isinstance function in order to perform type-narrowing operations, as it will lead to very obscure bugs when your type checks never work inside FL Studio, even if they work in your tests.

Instead, you can type narrow to a StandardFlMidiMsg object using the isMidiMsgStandard() function.

SysexMidiMsg

Bases: FlMidiMsg

An FlMidiMsg object which has been type narrowed to a SysexFlMidiMsg.

Note that as FL Studio events are actually of a different type to these shadow types, you should never use the isinstance function in order to perform type-narrowing operations, as it will lead to very obscure bugs when your type checks never work inside FL Studio, even if they work in your tests.

Instead, you can type narrow to a SysexFlMidiMsg object using the isMidiMsgSysex() function.

eventToRawData(event)

Convert event to raw data.

For standard events data is presented as little-endian, meaning that the status byte has the lowest component value in the integer.

Returns:
  • int | bytes: data

isMidiMsgStandard(event)

Returns whether an event is a standard event

Args:
  • event (FlMidiMsg): event to check
Returns:
  • TypeGuard[SysexFlMidiMsg]: type guarded event

isMidiMsgSysex(event)

Returns whether an event is a sysex event

Args:
  • event (FlMidiMsg): event to check
Returns:
  • TypeGuard[SysexFlMidiMsg]: type guarded event