Faust problems

gate/button output →
I’ve pushed an update with a foreign function that you can use like this:


push = ffunction(int owl_pushbutton(int), <owl.h>,"");
process = hslider("Frequency[OWL:PARAMETER_A]",0,0,1,0.01) : int : push;

(idiot patch, sorry!)

The return value is simply the current state: 0 or 1. Any non-zero value turns the LED red and gate on.
The function is called every sample, but registers changes which are propagated to the firmware along with the current sample count. Should be very efficient and accurate.

I’ve done a bit of testing with the latest faust2 and it seems pretty solid.
@stas if you are using faust2 let me know if you come across any problems.

If there are no obvious issues I’d like to push the latest faust2 to the live server, and update our sample patches. Help with the latter would be much appreciated!

Ok, I’ve made a few tests. It certainly does work (and I am running it on faust2 branch). But I’ve noticed a few issues. It’s up to you to decide if they’re severe enough to fix, because it’s still better than having no gate output. So here’s the test patch I’ve used:

import("stdfaust.lib");

push = ffunction(int owl_pushbutton(int), <owl.h>,"");
freq = hslider("Frequency[OWL:A]", 120, 20, 220, 1);
process = ba.pulsen(100, ma.SR / freq : int) : push;

That’s basically 100 samples wide pulse sent with 20-220 Hz frequency. Here’s what I’ve noticed:

  1. There’s a lag behind audio and gate out
  2. Lag duration depends on output buffer size - the bigger buffer, the later arrives gate signal, as expected
  3. On large buffer size, there’s some obvious jitter in gate output.

It’s an unrealistic code, just something I came up to test current implementation under extreme conditions.

And I’ve noticed another problem when testing this patch. Here’s how to reproduce it:

  1. Set frequency to miniumum, buffer size to 2.
  2. Now set frequency to maximum and try switching buffer size to anythnig else.

What happens for me is that the patch seems to retrigger (i.e. there’s about 25 ms silence), but buffer size stays the same in over 95% cases. Sometimes it does changes though and everything works fine if clock frequency is reduced. The same happens if I try to switch to another patch. CPU usage stays below 10% all the time. I’m not sure if that’s even a problem with IO in OWL itself or it could be something related to Linux USB stack. But remote control works and I can toggle device polling.

I’ll be testing faust patches in OwlPatches repo, will leave you a PR with fixes if necessary.

ok great - I’ve just pushed some changes I’ve done to OwlPatches/Faust, so make sure you pull.

So to receive midi note messages in faust it seems you make a slider or button for each note.
The only use of midi:key{on,off,press} I can find in the examples is in midiTester.dsp and it only seems to display the
value pressed.
Am I right in assuming that to handle all MIDI notes you would need 128 voices running in parallel, unless you use the experimental mute branch of Faust?

The CC handling is nice. Control change messages are already mapped to OWL parameters so not sure we need [midi:ctrl]. Could add support for all 40 MIDI-enabled OWL parameters though.

Regarding push output: yes, synchronising outgoing button/gate changes to the audio stream is on the firmware todo list.

As far as I understand, incoming midi MIDI note would be automatically mapped to a control with label “freq” and would be converted from midi note number to herz. And instruments from physical modeling library have MIDI-enabled models defined in that file i.e. https://github.com/grame-cncm/faust/blob/master-dev/libraries/physmodels.lib#L809-L823

I think there used to be no good solution for MIDI-based polyphony and you’d have to define each voice separately and handle voice allocation outside of faust. Seems like there’s proper support for this now, but it must be done from architecture file. See some info here - faust/architecture/api at master-dev · grame-cncm/faust · GitHub

documentation/faust-quick-reference.pdf has some info regarding MIDI&polyphony in chapters 8&9. But it’s mostly written for users. After looking through architecture/jack-qt.cpp, it seems to be pretty easy to implement. I guess owl’s own MIDI code would somewhat complicate things, since you’d have to coordinate its host MIDI code with faust’s rtmidi library? Seems to be what architecture/faust/midi/jack-midi.h does for JACK MIDI connectivity.

Here’s another useless fun fact I came up with: connecting OWL to Experst Sleepers FH-1 + 7x FH-1x expanders could give you up to 64 channels of CV controllable by MIDI. For now I can confirm that FH-1 can see Owl if I connect it by USB - but that should happen for any class compliant USB device.

I don’t understand if there’s any way to generate MIDI events in faust. Even if not, it could probably be done by writing a faust library for exposing OWL’s MIDI host implementation via FFI.

I’ve been rebuilding latest Faust2 and ended up with a failure related to min/max macro clashing with some stuff from libnewlib sources. Rolling back to a version about a week older fixed it for me.

For reference, this is the error log I’ve got:

Building patch AutoWah
In file included from /usr/include/newlib/c++/5.4.1/bits/char_traits.h:39:0,
                 from /usr/include/newlib/c++/5.4.1/string:40,
                 from ./Build/Source/FaustPatch.hpp:84,
                 from ./Build/registerpatch.h:1,
                 from ./Source/PatchProgram.cpp:7:
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:243:56: error: macro "min" passed 3 arguments, but takes just 2
     min(const _Tp& __a, const _Tp& __b, _Compare __comp)
                                                        ^
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:265:56: error: macro "max" passed 3 arguments, but takes just 2
     max(const _Tp& __a, const _Tp& __b, _Compare __comp)
                                                        ^
