Skip to main content
Glama

FL Studio MCP

by veenastudio
trigger.py7.33 kB
from typing import Any import httpx from mcp.server.fastmcp import FastMCP import mido from mido import Message import time # Initialize FastMCP server mcp = FastMCP("flstudio") output_port = mido.open_output('loopMIDI Port 2') # MIDI Note mappings for FL Studio commands NOTE_PLAY = 60 # C3 NOTE_STOP = 61 # C#3 NOTE_RECORD = 62 # D3 NOTE_NEW_PROJECT = 63 # D#3 NOTE_SET_BPM = 64 # E3 NOTE_NEW_PATTERN = 65 # F3 NOTE_SELECT_PATTERN = 66 # F#3 NOTE_ADD_CHANNEL = 67 # G3 NOTE_NAME_CHANNEL = 68 # G#3 NOTE_ADD_NOTE = 69 # A3 NOTE_ADD_TO_PLAYLIST = 70 # A#3 NOTE_SET_PATTERN_LEN = 71 # B3 NOTE_CHANGE_TEMPO = 72 # Define custom MIDI CC messages for direct step sequencer grid control CC_SELECT_CHANNEL = 100 # Select which channel to edit CC_SELECT_STEP = 110 # Select which step to edit CC_TOGGLE_STEP = 111 # Toggle the selected step on/off CC_STEP_VELOCITY = 112 # Set velocity for the selected step # Drum sound MIDI notes KICK = 36 # C1 SNARE = 38 # D1 CLAP = 39 # D#1 CLOSED_HAT = 42 # F#1 OPEN_HAT = 46 # A#1 @mcp.tool() def list_midi_ports(): """List all available MIDI input ports""" print("\nAvailable MIDI Input Ports:") input_ports = mido.get_output_names() if not input_ports: print(" No MIDI input ports found") else: for i, port in enumerate(input_ports): print(f" {i}: {port}") return input_ports @mcp.tool() def play(): """Send MIDI message to start playback in FL Studio""" # Send Note On for C3 (note 60) output_port.send(mido.Message('note_on', note=60, velocity=100)) time.sleep(0.1) # Small delay output_port.send(mido.Message('note_off', note=60, velocity=0)) print("Sent Play command") @mcp.tool() def stop(): """Send MIDI message to stop playback in FL Studio""" # Send Note On for C#3 (note 61) output_port.send(mido.Message('note_on', note=61, velocity=100)) time.sleep(0.1) # Small delay output_port.send(mido.Message('note_off', note=61, velocity=0)) print("Sent Stop command") def int_to_midi_bytes(value): """ Convert an integer value into an array of MIDI-compatible bytes (7-bit values) Args: value (int): The integer value to convert Returns: list: Array of MIDI bytes (each 0-127) """ if value < 0: print("Warning: Negative values not supported, converting to positive") value = abs(value) # Special case for zero if value == 0: return [0] # Convert to MIDI bytes (7-bit values, MSB first) midi_bytes = [] while value > 0: # Extract the lowest 7 bits and prepend to array midi_bytes.insert(0, value & 0x7F) # 0x7F = 127 (binary: 01111111) # Shift right by 7 bits value >>= 7 return midi_bytes def change_tempo(bpm): """ Change the tempo in FL Studio using a sequence of MIDI notes This function converts a BPM value to an array of MIDI notes, sends a start marker, the notes, and an end marker to trigger a tempo change in FL Studio. Args: bpm (float): The desired tempo in beats per minute """ # Ensure BPM is within a reasonable range if bpm < 20 or bpm > 999: print(f"Warning: BPM value {bpm} is outside normal range (20-999)") bpm = max(20, min(bpm, 999)) # Convert BPM to integer bpm_int = int(bpm) # Convert to MIDI bytes midi_notes = int_to_midi_bytes(bpm_int) print(f"Setting tempo to {bpm_int} BPM using note array: {midi_notes}") # Send start marker (note 72) send_midi_note(72) time.sleep(0.2) # Send each note in the array for note in midi_notes: send_midi_note(note) time.sleep(0.1) # Send end marker (note 73) send_midi_note(73) time.sleep(0.2) print(f"Tempo change to {bpm_int} BPM sent successfully using {len(midi_notes)} notes") @mcp.tool() def send_melody(notes_data): """ Send a sequence of MIDI notes with timing information to FL Studio for recording Args: notes_data (str): String containing note data in format "note,velocity,length,position" with each note on a new line """ # Parse the notes_data string into a list of note tuples notes = [] for line in notes_data.strip().split('\n'): if not line.strip(): continue parts = line.strip().split(',') if len(parts) != 4: print(f"Warning: Skipping invalid line: {line}") continue try: note = min(127, max(0, int(parts[0]))) velocity = min(127, max(0, int(parts[1]))) length = max(0, float(parts[2])) position = max(0, float(parts[3])) notes.append((note, velocity, length, position)) except ValueError: print(f"Warning: Skipping line with invalid values: {line}") continue if not notes: return "No valid notes found in input data" # Create the MIDI data array (5 values per note) midi_data = [] for note, velocity, length, position in notes: # 1. Note value (0-127) midi_data.append(note) # 2. Velocity value (0-127) midi_data.append(velocity) # 3. Length whole part (0-127) length_whole = min(127, int(length)) midi_data.append(length_whole) # 4. Length decimal part (0-9) length_decimal = int(round((length - length_whole) * 10)) % 10 midi_data.append(length_decimal) # 5. Position whole part (0-127) position_whole = min(127, int(position)) midi_data.append(position_whole) # 6. Position decimal part (0-9) position_decimal = int(round((position - position_whole) * 10)) % 10 midi_data.append(position_decimal) # Start MIDI transfer print(f"Transferring {len(notes)} notes ({len(midi_data)} MIDI values)...") # Initial toggle signal (note 0) send_midi_note(0) time.sleep(0.01) # Send total count of notes send_midi_note(min(127, len(notes))) time.sleep(0.01) # Send all MIDI data values for i, value in enumerate(midi_data): send_midi_note(value) #time.sleep(0.1) #print(f"Sent MIDI value {i+1}/{len(midi_data)}: {value}") send_midi_note(127) #print(f"Melody transfer complete: {len(notes)} notes sent") return f"Melody successfully transferred: {len(notes)} notes ({len(midi_data)} MIDI values) sent to FL Studio" # Send a MIDI note message @mcp.tool() def send_midi_note(note, velocity=1, duration=0.01): """Send a MIDI note on/off message with specified duration""" note_on = Message('note_on', note=note, velocity=velocity) output_port.send(note_on) #print(f"Sent MIDI note {note} (on), velocity {velocity}") time.sleep(duration) note_off = Message('note_off', note=note, velocity=0) output_port.send(note_off) print(f"Sent MIDI note {note} (off)") #time.sleep(0.1) # Small pause between messages if __name__ == "__main__": # Initialize and run the server mcp.run(transport='stdio')

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/veenastudio/flstudio-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server