Forum Rule: Always post complete source code & details to reproduce any issue!
Page 3 of 12 FirstFirst 1 2 3 4 5 ... LastLast
Results 51 to 75 of 300

Thread: Open Sound Control (OSC) Teensy Audio Library Implementation

  1. #51
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    337
    Quote Originally Posted by JayShoe View Post
    I've lost many of the errors but still one "error: 'setMaxBuffers' was not declared in this scope"
    That will be because I'm using Teensyduino 1.56b3 - Paul has rolled one of MarkT's improvements right in ... I think there's something wrong with his scheduler, though to be fair it does look as if the Audio library pull request backlog is getting some attention. Either update to TD1.56b3, or just the AudioPlayQueue files, or comment out the offending line (though it'll come right back on the next pull!)

  2. #52
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    337
    Agree, dual serial +MIDI + audio would be a great addition. Having said that, at this point the source of the OSC packets is entirely programmer-driven, so we can use serial, network, MIDI or anything else we fancy.

    Looks like some sort of subscribe option is a good plan, though it has to be borne in mind that most audio objects don't currently support read-back of their internal state. I think the subscribe would need to be told which channel(s) to report on.

  3. #53
    Senior Member
    Join Date
    Jun 2018
    Location
    USA
    Posts
    242
    though it has to be borne in mind that most audio objects don't currently support read-back of their internal state
    A standard /subscription would pass the request on to the subscribed clients so no need for read-back. All clients would have to pay close attention if they want to be in sync! :-) Meters would work fine as the historical data is relatively irrelevant.

    An /info or /update type call looking for the current state or a /subscribe-update call would require each audio library object to support read-back.

    Interesting.

  4. #54
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    337
    I'm very slightly struggling to see how to be sure that a subscribed status message doesn't end up getting misinterpreted as a command, but that's mainly because I've not RTFM yet! I will, but I'd really like to get the dynamic construction stuff vaguely working first. It's nearly there - I think.

  5. #55
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    I have now implemented so that event-scripts are executed for the following tasks:

    Class Added
    Class Renamed
    Class Removed
    AudioObject Added
    AudioObject Renamed
    AudioObject Removed
    AudioConnection Added
    AudioConnection Removed

    the scripts are set to defaults which only outputs at the bottom log
    but they can easily be replaced by "OSC messages sending" instead
    when we have the spec. ready

    The scripts editors are at the "settings tab" - OSC

    And the functions to send messages are just like in the prev. post
    https://forum.pjrc.com/threads/68798...l=1#post294846

  6. #56
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    this is the output when I'm creating a simple synth
    Code:
    renamed Workspace fromSheet_1 to Voice
    added node In
    added node Out
    added node waveformMod
    added link (In, 0, waveformMod, 0)
    added node mixer4
    added node envelope1
    added link (mixer4, 0, envelope1, 0)
    added link (envelope1, 0, Out, 0)
    added link (waveformMod, 0, mixer4, 0)
    added node waveformMod1
    added node waveformMod2
    added link (waveformMod1, 0, mixer4, 1)
    added link (waveformMod2, 0, mixer4, 2)
    added link (In, 0, waveformMod1, 0)
    added link (In, 0, waveformMod2, 0)
    added node wavetable1
    added link (wavetable1, 0, mixer4, 3)
    added Workspace Sheet_1
    renamed Workspace fromSheet_1 to Synth
    added node Voice
    added node waveform1
    renamed node from waveform1 to lfo
    added link (lfo, 0, Voice, 0)
    renamed node from Voice to voices[16]
    added node mixer1
    added link (voices[16], 0, mixer1, 0)
    added node pt8211_2
    added link (mixer1, 0, pt8211_2, 0)
    added link (mixer1, 0, pt8211_2, 1)

  7. #57
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    337
    Phew! Got there! For a given value of there...

    OK, the d83b746 (latest) commit can create and destroy connections and a subset of the audio objects, and can use a created connection to connect two audio ports. There should be a way to disconnect while leaving the connection object in existence, but for now that crashes the system... just destroy the object and create a new one, for now.

    • you will need the latest audio core for this to work, as I broke it and didn't notice until today
    • there are a couple of Python demos, one controlling existing objects and the other creating and destroying. Fun may be had running one after the other!

    Assuming your Teensy is running the OSCAudioTesting demo:
    • /teensy1/dynamic/createObject<Audiotype><name> creates a new audio object of type Audiotype (e.g. AudioSynthWaveform), named name (both parameters are strings)
    • /teensy1/dynamic/createConn<name> creates a new connection object, named name
    • /teensy1/dynamic/destroy<name> destroys the audio or connection object, named name
    • /teensy1/audio/<conn>/connect<src><srcPort><dst><dstPort> uses connection object conn to connect <src> to <dst> using the port numbers given: you can omit the port numbers if they're both 0, though there's probably little point

    Various abbreviations are possible: cr*O*, cr*C*, d*, c*, but note there appears to be a bug in the OSC * matching so it sometime needs one more character in the address than you'd expect - see demo Python for things that work!

    Now to take a look at the GUI - at last!

  8. #58
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    337
    After a lot of sweat, I have a slider that controls the frequency and a two-octave piano working via OSC! Haven't figured out placing and connecting yet, the data structures available are rather unclear to me right now. Time to put the light out for a bit...

  9. #59
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    where are the SAFE_RELEASE defined
    and how do you use it

    I did try by defining it before the
    Code:
    #define SAFE_RELEASE
    #include "OSCAudioBase.h"
    is that correct?

    I'm using platformio
    and have completely replaced the whole "cores" folder with
    the one from
    https://github.com/h4yn0nnym0u5e/cores

    and I did also comment out AudioLib missing classes/"function calls"


    for all that don't know!
    to get the latest dynamic updates branch use this command:
    Code:
    git clone -b feature/Audio/dynamic-updates https://github.com/h4yn0nnym0u5e/cores.git
    I did create a compilable example using VSCODE + platformio
    here it is
    https://github.com/manicken/OSCdynamicTest

  10. #60
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    no wait
    it is really existing in that latest branch
    did find it just now by Agent ransack
    it's some kind of macro
    found in AudioStream.h
    Code:
    #define SAFE_RELEASE(...) __disable_irq(); active = false; release(__VA_ARGS__)
    #define SAFE_RELEASE_MANY(n,...) __disable_irq(); active = false; {audio_block_t* blx[]={__VA_ARGS__}; release(blx,n);}

  11. #61
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    by the way
    I used this to verify the comms from the tool
    https://sourceforge.net/projects/com0com/
    works on windows 10

  12. #62
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    I have now tested it
    with the GUI
    only at the moment with buttons
    the current state of that GUI
    is in DesignToolGui.json
    @
    https://github.com/manicken/OSCdynamicTest

    To be able to receive OSCBundles
    I changed the example code to receive in bundles
    this also takes care of simple messages,
    so special treatment is not needed

    note. the oscBundle.route function don't work
    so I did it "externally" instead

    the current state of the loop() code
    Code:
    void loop()
    {
      OSCBundle  bundle;
      OSCMessage *msg;
      int msgLen;
      int msgCount;
      char prt[200];
      
      while (!HWSERIAL.endofPacket())
      {
        
        msgLen = HWSERIAL.available();
        while (msgLen--)
        {
          char c = HWSERIAL.read();
          bundle.fill((uint8_t) c);
        }
      }
      Serial.println();
    
      if (!bundle.hasError())
      {
        msgCount = bundle.size();
        for (int i = 0; i < msgCount; i++) {
          msg = bundle.getOSCMessage(i);
          msg->getAddress(prt);
          Serial.println(prt);
          Serial.flush();
          msg->route("/teensy*/audio*",routeAudio); // see if this object can use the message
          msg->route("/teensy*/dynamic*",routeDynamic); // see if this object can use the message
          
        }
        Serial.println("---------------------");
        listObjects();
        Serial.println("=====================");
      }
    }

  13. #63
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    @Jonathan
    Fantastic work with dynamic connections
    And now dynamic objects
    It is like a dream come true, now we don't need to compile/upload for every little change of the design.

  14. #64
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    Don't think there is any need for reusing AudioConnections as the connections cannot be named in the tool anyway, and if they could it would not make any sense as when a wire is rewired the old one must first be deleted.
    But for other applications it can matter because then the routing can be changed without first removing the "wire"

  15. #65
    Senior Member
    Join Date
    Mar 2013
    Posts
    149
    I look forward to catching up with these amazing developments next week as I wind up my work for the year. I have noted the issues observed with surprising pattern matching results in the OSC library and will take a close look at that soon. At some point we had unit tests so I should be able to track down the regression.

  16. #66
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    337
    Quote Originally Posted by manicksan View Post
    @Jonathan
    Fantastic work with dynamic connections
    And now dynamic objects
    It is like a dream come true, now we don't need to compile/upload for every little change of the design.
    Thanks - it just needed this thread to make it useful! And couldn't have done it without OSC and your enhanced GUI, that's for sure...

    I'm assuming from your previous posts you've worked out the SAFE_RELEASE thing. I was just being lazy using a macro I happen to know I've defined [only] in the dynamic audio library, but I should really create something more meaningful like AUDIO_LIBRARY_DYNAMIC.

    Quote Originally Posted by manicksan View Post
    Don't think there is any need for reusing AudioConnections as the connections cannot be named in the tool anyway, and if they could it would not make any sense as when a wire is rewired the old one must first be deleted.
    But for other applications it can matter because then the routing can be changed without first removing the "wire"
    True, but it annoys me that it's not working - could be a sign of an underlying bug, too. The GUI will need to keep track of connections by name so it knows which ones to delete, unless I change the audio library to delete connections when the object is deleted. But the GUI will still have to be able to request deletion of just a connection...

    Quote Originally Posted by adrianfreed View Post
    I look forward to catching up with these amazing developments next week as I wind up my work for the year. I have noted the issues observed with surprising pattern matching results in the OSC library and will take a close look at that soon. At some point we had unit tests so I should be able to track down the regression.
    Excellent, thanks Adrian. Pesky day jobs, eh? Looking at the github code, I have my suspicions of OSCmatch.c line 113, which appears to refuse to match the * if there's nothing left of the address. But equally, I'm unfamiliar with OSC so I could easily be mistaking a feature for a bug!

    Cheers

    Jonathan

  17. #67
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    Here are two ways of auto-naming the connections
    1. "<sourcename><sourceport><targetname><targetpo rt>"
    2. "ac<number that increments for every new connection>"

    The number increments are just for the current instance of the Tool
    So when the Tool "restarts" the numbering restarts from zero.
    The numbering makes short names but they are not remembered in the tool yet.

    The first naming scheme always uses the same names and ports so that don't require any saving of connection names.

  18. #68
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    337
    Quote Originally Posted by manicksan View Post
    Here are two ways of auto-naming the connections
    1. "<sourcename><sourceport><targetname><targetpo rt>"
    2. "ac<number that increments for every new connection>"

    The number increments are just for the current instance of the Tool
    So when the Tool "restarts" the numbering restarts from zero.
    The numbering makes short names but they are not remembered in the tool yet.

    The first naming scheme always uses the same names and ports so that don't require any saving of connection names.
    Either of those makes sense, and to an extent it doesn't matter to the OSCAudio library. If there is a possibility of re-starting the GUI and rebuilding the design based on information retrieved from the Teensy, scheme 1 makes the GUI programmer's life easier. However, it's entirely possible to add a function somewhere to get the source/destination information from the connection objects. That's probably a good idea anyway, to make it possible to mirror system activity on a remote interface, as suggested by @JayShoe in #40. We can't necessarily rely on every device having seen all messages...

  19. #69
    Senior Member
    Join Date
    Jun 2018
    Location
    USA
    Posts
    242
    @adrianfreed I'm very interested in hearing your thoughts on.

    1) Synchronization between server<->client and keeping multiple clients synchronized.
    2) Sending/Receiving VU Meter data from Server->Client to display meters and flags on the client application (peak, rms, fft256, fft1024, tone, notefreq).

    If you had any input on standards and common configurations I'd love to hear. In the meantime, I'm looking into other application configurations and studying them.

  20. #70
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    @h4yn0nnym0u5e
    can you make a rename "name" function to the OSCAudioBase
    as you clearly know c++ a lot better that me

  21. #71
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    337
    Quote Originally Posted by manicksan View Post
    @h4yn0nnym0u5e
    can you make a rename "name" function to the OSCAudioBase
    as you clearly know c++ a lot better that me
    Yes, noticed you'd done that and realised I need to implement it. Good call.

  22. #72
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    or is this ok?
    Code:
    void rename(const char* newName)
    {
        if (NULL == newName) return;
        
        Serial.printf("Renamed %s to %s\n\n",name,newName);
        free(name);
        nameLen = strlen(newName);
        name = (char*) malloc(nameLen+3); // include space for // and null terminator
        if (NULL != name)
        {
          name[0] = '/'; // for routing
          strcpy(name+1,newName);
        }
    }

  23. #73
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    337
    Quote Originally Posted by manicksan View Post
    or is this ok?
    Code:
    void rename(const char* newName)
    {
        if (NULL == newName) return;
        
        Serial.printf("Renamed %s to %s\n\n",name,newName);
        free(name);
        nameLen = strlen(newName);
        name = (char*) malloc(nameLen+3); // include space for // and null terminator
        if (NULL != name)
        {
          name[0] = '/'; // for routing
          strcpy(name+1,newName);
        }
    }
    Something like that, yes. I might get paranoid and check for name being NULL before trying to free it, and making a function so the original name setting and the renaming both use the exact same code. But that will do very well until I can get to my home PC!

  24. #74
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    I think it's best if you also check for empty strings @
    OSCAudioBase::createObject
    So that an object is not created without any name or do not contain any whitespace, you could also get all in and trim any whitespace.
    Or if a whitespace exists inside a name it automatically is translated into a _ (underline)

  25. #75
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    think these will do it
    as we are actually doing it the C way
    Code:
    char *ltrim(char *s)
    {
        while(isspace(*s)) s++;
        return s;
    }
    
    char *rtrim(char *s)
    {
        char* back = s + strlen(s);
        while(isspace(*--back));
        *(back+1) = '\0';
        return s;
    }
    
    char *trim(char *s)
    {
        return rtrim(ltrim(s)); 
    }
    found them here
    https://stackoverflow.com/questions/...-a-string-in-c

    I did also test them
    here is the new code for
    createObject and createConnection
    Code:
    void OSCAudioBase::createObject(OSCMessage& msg, int addressOffset)
    {
        char* name;
        char* typ;
        
        void* pNewObj = NULL;
        name = (char*) malloc(50);
        char* nameOrigin = name; // so that free can be used later (as the trim function changes the start address)
        typ = (char*) malloc(50);
    
        msg.getString(0,typ,50);
        msg.getString(1,name,50);
        
        //Serial.printf("createObject(%s,%s)\n",typ,name);
        //dbgPrt(msg,addressOffset);
        name = trim(name);
        replaceWhiteSpace(name, '_');
        Serial.printf("createObject(%s,%s)\n",typ,name);
    
        if (strlen(name) == 0) Serial.println("empty name"); // don't allow any kind of "empty" name
        else if (NULL != find(name)) Serial.println("duplicate"); // don't allow duplicate name
    #define OSC_CLASS(a,o) else if (0 == strcmp(#a,typ)) pNewObj = new o(name);
        OSC_AUDIO_CLASSES // massive inefficient macro expansion to create object of required type
    #undef OSC_CLASS
        
        if (NULL != pNewObj)
        {
            Serial.printf("Created %s as a new %s at %08X\n",name, typ, (uint32_t) pNewObj);
        }
        //address:
        //Serial.printf("Address free(name) in memory: %p\n", &&address);
        free(nameOrigin);
        free(typ);
    }
    
    //============================== OSCAudioConnection =====================================================
    /**
     *    Create a new [OSC]AudioConnection object.
     */
    void OSCAudioBase::createConnection(OSCMessage& msg, int addressOffset)
    {
        char* name;
        name = (char*) malloc(50);
        char* nameOrigin = name; // so that free can be used later (as the trim function changes the start address)
    
        //dbgPrt(msg,addressOffset);
        msg.getString(0,name,50);
        name = trim(name);
        replaceWhiteSpace(name, '_');
        Serial.printf("createConnection(%s)\n",name);
        if (strlen(name) == 0) Serial.println("empty name"); // don't allow any kind of "empty" name
        else {
            OSCAudioConnection* pNewConn = new OSCAudioConnection(name);
            (void) pNewConn;
            Serial.printf("Created at: 0x%08X\n",(uint32_t) pNewConn);
        }
        free(nameOrigin);
    }
    and I did put the following in the OSCAudioBase.h OSCAudioBase class
    Code:
    static char *ltrim(char *s)
    {
        while(isspace(*s)) s++;
        return s;
    }
    
    static char *rtrim(char *s)
    {
        char* back = s + strlen(s);
        while(isspace(*--back));
        *(back+1) = '\0';
        return s;
    }
    
    static char *trim(char *s)
    {
        return rtrim(ltrim(s)); 
    }
    static void replaceWhiteSpace(char *s, char replace)
    {
        while (*s) {
            if (isspace(*s)) *s = replace;
            s++;
        }
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •