SOUL Patches on OWL

Our idea for an improved custom memory manager is the following:

  1. expand the memory manager API so that it will receive the 1) type 2) size 3) access usage for the different memory zones of the DSP: like delay lines, static tables, DSP struct itself…
  2. have the -mem make the generated C++ code uses this extended memory manager API

Then use it in two steps:

  1. allocate a dummy DSP so that the memory manager could get all relevant informations about the DSP memory needs
  2. then the memory manager can decide the best allocation strategy with its 1) knowledge of the board capability (different RAM sections with their size and access speed) 2) requirement needs by the given DSP
  3. finally really allocate the DSP object by placing the DSP struct, delay lines, and static tables at the proper location in memory.

Do you think this strategy would fit your needs ?

Sounds a bit too complex and some things described may not be necessary. “delay lines, static tables, DSP struct itself” - actually, static tables would be loaded to static RAM as part of the patch. And DSP struct most likely should go to fastest memory section, because placing it on SDRAM would be the worst case scenario. Does that mean that we should only care about delay lines order in this case?

Current allocator that we use is fairly simple. It has one specific requirement to define sections in order of their memory addresses, which works well for us as this MCU has faster memories under lower addresses. So we end up allocating to faster memories first, but we have to choose allocation order accordingly.

knowledge of the board capability

The allocator itself doesn’t know anything other than address and size for each section. This is probably sufficient for performing allocations starting with largest objects (which could reduce fragmentation and place more data on faster memory).

requirement needs by the given DSP

It’s problematic to do it in runtime. But if we can detect at compile time which objects need updating once per block of audio rather than once per sample, we can treat them as second class and allocate them later (to slower memory).

Thanks for your feedback. The point of this somewhat complex strategy is to try to be as general as possible to be ready for the OWL, but also the Daisy board, ESP32 boards, Teensy board, possibly FPGA (with the starting Fast project here: https://fast.grame.fr).

Anyway I’ll come back to get more concrete feedback as soon as this new custom memory manager start to be usable.

I’ve merged in the OwlProgram branch and deployed to the online compiler, so… OWL now supports SOUL!

Just upload your soul files (.soul and/or .soulpatch) and select compilation type soul.

We don’t support sample loading yet, and there’s probably lots of things that don’t work, but setting parameters and receiving MIDI should be functional.

Also note that performance is not great, some examples that don’t work in realtime include:

  • Reverb
  • PadSynth
  • clarinetMIDI

Is clarinetMIDI this one SOUL/examples/patches/clarinetMIDI at master · soul-lang/SOUL · GitHub ?
If yes this is actually the Faust version automatically transpiled to SOUL in polyphonic mode (using SOUL written polyphonic wrapper). Does the original Faust version run in realtime then?

Faust can be transpiled to SOUL using the faust2soul tool here: faust/architecture/soul at master-dev · grame-cncm/faust · GitHub, or directly from the Faust Web IDE by choosing the “soul” platform in the export button.

Yes it is, and we have a copy in our patch library: Clarinet

It’s an old version, with old comments, and we run it monophonic so it can’t be directly compared to the SOUL example. On my Wizard here it uses 20% CPU.

OK. The new one is built using the Romain Michon reworked Physical Modeling library, now part of the Faust libraries: physmodels - Faust Libraries