[BUG] OSC input failing?

Hello, first-time poster here. I have developed OSC support, using JUCE, for the FOSS synthesizer Surge XT (https://surge-synthesizer.github.io/). All has been working well, but I just discovered that if I send a string over OSC consisting only of slashes (e.g. "/', or “//”, or “///”, etc.), no further callbacks of OSCMessageReceived() are generated until JUCE OSC input is stopped and restarted.

I wonder if anybody can confirm this behavior. I’m on a Silicon Mac, JUCE 7.0.5, btw.

EDIT: I have added a call to registerFormatErrorHandler(), and no such error seems to be generated. (Second EDIT): I cannot seem to trigger a Format Error at all, even when passing strings such as “x” or “&&&&” (although these strings do not “kill” subsequent OSC input processing).

I’m guessing the release of version 8 is keeping devs busy, but if someone could acknowledge (or refute) this bug, I’d be grateful.

I would say it potentially might have something to do with this infinite loop in src/surge-xt/osc/OpenSoundControl.cpp:

void OpenSoundControl::oscBundleReceived(const juce::OSCBundle &bundle)
{
    std::string msg;

    for (int i = 0; i < bundle.size(); ++i)
    {
        auto elem = bundle[i];
        if (elem.isMessage())
            oscMessageReceived(elem.getMessage());
        else if (elem.isBundle())
            oscBundleReceived(elem.getBundle());
    }
}


… basically, I think you shouldn’t be making the differentiation on whether to be despatching on bundles or messages in the bundle handler - juce_OSC already does this.

From juce_OSCReceiver.cpp:

    //==============================================================================
    void callListeners (const OSCBundle::Element& content)
    {
        using OSCListener = OSCReceiver::Listener<OSCReceiver::MessageLoopCallback>;

        if (content.isMessage())
        {
            auto&& message = content.getMessage();
            listeners.call ([&] (OSCListener& l) { l.oscMessageReceived (message); });
        }
        else if (content.isBundle())
        {
            auto&& bundle = content.getBundle();
            listeners.call ([&] (OSCListener& l) { l.oscBundleReceived (bundle); });
        }
    }

Instead, just use the juce_OSC- provided callbacks for oscMessageRecieved and oscBundleReceived individually (i.e. have two handlers) - don’t do this yourself, its redundant and buggy.

The despatching is handled upstream in juce_OSC - you should just be receiving the message/bundle you expect, and processing it.

Verify this yourself by setting a breakpoint on oscBundleReceived, and see how many times it gets called in your test case.

2 Likes

i have the same loop in all my code and never had any problems with it - indeed, if the sender can send bundles then you should have this in your code as the juce code won’t recurse, intentionally (obvs I’m not commenting on the original issue, but just the processing of incoming messages)

1 Like

I’m not getting any calls to OpenSoundControl::oscBundleReceived when I send a string of “/”. And I could be wrong (I’ll check into this), but I believe the example code for JUCE OSC does this same recursive call. I’ll look further into this, though, and thank you for your suggestion.

EDIT: As I understand it, the recursion is supposed to handle bundles of bundles; at any rate, it doesn’t look like the problem lies there, as it’s not even getting called for an input message of “/”.

Ieehu, thank you for your reply. Is there any way you could try sending a message of “/” to your parser to see if it does the same thing?

I’d like to extend this request to anyone who has a functioning, testable JUCE OSC implementation. Try sending it a “/” and see if it knocks out further OSC processing. I have yet to have confirmation that it’s happening to anybody else. Many thanks!

Have you tried debugging this down inside of the JUCE code? Find where the raw message comes in, put a breakpoint, and follow the code up from there.

Not yet, but I will. However, I’d prefer to know if it can be replicated before dropping the other stuff I’m working on to dig further into it.

I tried adding the following to the OSCDemo in the DemoRunner

sender2.send (String ("/"));
sender2.send (String ("//"));
sender2.send ("/", String ("/"));
sender2.send ("//", String ("//"));
sender2.send ("/juce/rotaryknob", String ("/"));
sender2.send ("/juce/rotaryknob", String ("//"));

and for this I see the corresponding output

- (8bytes with invalid format)
- (8bytes with invalid format)
- (12bytes with invalid format)
- (12bytes with invalid format)
- osc message, address = '/juce/rotaryknob', 1 argument(s)
    - string    /
- osc message, address = '/juce/rotaryknob', 1 argument(s)
    - string    //

These messages seem to continuously make it through without issue.

Thank you very much for doing this. OK, well, I’ll step-debug this later today.

Just out of curiosity, how well does:

sender2.send (String ("\/\/"));

… parse?

OK, it’s a false alarm. I finally got a chance to debug the code, and it was failing on my end. Here was my original parsing code:

void OpenSoundControl::oscMessageReceived(const juce::OSCMessage &message)
{
    std::string addr = message.getAddressPattern().toString().toStdString();
    if (addr.at(0) != '/')
    {
        sendError("Bad OSC message format.");
        return;
    }

‘addr’ is an empty string for OSC messages containing just “/” chars. Making the line

if (addr.empty() || addr.at(0) != '/')

fixes the issue for me. Sorry for the noise, but I hope this might help somebody else who runs into the same issue. I didn’t realize that getAddressPattern() would return a null string in this case, but in retrospect, should have guarded against it. It was an insidious error, too, as it looked like the failure was upstream…further parsing just silently failed.

1 Like