danomatika / ofxPd

(maintained) a Pure Data addon for OpenFrameworks using libpd
Other
202 stars 45 forks source link

[solved] how can we receive OSC messages from the pd patch? #72

Closed moebiussurfing closed 5 years ago

moebiussurfing commented 5 years ago

I want to receive OSC messages. What's a good approach to do this? On the pdExample you mention this:

void ofApp::receiveList(const std::string& dest, const List& list) {
    cout << "OF: list " << dest << ": ";
...
    // print an OSC-style type string
    cout << list.types() << endl;
}

So not sure if I should make an OSC receiver into the patch and then to convert the message to a this kind of list and then send to the ofApp... More precisely I have 2 opened pd patches running together into the ofApp. Both sharing send/receives objects... But the thing is that I can't delete the OSC object and use directly a list sender because I am loading some patches with that OSC templates. (I am trying to implement into my ofApp an Oled screen of Organelle machine that uses OSC internally)

(I can imagine that is not possible to receive OSC into de ofApp from the pd patch as usual localhost...)

danomatika commented 5 years ago

If you need to receive OSC from an external application or computer, you can either use a [netreceive] object within your patch or use ofxOSC, then pipe the received messaging into the ofxPd instance. Sending can be done in the same manner: either from within Pd directly or via an ofxOSC sender.

If you need to send/receive internally, you can simply route the composed OSC-style messages to a Pd [receive] object that ofxPd is listening to and handle them in the PdReceiver callbacks, once such you have quoted. I say "OSC-style" as in something like an address as the message name and then arguments ... it's just a standard Pd list. You can also compose a real orc message with [oscformat], then parse it back into a Pd list to send to ofxPd with a following [oscparse].

moebiussurfing commented 5 years ago

ok, thanks @danomatika, thanks. just another two points... Sorry for the long message... ;)

  1. Little description: I am doing a kind of [(http://organelle.io)] emulator. I load 2 patches into ofxPd. (One [A] is an Organelle mother that handles device menus, in/out audio/midi, oled screen. The other patch [B] is the device generator: can be a looper, a sampler, synth etc) Mother patch [A] is always loaded and I can load differents devices [B] on demand)

The B patches can't be modified, so I can use the user library devices patches made by community or developers for the organelle platform. This patch has the OSC sender and I need to receive into the [A] mother patch, and then to convert the OSC message into list or something to send to my ofxPd / ofApp.

The question: OSC is sended internally between the 2 patches. Is this a problem? (Also can't we receive directly the OSC from a pd patch (running into ofxPd) to the ofApp?)

  1. Now I am doing like you said above. But can List methods (ofApp::receiveList) handles symbol (string) or float (numbers) types only? not int? I say this because in this case, the OSC is "destroyed" or requires to be rebuild in some way. This is to respect the argument types: OSC ints args are received as floats on the list listener...

The question: can we receive into ofxPd/ofApp a "pure OSC message" sending it as list?

Some code here:

// ofxOled.h
ofxOscMessage mOled;

//..

//ofApp.cpp
pd.subscribe("OF_oled");

//..

// ofApp.cpp
void ofApp::receiveList(const std::string& dest, const List& list) {

    if (list.isSymbol(0)) // first argument allways is the osc address
    {
        std::string address = "/";
        address += list.getSymbol(0);
        ofLogNotice() << "-> address '" << address << "'";

        mOled.setAddress(address);

        for (int i = 1; i < list.len(); ++i) // get all other present arguments
        {
            if (list.isFloat(i))
            {
                float listF = list.getFloat(i);
                int listI = (int) listF;
                ofLogNotice() << "    LIST FLOAT (as int) " << listI << " ";

                mOled.addIntArg(listI);
            }
            else if (list.isSymbol(i))
            {
                std::string listStr = ofToString( list.getSymbol(i) );
                ofLogNotice() << "    LIST SYMBOL " << listStr << " ";

                mOled.addStringArg(listStr);
            }
        }

        ofLogNotice("    OSC OLED") << ofToString(mOled);

        //-

        bTrigOSC = true;
    }
}

//            [notice ]     LIST FLOAT (as int) 0   // pos x
//            [notice ]     LIST FLOAT (as int) 57  // pos y
//            [notice ]     LIST FLOAT (as int) 8   // size
//            [notice ]     LIST FLOAT (as int) 1   // color
//            [notice ]     LIST SYMBOL 'Aux:''     // text
//            [notice ]     LIST SYMBOL 'Cancel'        // text
//            [notice ]     LIST FLOAT (as int) '1' // text
//            [notice ]     LIST SYMBOL 'voices'        // text
//            [notice ]     OSC OLED: /gPrintln 0 56 128 9 0 0 57 8 1 Aux: Cancel 1 voices

//--------------------------------------------------------------
void ofApp::update() 
{
    if (bTrigOSC == true)
    {
        // send message to filter
        oled.OSC_filter(mOled);

        bTrigOSC = false;
        mOled.clear();
    }
}

//--------------------------------------------------------------
void ofxOled::OSC_filter(ofxOscMessage m)
{
    //...

    else if (m.getAddress() == "/gPrintln")
    {
        int x       = m.getArgAsInt32(0); // pos x
        int y       = m.getArgAsInt32(1); // pos y
        int size    = m.getArgAsInt32(2); // size
        int c       = m.getArgAsInt32(3); // color
        string txt  = "";
        txt         += m.getArgAsString(4); // text. append all next args
        txt         += " " + m.getArgAsString(5);
        int last = 5;//previous are be mandatory. they will be there always. next ones are optional

        for(size_t i = last+1; i < m.getNumArgs(); i++)
        {
            if(m.getArgType(i) == OFXOSC_TYPE_INT32){
                txt += " " + ofToString(m.getArgAsInt32(i));
            }
            else if(m.getArgType(i) == OFXOSC_TYPE_FLOAT){
                txt += " " + ofToString(m.getArgAsFloat(i));
            }
            else if(m.getArgType(i) == OFXOSC_TYPE_STRING){
                txt += " " + m.getArgAsString(i);
            }
        }

        // draw received message:
        gPrintln(x, y, size, c, txt);
    }
}

Screen Shot 2019-06-21 at 18 51 02

moebiussurfing commented 5 years ago

ok. I see that "Note: there's no way using oscparse to distinguish between floats and integers, nor to see blobs unambiguously."

moebiussurfing commented 5 years ago

Now trying to getting the more direct way to make that real osc messages like in the screenshot patch... Not sure if the link from 'oscformat' to 'oscparse' send a ready list (floats/ints/resolution of floats...) to pipe to ofxPd