More:

Tejas is correct that the issue is likely tied to how the *Teensy Audio
Library* architecture handles Faust UI elements, rather than raw DSP memory.

When you use hslider, nentry, or vslider in Faust, the faust2teensy
compiler generates specific "metadata" and control structures in the C++
class to make these variables accessible via the setParamValue method. If
you have many instances, each with multiple UI elements, you can hit a
limit in the way the Teensy Audio Library manages its internal "patch cord"
connections or the metadata table size.

Since you are targeting a Teensy and don't need a graphical interface, here
are the ideal ways to initialize and control these variables without using
standard UI primitives:
1. The "Function Argument" Approach (Best for flexibility)

Instead of defining freq as a UI element globally, define your triangle
wave as a function that takes these values as arguments. You can then "map"
these arguments to something that doesn't trigger UI generation.
Code snippet

// Instead of: freq = hslider("freq", 440, 20, 20000, 1);
// Use a function that expects arguments:
myTriangle(f, d, p) = ... your DSP code using f, d, and p ...;

// Then instantiate it with specific values or "external" signals
process = myTriangle(440, 0.5, 0.5);

2. Use checkbox for "Invisible" metadata (If you still need setParamValue)

Sometimes nentry and hslider carry more overhead because they require range
checking and step logic. If you only have a few parameters but many
instances, you might try using checkbox or a very simple button if the
logic allows, but this is usually a stopgap.
3. Use arg (C++ Style Arguments)

If you are comfortable with the generated C++ code, you can use the -args
compilation flag with the Faust compiler. This allows you to pass values
directly to the DSP's instanceInit function. However, this is less
"Faust-native" than the other methods.
4. Direct Variable Injection via library

If you want to keep the variables "tunable" from your .ino sketch without
the UI overhead, the most robust way is to define them as *global inputs*
to your process and connect them in the Teensy Audio Tool to a "DC" object
or a control signal.

   -

   In Faust: process(f, d, p) = ...; (This creates a 3-input DSP object).
   -

   In Teensy: Use the AudioSynthWaveformDC object to send a constant value
   into those inputs. This bypasses the Faust UI metadata entirely but keeps
   the values changeable at runtime.

Why removing hslider fixed it:

The Faust Teensy tutorial <https://faustdoc.grame.fr/tutorials/teensy/>
mentions that setParamValue uses string matching or index matching against
a table. Each hslider adds an entry to this table. By switching to
constants, you removed the metadata table and the associated
string-handling overhead, which is likely where the "upper limit" was being
hit.

*Recommendation for Tejas:* If you need to change these values at runtime
but want to avoid the UI limit, *Solution #4* is the most "Teensy-native"
way. By defining your freq, duty, and phase as *inputs* to your process
function (e.g., process = myTriangle;), they become standard audio-rate or
control-rate inputs in the Teensy Audio System. You can then use the Teensy
Audio Library's AudioConnection to plug control values into them.

On Wed, Mar 4, 2026 at 4:56 PM Julius Smith <[email protected]> wrote:

