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.

Cinema 4D, Experimental, MoGraph, Processing, Python