This was a funny experiment. Sending MoGraph data from Cinema 4D to Novation Launchpad (the first version). I used Python Effector to send UDP packets to Processing and in Processing I used UDP library to read those packets and The MidiBus library to send MIDI messages to Launchpad.

Pads’ indexes starts from 0 and ends to 199. Every circle pad takes 8 indexes so in every row we add that amount to index value. Velocity value changes color and brightness of the pad but I did not have interest to find out what every single values from 0 to 127 did. In my setup I just mapped clone’s red color value (float 0.0-1.0) to MIDI velocity (integer 0-127). Mapping is done in Processing sketch.
Python Effector from this experiment can now be used as a template for different setups to send MoGraph data to other softwares. Data is transfered with UDP packets in strings. So Cinema 4D is sending constantly long strings and Processing sketch is listening those and unpacking those strings to something useful.
Python Effector code
import c4d
import socket
from c4d.modules import mograph as mo
def initSocket():
global s
global server
host = '127.0.0.1' # Host address
port = 5001 # Port
server = ('127.0.0.1', 5006) # Server address and server port
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Initialize socket
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Re-use socket
s.bind((host, port)) # Bind
return s, server
initSocket() # Create a socket
def main():
md = mo.GeGetMoData(op) # Get MoData
if md is None: return False # If no MoData return false
cnt = md.GetCount() # Get clone count
carr = md.GetArray(c4d.MODATA_COLOR) # Get color array
message = "" # Initialize message string
row = 0 # Initialize row integer
for i in xrange(0, cnt): # Loop through clones
if i != 0: # If not the first index
if i % 8 == 0:
row = row + 8 # Launchpad pad numbering
color = carr[i] # Get clone's color
index = (i+row) # Calculate pitch
message += str(index) + "-" + str(color.x) + "," # Write message
s.sendto(message, server) # Send message
return True # Everything is fine
Processing sketch
import hypermedia.net.*;
import themidibus.*;
MidiBus myBus;
UDP udp;
String HOST = "127.0.0.1"; //ip address
int PORT = 5006; //port
String receivedFromUDP = "0-0.0,1-0.0,2-0.0,3-0.0,4-0.0,5-0.0,6-0.0,7-0.0,16-0.0,17-0.0,18-0.0,19-0.0,20-0.0,21-0.0,22-0.0,23-0.0,32-0.0,33-0.0,34-0.0,35-0.0,36-0.0,37-0.0,38-0.0,39-0.0,48-0.0,49-0.0,50-0.0,51-0.0,52-0.0,53-0.0,54-0.0,55-0.0,64-0.0,65-0.0,66-0.0,67-0.0,68-0.0,69-0.0,70-0.0,71-0.0,80-0.0,81-0.0,82-0.0,83-0.0,84-0.0,85-0.0,86-0.0,87-0.0,96-0.0,97-0.0,98-0.0,99-0.0,100-0.0,101-0.0,102-0.0,103-0.0,112-0.0,113-0.0,114-0.0,115-0.0,116-0.0,117-0.0,118-0.0,119-0.0,"; // Example message
void setup() {
size(400, 400); // Document size
background(0); // Background color
udp = new UDP(this, PORT, HOST); // Create a new UDP
udp.listen(true); // Listen UDP
//MidiBus.list(); // List all available Midi devices
myBus = new MidiBus(this, 1, "Launchpad"); // Create a new MidiBus
}
void draw() {
String[] list = split(receivedFromUDP, ','); // Create a list from a string
int channel = 0; // MIDI channel
int number = 0;
int value = 90;
for (int i = 0; i < (list.length-1); i+=1) {
String[] values = split(list[i], '-');
int pitch = int(values[0]); // Pitch (pad)
float m = map(float(values[1]), 0, 1, 0, 127); // Map values from 0-1 to 0-127
int velocity = int(m); // Velocity (color)
myBus.sendNoteOn(channel, pitch, velocity); // Set note on
}
myBus.sendControllerChange(channel, number, value); // Send a controller change
}
void receive(byte[] data, String HOST, int PORT) {
String value = new String(data); // Recieved UDP message
receivedFromUDP = value; // Assign message to global string
}
That’s that.