# New audio class for generating waveforms from sines

#### C0d3man

##### Well-known member
Hi,

I have created an audio class that allows to create waveforms (square, triangle, sawtooth) by addition from sine waves. I want to use the class for a synth that should not get aliasing problems in the higher frequency range. The basic idea is the FM synthesis of the Yamaha DX7, from which you can also extract "analog" waveforms by means of appropriately tuned operators.

The whole thing is based on the findings from https://lpsa.swarthmore.edu/Fourier/Series/ExFS.html. The class is designed so that you can determine which number of operators (or partials) you want to use. I did some benchmark tests with a Teensy-3.5 and a Teensy-3.6.

All this (with some collected info) can be found at https://codeberg.org/dcoredump/Synth_FM_Partial.

Maybe someone of you finds this useful or has hints for the use, optimization or what I did wrong

Have fun!

Holger

[EDIT] Forgot to say: The code is using floats, so you need a Teensy >= 3.5!

Last edited:
After thinking a bit about the name of the class, I think that yes, it is not FM. So the class and the project should rather be called Synth_Sine_Partial... hm. I'll leave it like that for now, but will rename it when I get the chance.

I would suggest using complex arithmetic to sum a Fourier series, then only one sin() and one cos() call are needed per sample (or perhaps less often). Rotation is simply multiplication in the complex domain.

The arm_sin_f32 and arm_cos_f32 library routines are only table-based approximations, I would worry are probably not spectrally pure enough to avoid audible artifacts.

I would suggest using complex arithmetic to sum a Fourier series, then only one sin() and one cos() call are needed per sample (or perhaps less often). Rotation is simply multiplication in the complex domain.

I had to search deep in my brain again to recapitulate the complex math and made some changes that now make the base class much more independent of the function that is to be emulated. I still have to test the whole thing to see if I didn't make any mistakes somewhere.

The arm_sin_f32 and arm_cos_f32 library routines are only table-based approximations, I would worry are probably not spectrally pure enough to avoid audible artifacts.

Yes, I had read and hoped that the speed increase is higher than the error that can occur. I have to check it again. Now I have first again the "normal" functions used and try then with it first.

I have now rebuilt the classes based on your hints. The whole thing seems to work quite well now. However, the CPU usage is now twice as high as before, but the advantage is that you can create any waveform, as long as you can describe it in a function.

I see your files have GPLv3 license. That's fine, but they can never be merged with the original library which uses MIT license.

Any chance you might consider using the same MIT license as the rest of the library? Then this could be included in a future version.

Hi Paul,

I see your files have GPLv3 license. That's fine, but they can never be merged with the original library which uses MIT license.

Any chance you might consider using the same MIT license as the rest of the library? Then this could be included in a future version.

I have created a simple demo video (with audio) for all the waveforms: 20% square, 50% square, triangle, sawtooth - every waveform from 1 (only a sine wave) to 20 partials.

Be careful with the audio level!!!

Looks good!

Holger, thanks for putting this together. Good thinking material. But, I don't see why you can't just generate, for instance, a triangular waveform and then run this through a linear-phase LP FIR filter. All components below the cut-off would align properly since the delay in the FIR is constant with frequencies. Those above the cutoff could be reduced arbitrarily low. The end result would seem to be the same, but less compute. I bet I am missing something?? Bob

Hi Bob,