In file included from ./LibSource/Patch.h:4:0,
                 from ./Source/SampleBuffer.hpp:6,
                 from ./Source/PatchProgram.cpp:3:
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:195:5: error: expected unqualified-id before 'const'
     min(const _Tp& __a, const _Tp& __b)
     ^
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:195:5: error: expected ')' before 'const'
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:195:5: error: expected ')' before 'const'
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:195:5: error: expected initializer before 'const'
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:219:5: error: expected unqualified-id before 'const'
     max(const _Tp& __a, const _Tp& __b)
     ^
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:219:5: error: expected ')' before 'const'
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:219:5: error: expected ')' before 'const'
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:219:5: error: expected initializer before 'const'
In file included from /usr/include/newlib/c++/5.4.1/bits/char_traits.h:39:0,
                 from /usr/include/newlib/c++/5.4.1/string:40,
                 from ./Build/Source/FaustPatch.hpp:84,
                 from ./Build/registerpatch.h:1,
                 from ./Source/PatchProgram.cpp:7:
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:243:5: error: 'std::min' declared as an 'inline' variable
     min(const _Tp& __a, const _Tp& __b, _Compare __comp)
     ^
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:246:7: error: expected primary-expression before 'if'
       if (__comp(__b, __a))
       ^
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:246:7: error: expected '}' before 'if'
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:246:7: error: expected ';' before 'if'
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:248:7: error: expected unqualified-id before 'return'
       return __a;
       ^
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:265:5: error: 'max' declared as an 'inline' variable
     max(const _Tp& __a, const _Tp& __b, _Compare __comp)
     ^
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:268:7: error: expected primary-expression before 'if'
       if (__comp(__a, __b))
       ^
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:268:7: error: expected '}' before 'if'
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:268:7: error: expected ';' before 'if'
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:270:7: error: expected unqualified-id before 'return'
       return __a;
       ^
/usr/include/newlib/c++/5.4.1/bits/stl_algobase.h:271:5: error: expected declaration before '}' token
     }
     ^
compile.mk:97: recipe for target 'Build/PatchProgram.o' failed

That’s odd, I’m not seeing the same error.

I’ve just updated to latest faust2 branch, Version 2.1.1

What version of the gcc toolchain are you compiling with?

I’ve pushed a small change to OwlProgram which might help, try pulling and recompiling (changed the include file order).

Did you happen to forget to push that OwlProgram update? I don’t see anything but docs update in master branch.

FYI, I did remove FaustPatch.cpp in OwlProgram after each upgrade and toolchain version used was arm-none-eabi-gcc (15:5.4.1+svn241155-1) 5.4.1 20160919

I’ve made a few tests and I think I can tell you how to reproduce this. The problem seems to happen only if I create Build/Source/FaustPatch.hpp from faust2 branch. If I compile patches with that file created on master branch of faust, everything is fine no matter which version of faust I use at patch compile time. So you have to delete FaustPatch.hpp and use faust2 in order to get this failure.

For MIDI, a specific OWL native API ==> Faust MIDI layer glue has probably to be implemented (defining a owl_midi class, sub class of midi_handler). Following what is already done for JUCE and Bela (for instance…) in this folder: faust/architecture/faust/midi at master-dev · grame-cncm/faust · GitHub

This owl_midi class could then be used with the MidiUI class, or a polyphonic object (mydsp_poly class defined in faust/poly-dsp.h at master-dev · grame-cncm/faust · GitHub file)

The FAUST poly midi code looks great, but I think we will have to roll our own. The FAUST version uses STL (std::map, std::vector et c) which is a bit too heavy for embedded use.

FAUST poly-dsp.h uses a method of processing in slices which is a really nice way to get sample accurate parameter changes e.g. for note onsets.

Sample accurate parameter changes and sample processing is the role of timed_dsp class (in timed-dsp.h). This has been implemented with MIDI sync (clock/start/stop messages), but not yet with other MIDI messages (note on/off, controller…). But this could be done easily.

Hey Martin,

Any luck reproducing the min/max macro issue on your side?

As far as I understand, it happens because patches on faust2 have #include <string> needed for a few variables defined in the dsp_factory class that appears under faust2. That class is for interpreter backend as described at http://faust.grame.fr/news/2016/06/30/faust-interpreter.html . Doesn’t look like that’s something usable on owl - in fact just commenting out that class and string library include works for me as a solution.

Maybe it should be possible to disable those includes in faust/dsp/dsp.h with preprocessor?

dsp_factory is actually used for LLVM and interpreter backends. BTW, why is having a string type (and associated #include <string> a problem on OWL ? Limitations of supported C++ ?

I think it’s just a clash with the include order. We define max() and min() macros for patches to use - we probably shouldn’t.

The problem I’m getting is that there’s a conflict from min/max functions defined here - OwlProgram/basicmaths.h at master · pingdynasty/OwlProgram · GitHub and in newlib bundled with ARM toolchain. The latter has 3-operator form for 2 values and comparison function - error log is at https://hoxtonowl.com/forums/topic/faust-problems/page/2/#post-2942

I’ve tried various toolchain versions but it seems to be always present. I’m not 100% sure if that’s something wrong on my environment or not, since Martin said before he wasn’t getting that failure.

I thought changing the include order would fix it. You can try putting #include "Patch.h" last in the includes.
Or you can try adding #undef min, #undef max, #undef abs after the Patch.h include.

I don’t think any of this helps. The final FaustPatch.hpp file gets additional #include <string> below #include “Patch.h” anyway - it comes from inlined faust/dsp/dsp.h . So reordering won’t help eliminate this clash. Undefining min/max doesn’t help either - this macro is used in generated later.

So currently the only way for me to compile a patch is to manually edit FaustPatch.hpp to undef min/max before the include of string module from dsp.h and then redefine it, since it’s still being used later for constraints checks or something like that.

#including it before should work because the headers are only included once.

What branch of faust are you using?