01-20-2019, 02:10 PM | #1 |
Human being with feelings
Join Date: Nov 2016
Posts: 34
|
Recieve from serial
Hi folks. I'm stucked here and I'd appreciate some help.
I'm trying to send float values from my controller to OSCii Bot. I was thinking about using SysEx to do that, as posted here: https://forum.cockos.com/showthread.php?t=215957 But as SysEx sends group of bytes (of which only 7 bits per byte are used) it seems more difficult than expected, specially the part of reconstructing the float value in the script using the separated bytes. But the point is that my controller generates normalized values between 0 and 1, and as the controller can send directly over serial (meaning that is not necesary for the messages to have MIDI format), is it possible to recieve data directly from the serial port in OSCii bot? (AFAIK Oscii bot only receives messages if they have MIDI (@midimsg) or OSC(@oscmsg) format) What would be the best way to accomplish this? Cheers! |
01-22-2019, 07:15 AM | #2 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
|
OSCIIBot only can attach to Midi devices and to TCP ports (OSC).
Does your controller do "serial" data in hardware ? If so, you need to set the port to 31250 Baud and adhere to the Midi protocol in your software. Moreover you need appropriate hardware to adhere o the midi 5-Pin hardware specs. And of course use a Midi I/O device to connct your controller to the Computer. Or does your controller do "???" over USB ? If so you need to use a "family" Midi-USB library to make the controller be accepted as a Midi device in the computer. -Michael Last edited by mschnell; 01-25-2019 at 06:06 AM. |
01-23-2019, 09:06 AM | #3 |
Human being with feelings
Join Date: Nov 2016
Posts: 34
|
Hi mschnell
My controller uses a Teensy 3.2, so it can send serial over USB, and also is recognized as a MIDI device in the computer. So maybe I could receive random serial data in OSCBot using msg1, msg2.. etc? I've never thought of that, I'll try it toda. Thank you! |
01-25-2019, 06:03 AM | #4 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
|
There was a typo in my message
OSCBot can receive "random" MIDI data. It can't connect to a "COMx" device in Windows, but just to a MIDI device. But if your µC is recognized by Windows as an USB Midi device this will be fine. Of course you need to adhere to the Midi spec and send only messages that start with a Byte with bit 7 set and the bytes with bit seven cleared (SysEx: 0xF0, ..... 0xF7) -Michael Last edited by mschnell; 01-25-2019 at 06:10 AM. |
01-27-2019, 04:26 AM | #5 |
Human being with feelings
Join Date: Nov 2016
Posts: 34
|
Yes, I've checked that it can't receive random serial.
It can receive "random MIDI" = Sysex, but as you said, always addering to the MIDI protocol. Thanks! |
01-27-2019, 02:32 PM | #6 |
Human being with feelings
Join Date: Nov 2016
Posts: 34
|
Some progress here.
What I'm trying to achieve is to send a float number fom my MIDI controller (Teensy) to OSCiiBot. This float number is normalized to 1024, so it has decimals and it goes from 0 to 1. So far I've manged to pack this float into a SysEx message, like this: for (int i = 0; i <= 3; i++) { paramValMSB[i] = (mapped.bytes[i] >> 4) & B00001111; paramValLSB[i] = mapped.bytes[i] & B00001111; } // SysEx message assemby uint8_t buff[] = {SysExStart, paramNumMSB, paramNumLSB, paramValMSB[0], paramValLSB[0], paramValMSB[1], paramValLSB[1], paramValMSB[2], paramValLSB[2], paramValMSB[3], paramValLSB[3], SysExEnd}; // Sens SysEx UsbMIDI.sendSysEx(sizeof(buff), buff, true); A float has 4 bytes. And I had to split evey one of the 4 bytes of the float variable (paramVal) into 2 bytes (MSB and LSB), in order to have the bit 7 set to 0 on each byte, according to the MIDI protocol. Although this is not a very efficient solution it works. Now, in OSCii Bot I wrote this to receive and reconstruct each byte: valByte0 = ((str_getchar(oscstr, 3) << 4) & 0xF0) | str_getchar(oscstr, 4); valByte1 = ((str_getchar(oscstr, 5) << 4) & 0xF0) | str_getchar(oscstr, 6); valByte2 = ((str_getchar(oscstr, 7) << 4) & 0xF0) | str_getchar(oscstr, 8); valByte3 = ((str_getchar(oscstr, 9) << 4) & 0xF0) | str_getchar(oscstr, 10); Checking every one the bytes received, they match byte per byte with the ones sent from the controller. So far so good. Now, the problem is how to construct a float number with these four bytes. I tryed this: val = ((valByte3 << 24) & 0xFF000000) | ((valByte2 << 16) & 0xFF0000) | ((valByte1 << 8) & 0xFF00) | valByte0; And although I get a 4 byte value with the 4 bytes in their right position and order, the value is interpreted as an integer. It doesn't follow the IEEE protocol: taking some bits for the sing, some for the exponent and some for the mantisa (which are indeed observed at the Arduino IDE on the other end). This is something I don't understand because inthe OSCii bot code reference says "Variables do not need to be declared, are by default global, and are all double-precision floating point". So my question is this: how can I construct a float value in OSCii bot starting from 4 bytes? Is there any chance to make some casting like "float(var)" or something? (I tried, didn´t work). Sorry for the very long post, but I couldn`t find a sorter way to explain this |
01-30-2019, 07:42 AM | #7 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
|
To send 4 random bytes you can just use 5 Midi bytes with bit 7 = 0. This would be slightly more efficient than sending 8 bytes with four relevant bits each.
But in fact I would not try to transfer some kind of binary float format via Midi. Regarding OSC the byte order and coding of float is predefined, and hence OSCBot will adhere to it. But the coding of the (floating point) variables used by EEL is not defined, and hence any assumption would be erroneous, and I suppose EEL can't "construct" binary floats at all. . That is why I would use integer (e.g. your floating value multipied by 1024 or something like this (resulting in 20 bits) . Esay but not perfectly efficient would be transferring 5 bytes with 4 bits each and in OSCIIBot just recreate that integer by adding and multiplying by 16, and finally divide by 1024 (remember, in EEL, any variable is a floating point). Now you can send this value via OSC by the standard means of OSCIIBot. Slightly more efficient and more exact: multiply by 262144, resulting in 28 bits that can be transferred in four Midi bytes . -Michael Last edited by mschnell; 02-03-2019 at 11:30 PM. |
02-02-2019, 05:08 AM | #8 |
Human being with feelings
Join Date: Nov 2016
Posts: 34
|
Yes, transmitting the floats with no decimal point is a very good idea. I can send an "integer", which is easier, and then divide the received value in the other end (OSCbot script) to recover the original float number.
ARDUINO SIDE: uint8_t SysExStart = 0xF0; // Start of System Exclusive message uint8_t paramNumMSB, paramNumLSB; // 2 bytes for the parameter number uint8_t SysExEnd = 0xF7; // EOX - End of Exclusive float nVal; // Normalized value float mappedVal; // Mapped value union data { // Structure for sent and received value (mapped*1E^9) uint32_t val; uint8_t bytes[4]; } multi_TX, multi_RX; float toLow; // Low margin for scaling float toHigh; // High marging for scaling uint8_t paramValMSB[4], paramValLSB[4]; // 4 bytes arrays for MSB and LSB parameter value // OSC number MSB and LSB paramNumMSB = uint8_t(OSCnum >> 7); paramNumLSB = (uint8_t(OSCnum) & 0x7F); // Convert value to float and normalize to 1024 nVal = float(val)/1024; // Scale toLow = float(minRange)/100; toHigh = float(maxRange)/100; mappedVal = map(nVal, 0, 1, toLow, toHigh); multi_TX.val = uint32_t(mappedVal*1e9); // Deconstruct float parameter value in bytes suitable for MIDI protocol: 4 bytes to 8 bytes, and bit 7 set to 0 on each byte for (int i = 0; i <= 3; i++) { paramValMSB[i] = (multi_TX.bytes[i] >> 4) & B00001111; paramValLSB[i] = multi_TX.bytes[i] & B00001111; } // SysEx message assemby uint8_t buff[] = {SysExStart, paramNumMSB, paramNumLSB, paramValMSB[0], paramValLSB[0], paramValMSB[1], paramValLSB[1], paramValMSB[2], paramValLSB[2], paramValMSB[3], paramValLSB[3], SysExEnd}; // Sens SysEx usbMIDI.sendSysEx(sizeof(buff), buff, true); OSCii bot SIDE: @midimsg // SYSEX messages startSYSX = str_getchar(oscstr, 0); // Check if message is a SYSEX header endSYSX = str_getchar(oscstr, 12); // Check if message is an end of SYSEX message. (startSYSX == 240) && (endSYSX == 247) ? ( origccMSB = str_getchar(oscstr, 1); // Get parameter MSB from oscstr origccLSB = str_getchar(oscstr, 2); // Get parameter LSB from oscstr origcc = (origccMSB *128) + origccLSB; valByte0 = ((str_getchar(oscstr, 3) << 4) & 0xF0) | str_getchar(oscstr, 4); valByte1 = ((str_getchar(oscstr, 5) << 4) & 0xF0) | str_getchar(oscstr, 6); valByte2 = ((str_getchar(oscstr, 7) << 4) & 0xF0) | str_getchar(oscstr, 8); valByte3 = ((str_getchar(oscstr, 9) << 4) & 0xF0) | str_getchar(oscstr, 10); val = ((valByte3 << 24) & 0xFF000000) | ((valByte2 << 16) & 0xFF0000) | ((valByte1 << 8) & 0xFF00) | valByte0; curvalparam = val/1e9; Althoug it can be more efficient, as you said, it works pretty well. Thanks for the hint! |
02-03-2019, 11:25 PM | #9 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
|
Great to hear that you solved it !
-Michael |
02-04-2019, 06:27 AM | #10 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
|
In fact for transferring 28 bit with 6 Midi messages, you don't even need to use SysEx. You could do
Note-On Bit 21-27 Bit 14-20 Note Off Bit 7-13 Bit 0-6 -Michael |
02-18-2019, 04:00 PM | #11 |
Human being with feelings
Join Date: Nov 2016
Posts: 34
|
Hi again
Well, I successfully managed to send SysEx messages from my controller (Teensy based) to OSCii bot, convert them to OSC messages and send them to Reaper. Also, the other way back works: OSC messages from Reaper go to OSCii bot and are converted to SysEx and sent to my controller. The problem I'm finding now is when opening Reaper: it sends all parameters at once. Since I can check that all Sysex messages are sent to the controller, I can see that only a few are received. Why is that? My guess is that this has something to do with buffers and serial port baud rate. I tried to increase the last, but no changes. Any ideas? Thanks! |
02-19-2019, 10:44 PM | #12 | |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
|
Quote:
Increase baud rate ? If this is 5 pin Midi, the baud rate is fixed (to 31.5 KBaud IIRC). If it's USB, the baud rate does not matter (Serial via USB always is as fast as possible). OSC can't be "timed", as it's a half duplex UDP protocol. Maybe you need to do a FiFo buffer in the OSCII script. Maybe even implement a handshake in the protocol with your comntroller. -Michael |
|
Thread Tools | |
Display Modes | |
|
|