Converting OSC messages to protocol buffer objects (or similar)


#1

Hi there -

(Forgive me, I’m still new to OSC messages & protocol buffers.)

I’m trying to build a simple C++ application that

  1. connects to the live OSC event stream broadcast by muse-io and
  2. plots the eeg or accelerometer data received (or otherwise “consumes” said data in an interesting, but simple way)

Nothing crazy - it’s just means of getting familiar with the SDK and getting the data flowing.

So far, I’ve got an application that uses liblo to connect to the OSC stream.


int main ()
{
  /** create an OSC server & listen on a port */
  lo_server_thread st = lo_server_thread_new ("5000", error);

  /** add handlers for OSC paths we're interested in */
  lo_server_thread_add_method (st, "/muse/eeg", NULL, handle_eeg_msg, NULL);
  lo_server_thread_add_method (st, "/muse/acc", NULL, handle_acc_msg, NULL);
  ...

  /** start the thread running, sleep in a loop, yadda yadda yadda */
  ...
  return 0;
}

/** simple handler for EEG messages */
int handle_eeg (const char *path, const char *types, lo_arg **argv,
                 int argc, void *data, void *user_data)
{ printf ("hey, look! an EEG datum!
");
 return 0;
}

The OSC message handlers are working fine, but it feels awkward to work with the OSC data structures.


/** simple handler for EEG messages */
int handle_eeg_msg (const char *path, const char *types, lo_arg **argv,
                     int argc, void *data, void *user_data)
{ printf ("hey, look! an EEG datum!
");

  /** parse the data out of argv and do something with it... **/
  if (argc == 4) // four channels
    { float pts[4];
      for (int i = 0; i < argc; i++)
        pts[i] = argv[i]->f;
      plot_new_eeg_point (pts);
      return 0;
    }
  else if (argc == 6) // six channels
    {
      // something similar...
    }
  else
    { printf ("malformed eeg message
");
      return 1;
    }

 return 0;
}

Ideally, I’d like to convert the data into a more convenient form for passing around the application or distributing via some type of in-process event system. It seems like this is what the protocol buffer schema is for, but constructing the objects still feels a little clunky.


int handle_eeg_msg ( ... )
{
  EEG eeg;
  if (argc == 4 || argc == 6)
    for (int i = 0; i < argc; i++)
      eeg . add_values (argv[i]->f);

  // hand the eeg object off to other parts of the application
  distribute_eeg_event (eeg);
  return 0;
}

Lastly, it’s not obvious to me how to incorporate information from messages in sub-paths like “/muse/eeg/quantization” with their higher-level data (e.g. “/muse/eeg”). That is, if the quantization numbers are needed to scale the eeg values, how does one combine those pieces of information if they come in on different messages? Do you keep the current quantization number around in global state? Are you always guaranteed to get a quantization message before an eeg message?

What I want to know…

  1. Is there a more elegant means of converting the OSC messages to MuseData objects from the protocol buffer schema?
  2. Is there another way I should be thinking about “consuming” or processing OSC messages?
  3. How does one handle combining hierarchical OSC data as in the “/muse/eeg” + “/muse/eeg/quantization” case?

Like I said, I’m just looking to get my feet wet with the SDK. Any guidance you can offer will be much appreciated.

Thanks!
Alan


#2

I’m attacking pretty much the same problem as you are. I’m just getting started, but I think that OSC is pretty much an ideal way to pass around information in real time, so for real time use wouldn’t you want to stick to OSC? That’s what it was designed for. I think that the protocol buffers aspect is used by muse for serialization (to save space for example).


#3

Hi, I’m also tackling this exact problem. I am new to this, but is there a way to fill the protobuf structures with the OSC data stream directly? Do I put /muse/eeg into protobuf’s EEG class manually or can I just dump all of /muse into MuseDataCollection? Sorry, newbie here.