Mac can't handle amount of serial data that windows can

Status
Not open for further replies.

fricia

Member
Hi everyone

So, I'm building an OSC controller with a teensy 3.6. I'm reading 16 fader (slide potentiometer) values and sending them to a computer if a fader is moved. The code works as expected on Windows machines, but Macs seem to not be able to handle the amount of data I'm sending. If I make big jumps with a fader there is a very noticeable lag and if I do that with more than one fader it sometimes takes the mac seconds to process all the sent values. Then sometimes it recovers and i can receive a single fader signal normally, but sometimes the lag persists or gets continually worse, even if don't make any crazy movements.
I see that behavior in the software for which the control messages are meant (Max), as wells as the Arduino serial monitor. I have tried it on two different Macbooks.

Reducing the resolution of the ADC (hence reducing the amount of data sent) helps, but I have to reduce it by about 2/3 (!!) for it to work as smoothly as on Windows (and I have yet to see as much as a stutter on a windows machine).


I'm assuming Apples USB implementation doesn't just generally suck, so what am I missing? What am I doing wrong?


Code:
#include <OSCMessage.h>
#include <SLIPEncodedUSBSerial.h>
#include <ResponsiveAnalogRead.h>

const int faderAmount = 16;
const int analogInputPins[16] = {A14, A13, A16, A17, A18, A19, A20, A1, A2, A3, A4, A5, A6, A7, A8, A9};
char* oscAdresses[16] = {"/fader1", "/fader2", "/fader3", "/fader4", "/fader5", "/fader6", "/fader7", 
                         "/fader8", "/fader9", "/fader10", "/fader11", "/fader12", "/fader13", "/fader14", 
                         "/fader15", "/fader16"};

                  
class Fader {
  public:
    Fader(int _inputPin, char* _oscAdress);
    void handleInput(SLIPEncodedUSBSerial& SLIPSerial);
  
  private:
    int inputPin;
    char* oscAdress;  
    ResponsiveAnalogRead analog;
};

Fader::Fader(int _inputPin, char* _oscAdress) 
  : inputPin(_inputPin), oscAdress(_oscAdress), analog(_inputPin, true)
{
  pinMode(inputPin, INPUT);
  analog.enableEdgeSnap();    
}

void Fader::handleInput(SLIPEncodedUSBSerial& SLIPSerial) {
  analog.update();

  /* sending the OSC message */
  if(analog.hasChanged()) {    
    OSCMessage msg(oscAdress);
    msg.add(analog.getValue());
    SLIPSerial.beginPacket();  
    msg.send(SLIPSerial); 
    SLIPSerial.endPacket();
  }
}
                    
const int ledPin = 13;
Fader** fader = new Fader*[faderAmount];
SLIPEncodedUSBSerial SLIPSerial(Serial);

void setup() {
  pinMode(ledPin, OUTPUT);
  SLIPSerial.begin(9600);

  /* initializing the fader objects */
  for(int i = 0; i < faderAmount; i++) {
    fader[i] = new Fader(analogInputPins[i], oscAdresses[i]);
  }
  
  digitalWrite(ledPin, HIGH);  // turn on LED, so we know the Controller is powered. 
}

void loop() {
  
  for(int i = 0; i < faderAmount; i++) {
    fader[i]->handleInput(SLIPSerial);
  }
}
 
Last edited:
I'm assuming Apples USB implementation doesn't just generally suck, so what am I missing? What am I doing wrong?

Usually these sorts of problems happen when GUI-based software tries to redraw a window or do some other heavy GUI operation for each individual message. Often the best solution is to freeze the GUI and process all outstanding messages, then let the screen update.

Alternately, you could limit the transmit rate on the Teensy side. Or use a library like ResponsiveAnalogRead, which smooths the data for fewer changes.
 
Usually these sorts of problems happen when GUI-based software tries to redraw a window or do some other heavy GUI operation for each individual message. Often the best solution is to freeze the GUI and process all outstanding messages, then let the screen update.

Sadly I'm not in control of how the software draws the GUI. Thanks for that input though!

Alternately, you could limit the transmit rate on the Teensy side. Or use a library like ResponsiveAnalogRead, which smooths the data for fewer changes.

I am actually using the ResponsiveAnalogRead library. See code above.

Limiting the transmit rate on the Teensy side does help, but I can't believe that this is the only solution, when on Windows everything is running smoothly.
 
I don't think it's a general Win/Mac question, but a question of the OSC software running. Most probably, it's just the one which you have on the Mac which has problems. Try another one. Or monitor the OSC messages in general first with that tool: https://www.kasperkamperman.com/blog/processing-code/osc-datamonitor/

In case you have some noise on the potentiometer wipers, the analog.hasChanged() function might report too much false positives. If I were you, I would (independent of that) take the current stuff out of the loop. There is no need to waste system ressources about 1 million of times per second just to read 16 faders and to transmit all that quantization noise. Pack that code in a function and trigger it with an intervalTimer about 500 times a second. That's still more than enough, you can't move a slider pot quicker than that.
 
I can't really diagnose this Mac performance problem, but I can tell you from quite a lot of experience working with receiving the USB serial data on both platforms, at least that part uses relatively little CPU time on either system.

While OSC is more complex than MIDI, it's still a fairly simple protocol. It's possible OSC parsing might play a factor, but I would not suspect that.

From other projects, especially with Puredata and also working with optimizing Arduino's serial monitor (which used to lock up under full data rate that Teensy could send), my experience has been that trying to refresh a GUI too often has brought Mac, Windows and Linux systems to their knees. I've only done a moderate amount of GUI programming, and usually from within cross platform frameworks (like Java/swing, wxWidgets, FLTK, etc) but I've seen plenty of times where Mac and Windows differed greatly. At least with older versions, Apple had a double buffered drawing system by default for all windows, which apparently is the reason why pretty much all Mac programs avoid the flickery style updating some Windows and Linux programs seem to suffer. Whether that or other differences really account for the large difference in CPU usage is really just guesswork though.

But I would be very surprised if the serial stuff mattered. It's such a small amount of CPU time on either system.
 
In case you have some noise on the potentiometer wipers, the analog.hasChanged() function might report too much false positives. If I were you, I would (independent of that) take the current stuff out of the loop. There is no need to waste system ressources about 1 million of times per second just to read 16 faders and to transmit all that quantization noise. Pack that code in a function and trigger it with an intervalTimer about 500 times a second. That's still more than enough, you can't move a slider pot quicker than that.

I have already tried setting a delay of up to 5ms at the beginning of the loop, which didn't fix the problem. As I understand it this amounts to more or less the same as setting an intervalTimer right?

From other projects, especially with Puredata and also working with optimizing Arduino's serial monitor (which used to lock up under full data rate that Teensy could send), my experience has been that trying to refresh a GUI too often has brought Mac, Windows and Linux systems to their knees. I've only done a moderate amount of GUI programming, and usually from within cross platform frameworks (like Java/swing, wxWidgets, FLTK, etc) but I've seen plenty of times where Mac and Windows differed greatly. At least with older versions, Apple had a double buffered drawing system by default for all windows, which apparently is the reason why pretty much all Mac programs avoid the flickery style updating some Windows and Linux programs seem to suffer. Whether that or other differences really account for the large difference in CPU usage is really just guesswork though.

This could very well be the problem. I'll have a macbook at my disposal for a couple days sometimes next week so I will investigate further then.

Thank you all for your inputs!
 
Status
Not open for further replies.
Back
Top