I read your first post again and if you don't need MIDI for your NeoPixels, you won't need MIDI at all! You can do everything with OSC, you would have to set up a network connection though. OSC works via network with IPs and stuff. So I don't know exactly how OSC would work with an USB-plugged-in Ardiuno or so. Maybe there is a way to establish a network via USB?
OSC for itself is a very simple thing. You have a server and one or multiple clients. Basically a client tells the server "oi, send me all your data!" and the server will do so.
So an OSC-message will look something like this: "/sl/1/hit record" which would hit the record-button of sl. When record was started, SL will send "/sl/1/state 2" (I believe) and you could determine your actions by knowing, that state 2 means "recording".
For your better understanding here is a little bit of my code which receives the OSC message, deconstructs it and sends it to everything I want to:
Code: Select all
int oscEingang(const char *path, const char *types, lo_arg ** argv, int argc, void *data, void *user_data)
{
std::string pfad = path;
if (pfad.find("/sl/") == 0) {
std::string typetag;
for (int i = 0; i < argc; i++) {
typetag += types [i];
}
if (typetag == "isf") {
int loopID = argv[0]->i;
std::string befehl(&argv[1]->s);
float parameter = argv[2]->f;
behringer.BefehlOSC(loopID, befehl, parameter);
iPad.BefehlOSC(loopID, befehl, parameter);
launchPad.BefehlOSC(loopID, befehl, parameter);
if (logOSC) if (befehl != "in_peak_meter") std::cout << "OSC-Nachricht von SL: " << loopID << ", " << befehl << ", " << parameter << std::endl;
} else {
if (logEvents) std::cout << "FEHLER: unbekannter Typetag: " << typetag << std::endl;
}
} else {
if (logEvents) std::cout << "FEHLER: unbekannter OSC-Pfad: " << pfad << std::endl;
}
fflush(stdout);
return 1;
}
So it receives a message like "/sl/1/state 2" and deconstructs it this way:
"/sl/" isn't needed since there is only instance of sooperlooper, so it's only used to determine whether it is a message from sooperlooper or not.
The typetag means there is a message with an integer datatype, a string datatype and a float datatype. The integer would be the loopnumber (/sl/
1/state 2), the string would be the "command" (/sl/1/
state 2) and the float the value of that (/sl/1/state
2). It then takes those variables and stuffs them into "BefehlOSC" so it can be used by a function which will do whatever you want with this information. Note that nearly all messages will be in this format! So if you would want to use the value (which is called "parameter" in the next code-snippet) as an integer, you would have to convert it first into integer. Same thing for sending OSC, if you have an integer value to send, you would have to convert it to float first.
And here this received message tells a Novation LaunchPad (which does only accept MIDI, you could do anything you want with the data though) what to do when receiving the state of a looper:
Code: Select all
void LaunchPadSteuerung::BefehlOSC(int loopID, std::string befehl, float parameter) {
if (befehl == "state") {
switch ((int)parameter) {
case 0: midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpStumm + loopID, rot1);
midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpSolo + loopID, gruen1);
midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpAufnahme + loopID, gelb1);
midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpOverdub + loopID, aus);
midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpReplace + loopID, aus);
aufnahmeStatus[loopID] = 0; break;
case 1: midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpAufnahme + loopID, blinkrot2);
aufnahmeStatus[loopID] = 1; break;
case 2: midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpAufnahme + loopID, rot3);
aufnahmeStatus[loopID] = 2; break;
case 3: midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpAufnahme + loopID, blinkrot2);
aufnahmeStatus[loopID] = 3; break;
case 4: midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpAufnahme + loopID, gruen2);
midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpSolo + loopID, gruen1);
midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpStumm + loopID, rot1);
midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpOverdub + loopID, gelb1);
midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpReplace + loopID, rot1);
aufnahmeStatus[loopID] = 4; break;
case 5: midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpOverdub + loopID, gelb3);
aufnahmeStatus[loopID] = 5; break;
case 10: midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpStumm + loopID, rot3); break;
case 20: midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpStumm + loopID, rot3); break;
}
} else if (befehl == "is_soloed") {
if ((int)parameter == 1) midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpSolo + loopID, gruen3);
else midiBefehl(LaunchPadAusgang, portAusIDLP, noteOn, lpSolo + loopID, gruen1);
}
}
So here I transfer all variables from the OSC message into a MIDI command to be understood by the LaunchPad. So "/sl/1/state 2" will make the button which correlates to the looper id (called loopID here + a constant which will "push" the desired command into the right place) shine in bright red.
Since I'm german I coded everything possible in german, so I hope you can understand what I did there.
There are a couple of OSC tutorials in the web and there is an OSC-documentation of sooperlooper as well which can be found
here. A library for OSC on Arduino would be
this (I used another one apparently - I coded this quite a while ago).
Good luck and a lot of patience!