Low pass filter knob implementation into working FM synth example

86 views
Skip to first unread message

Jack Chapell

unread,
Feb 14, 2025, 7:05:27 PMFeb 14
to Mozzi-users
Hi all,

I'm new to Mozzi and synthesizer code, but not new to arduino coding. I'm modifying the included Knob_LightLevel_x2_FMSynth example to have another knob on pin A3 which controls the cutoff of a low pass filter. I believe (not entirely sure still wrapping my head around Mozzi's code) I have implemented the low pass filter, but I do not know how to add the filter on top of the already working sound in the updateAudio() function. Anything I change within this function seems to break the code (and frankly, I have no idea how this function works at all). So my question is how can I take my low pass filter, and apply it to the updateAudio() function so that the program works? Code attached, thanks.

Benedikt Schöffmann

unread,
Feb 15, 2025, 7:32:06 AMFeb 15
to mozzi...@googlegroups.com

Hi Jack,

take a look at the updateAudio function in example AudioFilter/ResonantFilter:

AudioOutput updateAudio(){
  char asig = rf.next(aCrunchySound.next());
  return MonoOutput::from8Bit(asig);
}

 What is happening here is the sound of the oscillator (aCrunchySound) gets processed by the filter (rf). That is all you have to do in your case.

  1. AudioOutput updateAudio(){
  2.   long modulation = aSmoothIntensity.next(fm_intensity) * aModulator.next();
  3. char fmOut = aCarrier.phMod(modulation); 
  1.   return MonoOutput::from8Bit(lpf.next(fmOut);
  2.  
  3. }

Greets from Vienna,
Ben

--
You received this message because you are subscribed to the Google Groups "Mozzi-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mozzi-users...@googlegroups.com.
To view this discussion, visit https://groups.google.com/d/msgid/mozzi-users/51592593-3b19-441c-bcfb-8a96950fc1e2n%40googlegroups.com.
Message has been deleted
Message has been deleted

Jack Chapell

unread,
Feb 20, 2025, 6:54:50 AMFeb 20
to Mozzi-users
I tried to implement what you wrote, but now it makes a lot of glitchy noises and doesn't keep outputting the sound, so I think I've broken something. What did I miss?
Thanks from Canada,
Jack

Jack Chapell

unread,
Feb 20, 2025, 6:54:50 AMFeb 20
to Mozzi-users
I see, so does this mean I just need to nest my effects in order in brackets before returning them? Say I wanted a high pass filter after the low pass filter, could I write return MonoOutput::from8Bit(hpf.next(lpf.next(fmOut)); ? And while I'm on the topic, what exactly does MonoOutput::from8Bit mean? I've seen other sketches that use MonoOutput::from16Bit or MonoOutput::fromNBit. Other than some amount of bits being returned, what is the reason for choosing each of these return options? Thanks from Canada,
Jack

On Saturday, February 15, 2025 at 4:32:06 AM UTC-8 Benedikt Schöffmann wrote:
Message has been deleted
Message has been deleted

tomco...@live.fr

unread,
Feb 21, 2025, 7:36:13 AMFeb 21
to Mozzi-users
(I though I answered, but this does not appear, weird…).

> does this mean I just need to nest my effects in order in brackets before returning them? Say I wanted a high pass filter after the low pass filter, could I write return MonoOutput::from8Bit(hpf.next(lpf.next(fmOut)); ?

Yes, even though, depending on your resonance settings you might run into glitches/overflow if done directly. Basically, it boils to the fact that, as these filters have a resonance, they can output signals with a greater amplitude than what you feed them with, so say, the output lpf.next(fmOut) might actually span 10bits. There are different ways to solve that: clipping (with .clip()), using the 16bits version of the outmost filter, taming the signal after one one filter stage (for eg: (lpf.next(fmOut)>>2)), or having low resonance settings.

> what exactly does MonoOutput::from8Bit mean?

This actually nicely connected! Mozzi supports a lot of different platforms and modes to output the sound. The number of bits these platforms can output is not always the same (good old AVR outputs on 8bits, Teensy3 outputs on 12bits for instance). Mozzi is aware of that and will scale the samples accordingly but for that it needs to be aware of the range (number of bits) of the signal you are feeding it with. from8bits tells Mozzi than what follows is a value with spans 8bits. If your platform outputs 12bits, Mozzi will automatically shift it to fill up the 12bits (and the other way around if you output more than what your platform can output), see also: https://sensorium.github.io/Mozzi/doc/html/struct_mono_output.html#a02f9adf531ab61ce96ed80a8319bdeea

fromNbit is very useful to find the minimal number of bits needed, especially after a resonant filter (I always wanted to characterize these filters to know exactly how they change the range when the resonance is not zero but, well…). For instance I would start with: MonoOutput::fromNBit(8, lpf.next(fmOut); and if that glitches I would increase to say 10 or so until I am satisfied with the given resonance.

Hope this helps,

tomco...@live.fr

unread,
Feb 21, 2025, 7:36:13 AMFeb 21
to Mozzi-users
Hi,
> Say I wanted a high pass filter after the low pass filter, could I write return MonoOutput::from8Bit(hpf.next(lpf.next(fmOut)); ?
Basically yes! You might encounter distortion though, especially with a resonance of 200: because of the resonance, the filter will output more than the 8bits that you feed it. For cascading, you could use the 16bits version of the filter for the second to have a lot of headroom or tame a bit the signal before feeding it into the hpf, for instance something like: MonoOutput::from8Bit(hpf.next((lpf.next(fmOut)>>2)); A .clip() afterward might also be useful if you seek for a bit of disto.

That brings nicely to :
> what exactly does MonoOutput::from8Bit mean?
Mozzi works on a lot of different platforms and modes, all of them having different capability in terms of resolution of the output (good old AVR outputs on 8bits, Teensys 3 on 12bits, etc…). Mozzi knows that, and will scale the output to fit the resolution of the platform you are using. But for that, Mozzi needs to know how many bits you are giving, which is the goal of from8/N/16Bit: that indicates to Mozzi the number of bits of your signal. For the lowpassfilter, the way I usually do it is to use:
return MonoOutput::fromNBit(N,lpf.next(fmOut)).clip();  (note that there is a missing parenthesis in Benedikt's code, just seen that ;) ) with replacing N with 8 at first (that's exactly equivalent to from8Bits). If the signal saturates too much with my resonance settings, I increase N until I am satisfied. It should be possible to know exactly how many bits the filters are adding for any given resonance, but I never took the time to characterize them properly ;).

Hope it helps!


Le jeudi 20 février 2025 à 12:54:50 UTC+1, Jack Chapell a écrit :
Reply all
Reply to author
Forward
0 new messages