10/07/2019
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.