> Gemini replies:
>
> It appears Tejas has identified a crucial bottleneck: the *Teensy Audio
> Library’s metadata and memory overhead for UI elements*.
>
> When you use hslider, nentry, or vslider in Faust, the compiler generates
> metadata strings and internal variables to map these to a UI. On a
> microcontroller like the Teensy, each of these elements consumes a portion
> of the *DMAMEM* or *RAM* used by the Audio Library to manage the "patch
> cord" system. If you have many instances of a Faust object, ...
>
> On Tue, Mar 3, 2026 at 8:28 PM Tejas Rode <[email protected]> wrote:
>
>> Haha! Thank you for sharing that! :)
>>
>> Unfortunately, neither of the recommendations of Gemini worked. What
>> worked, again weirdly, is removing hslider() from the code. When I set
>> freq, duty and phase to constants (namely 440, 0.5 and 0.5), I was able to
>> create innumerable instances of triangle. I think what's coming in the way
>> is not related to Teensy memory at all, but related to Faust's UI, where
>> there's probably an upper limit on the number of UI elements that Faust
>> allows. Since teensy doesn't need UI elements, I removed them from the
>> code. However, I obviously don't want freq, duty and phase to have fixed
>> values. I tried nentry(), but that being a UI element too, has the same
>> problem. What is the ideal way I could initialize the three variables in
>> this case?
>>
>> I'll get to smoothing once this gets fixed.
>>
>> Thanks!
>> Tejas
>>
>> On Tue, Mar 3, 2026 at 7:29 PM Julius Smith <[email protected]>
>> wrote:
>>
>>> Being obsessed with AI assistance nowadays, I had Gemini answer this one
>>> directly in Chrome.  Gemini clearly knows more than me about life on a
>>> Teensy, so I delegate that, but the topics I do know about sound correct to
>>> me, so consider those "checked by someone who should know presuming he
>>> really paid attention" :-).
>>>
>>> Regarding the smoothing making the artifact worse, please post a
>>> standalone Faust program that illustrates it as simply as possible.
>>> There's probably a simple problem to fix.  We smoothly use interpolated
>>> delay lines all the time.
>>>
>>> --- Begin Gemini Weigh-In ---
>>>
>>> Based on the Faust documentation for Teensy
>>> <https://faustdoc.grame.fr/tutorials/teensy/>, the issue Tejas is
>>> experiencing with the fourth instance of the triangle wave is likely
>>> related to *RAM (memory) constraints*.
>>>
>>> Here is a breakdown of why this is happening and how to address it:
>>> Why the limit exists
>>>
>>> While the Teensy 4.1 is powerful, it has limited internal RAM.
>>> Faust-generated objects, especially those using delay-based oscillators or
>>> high-order interpolation (like squareND which Julius suggested), can
>>> have a larger memory footprint than expected.
>>>
>>>    -
>>>
>>>    If your code compiles but fails to execute (e.g., stops at the
>>>    "Test" print or crashes before setup), it usually means the global
>>>    objects are exceeding the available *DTCM (Data Tightly Coupled
>>>    Memory)*, causing the microcontroller to hang during initialization.
>>>
>>> Potential Solutions
>>>
>>>    1.
>>>
>>>    *Reduce Table Sizes:* If your triangle wave uses a large lookup
>>>    table, reduce its size. The default Faust oscillators often use a table
>>>    size of $2^{16}$ (65,536 samples), which is too large for multiple
>>>    instances on a Teensy. You can try reducing it to $2^{15}$ or
>>>    $2^{14}$ in your .dsp file:
>>>    Code snippet
>>>
>>>    // Example: reducing table size to 32768
>>>    tablesize = 1 << 15;
>>>
>>>    2.
>>>
>>>    *Optimize Delay Lines:* Since Tejas mentioned using fdelay, it's
>>>    important to know that every delay line allocates memory based on its
>>>    maximum delay length. If you don't specify a maximum, Faust might default
>>>    to a large value. You can use the -dlt (delay line threshold)
>>>    compiler option to manage how memory is allocated for these.
>>>    3.
>>>
>>>    *Check Memory Usage:* In the Arduino IDE, check the memory report
>>>    after compilation. If "Global variables use..." is very high (near 100%),
>>>    adding one more instance will push it over the edge.
>>>    4.
>>>
>>>    *Use AudioMemory:* Ensure you have enough audio blocks allocated in
>>>    your .ino file. While Tejas's snippet doesn't show the AudioMemory()
>>>    call for the triangle instances, the tutorial recommends increasing this
>>>    number if you have multiple audio inputs/outputs.
>>>    C++
>>>
>>>    void setup() {
>>>      AudioMemory(12); // Try increasing this value
>>>      Serial.begin(115200);
>>>      Serial.println("Test");
>>>    }
>>>
>>>
>>> For more details on managing memory for Faust on Teensy, you can refer
>>> to the *Notes About Computational Power and Memory Footprint
>>> <https://www.google.com/search?q=https://faustdoc.grame.fr/tutorials/teensy/%23notes-about-computational-power-and-memory-footprint>*
>>> section of the official tutorial.
>>>
>>> On Tue, Mar 3, 2026 at 4:00 PM Tejas Rode <[email protected]> wrote:
>>>
>>>> Thank you for the suggestion, Julius! I tried using both fdelay and
>>>> si.smoo(), but it worsened the artifact. I guess it's because the phase
>>>> changed more often with those approaches, as compared to using just delay.
>>>>
>>>> On a different note, I'm trying to run this on teensy 4.1. I've
>>>> followed this approach: https://faustdoc.grame.fr/tutorials/teensy/ .
>>>> There is a weird problem, though, where I'm able to create at most three
>>>> instances of the triangle. If I create a fourth instance, the code
>>>> compiles, but doesn't do anything. Is there really an upper limit on the
>>>> number of instances that could be created? How could I change the limit, if
>>>> any? Here is the code:
>>>>
>>>> #include <Audio.h>
>>>>
>>>> #include "FaustTriangle.h"
>>>>
>>>> FaustTriangle faustTriangle[4];  // "Test" is printed only when the
>>>> number of instances here are <= 3
>>>>
>>>> void setup() {
>>>>
>>>>   Serial.begin(115200);
>>>>
>>>>   Serial.println("Test");
>>>>
>>>> }
>>>>
>>>> void loop() {}
>>>>
>>>>
>>>> Regards,
>>>>
>>>> Tejas
>>>>
>>>> On Thu, Feb 26, 2026 at 1:57 AM Julius Smith <[email protected]>
>>>> wrote:
>>>>
>>>>> N is the order of interpolation.  It sounds like you want N=1, but
>>>>> maybe compare to higher N when everything is done.
>>>>>
>>>>> Instead of delay, use fdelay, and run its delay parameter through a
>>>>> smoother (e.g., si.smoo(), IIRC)
>>>>>
>>>>> On Thu, Feb 26, 2026 at 12:49 AM Tejas Rode <[email protected]>
>>>>> wrote:
>>>>>
>>>>>> Thanks for the hint! This is what I have put together. It runs, but I
>>>>>> have further questions.
>>>>>>
>>>>>> import("stdfaust.lib");
>>>>>> freq = hslider("freq", 440, 11, 880, 1);
>>>>>> N = 1;  // tried up to 4
>>>>>> duty = hslider("duty", 0.5, 0, 1, 0.01);
>>>>>> phase = hslider("phase", 0.5, 0, 1, 0.001);
>>>>>> triangleND(N,freq,duty,phase) = squareND(N,freq,duty,phase) :
>>>>>> fi.pole(p) : *(gain) with {
>>>>>>   gain = 4.0*freq/ma.SR;
>>>>>>   p = 0.999;
>>>>>> };
>>>>>> squareND(N,freq,duty,phase) = os.pulsetrainN(N,freq,duty) @
>>>>>> round(phase*ma.SR/freq);  // phase has audible jumps
>>>>>> process = triangleND(N,freq,duty,phase);
>>>>>>
>>>>>> I have two questions.
>>>>>> 1. How does the value of N affect how the output sounds? I tried N=1
>>>>>> to N=4, but didn't hear an audible difference. What value of N should I 
>>>>>> set
>>>>>> as default?
>>>>>> 2. When I move the phase slider, there are audible jumps. It's
>>>>>> probably because the phase is rounding to the nearest integer. Is there a
>>>>>> way to make the phase change sound smooth?
>>>>>>
>>>>>> I'm quite new to FAUST. Thank you for all the help!
>>>>>>
>>>>>> Regards,
>>>>>> Tejas
>>>>>>
>>>>>> On Sun, Feb 22, 2026 at 2:11 AM Julius Smith <[email protected]>
>>>>>> wrote:
>>>>>>
>>>>>>> I think I would just use a delay.  Search for "phase" in
>>>>>>> oscillators.lib and you'll see various approaches.
>>>>>>>
>>>>>>> On Sat, Feb 21, 2026 at 9:43 PM Tejas Rode <[email protected]>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> Hi Julius,
>>>>>>>>
>>>>>>>> I have a followup question. If I want to add phase value as an
>>>>>>>> argument to this triangleND function, what is the best way to do that?
>>>>>>>>
>>>>>>>> Thanks!
>>>>>>>> Tejas
>>>>>>>>
>>>>>>>> On Fri, Feb 13, 2026 at 4:08 PM Julius Smith <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Hi Tejas,
>>>>>>>>>
>>>>>>>>> You might try modifying os.triangleN(N,freq) to add a duty factor,
>>>>>>>>> where N is the order of the aliasing suppression.
>>>>>>>>> It's based on the paper "Alias-Suppressed Oscillators based on
>>>>>>>>> Differentiated Polynomial Waveforms" by Valimaki et al.
>>>>>>>>>
>>>>>>>>> My guess:
>>>>>>>>>
>>>>>>>>> triangleND(N,freq,duty) = squareND(N,freq,duty) : fi.pole(p) :
>>>>>>>>> *(gain) with {
>>>>>>>>>   gain = 4.0*freq/ma.SR; // for aproximate unit peak amplitude
>>>>>>>>>   p = 0.999;
>>>>>>>>> };
>>>>>>>>> squareND(N,freq,duty) = pulsetrainN(N,freq,duty);
>>>>>>>>>
>>>>>>>>> Then your 25% case would be os.triangleND(N,freq,0.25);
>>>>>>>>>
>>>>>>>>> Cheers,
>>>>>>>>> - Julius
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Fri, Feb 13, 2026 at 10:39 AM Tejas Rode <[email protected]>
>>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>>> Hello,
>>>>>>>>>>
>>>>>>>>>> I want to create an anti-aliased dfdsdg triangle wave with 25%
>>>>>>>>>> duty cycle for use in a teensy project. I'm new to faust. Is there a
>>>>>>>>>> resource that I can refer to? Any ideas that can help me start 
>>>>>>>>>> implementing
>>>>>>>>>> this?
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>> Tejas
>>>>>>>>>> _______________________________________________
>>>>>>>>>> Faudiostream-users mailing list
>>>>>>>>>> [email protected]
>>>>>>>>>> https://lists.sourceforge.net/lists/listinfo/faudiostream-users
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> AI has taken my job, but only I know what it is.
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> AI has taken my job, but only I know what it is.
>>>>>>>
>>>>>>
>>>>>
>>>>> --
>>>>> AI has taken my job, but only I know what it is.
>>>>>
>>>>
>>>
>>> --
>>> AI has taken my job, but only I know what it is.
>>>
>>
>
> --
> AI has taken my job, but only I know what it is.
>


-- 
AI has taken my job, but only I know what it is.
_______________________________________________
Faudiostream-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/faudiostream-users

Reply via email to