Old 01-20-2019, 02:10 PM   #1
Kaitain
Human being with feelings
 
Join Date: Nov 2016
Posts: 34
Default 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!
Kaitain is offline   Reply With Quote
Old 01-22-2019, 07:15 AM   #2
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
Default

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.
mschnell is offline   Reply With Quote
Old 01-23-2019, 09:06 AM   #3
Kaitain
Human being with feelings
 
Join Date: Nov 2016
Posts: 34
Default

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!
Kaitain is offline   Reply With Quote
Old 01-25-2019, 06:03 AM   #4
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
Default

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.
mschnell is offline   Reply With Quote
Old 01-27-2019, 04:26 AM   #5
Kaitain
Human being with feelings
 
Join Date: Nov 2016
Posts: 34
Default

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!
Kaitain is offline   Reply With Quote
Old 01-27-2019, 02:32 PM   #6
Kaitain
Human being with feelings
 
Join Date: Nov 2016
Posts: 34
Default

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
Kaitain is offline   Reply With Quote
Old 01-30-2019, 07:42 AM   #7
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
Default

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.
mschnell is offline   Reply With Quote
Old 02-02-2019, 05:08 AM   #8
Kaitain
Human being with feelings
 
Join Date: Nov 2016
Posts: 34
Default

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!
Kaitain is offline   Reply With Quote
Old 02-03-2019, 11:25 PM   #9
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
Default

Great to hear that you solved it !

-Michael
mschnell is offline   Reply With Quote
Old 02-04-2019, 06:27 AM   #10
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
Default

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
mschnell is offline   Reply With Quote
Old 02-18-2019, 04:00 PM   #11
Kaitain
Human being with feelings
 
Join Date: Nov 2016
Posts: 34
Default

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!
Kaitain is offline   Reply With Quote
Old 02-19-2019, 10:44 PM   #12
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,634
Default

Quote:
Originally Posted by Kaitain View Post
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.
I suppose you are right about some buffers being the problem.
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
mschnell is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 07:45 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.