electro-smith / DaisySP

A Powerful DSP Library in C++
https://www.electro-smith.com/daisy
Other
882 stars 139 forks source link

Add basic Wavefolder module #175

Closed ndonald2 closed 2 years ago

ndonald2 commented 2 years ago

Summary

Adds a very simple and basic Wavefolder class/module for growly wavefolding goodness!

Details

This is a dead simple wavefolder based on original code by me. It's implementing this function where k represents the gain and a is the offset.

It's not anti-aliased so you will get aliasing at higher harmonics, especially at high gain levels and for higher input frequencies. But I still think it sounds pretty rad.

Examples

Be sure to un-mute πŸ”Š the video players

Slow gain sweep on a triangle wave

https://user-images.githubusercontent.com/1433497/183200947-663945ad-044e-4366-82f3-706a5777502b.mp4


Audio rate thru-zero modulated folding

Gain parameter modulated at audio rate by an oscillator one octave below the input signal, modulated by an LFO

https://user-images.githubusercontent.com/1433497/183202624-e4437cc5-ae23-401d-bfa5-f9b7ed0dc5f2.mp4


Example Usage

This the source from the first video example above

#include "daisy_seed.h"
#include "daisysp.h"

using namespace daisy;
using namespace daisysp;

DaisySeed hw;
Oscillator osc, lfo;
Wavefolder wf;

void AudioCallback(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size)
{
    float mod;
    for (size_t i = 0; i < size; i++)
    {
        // Sweep the folder input gain from 0.5 to 20.0
        mod = (lfo.Process() + 1.0f) * 0.5f;
        wf.SetGain(0.5f + mod * 19.5f);
        out[0][i] = out[1][i] = wf.Process(osc.Process()) * 0.5f;
    }
}

int main(void)
{
    hw.Init();
    hw.SetAudioBlockSize(4); // number of samples handled per callback
    hw.SetAudioSampleRate(SaiHandle::Config::SampleRate::SAI_48KHZ);

    osc.Init(hw.AudioSampleRate());
    osc.SetAmp(1.0f);
    osc.SetFreq(110.0f);
    osc.SetWaveform(Oscillator::WAVE_POLYBLEP_TRI);

    lfo.Init(hw.AudioSampleRate());
    lfo.SetAmp(1.0f);
    lfo.SetWaveform(Oscillator::WAVE_TRI);
    lfo.SetFreq(0.1f);

    wf.Init();

    hw.StartAudio(AudioCallback);
    while(1) {}
}
stephenhensley commented 2 years ago

@ndonald2 This is a fantastic PR! πŸš€

Thanks for the contribution, and for the excellent audio/video demoes along with the example.

Everything looks good at first glance. We'll get it merged in sometime in the next few days!

ndonald2 commented 2 years ago

Hi @stephenhensley, I'm sure you're quite busy so no rush at all, but wondering if you thought this might get merged soon-ish? Or any feedback to make sure it's merge-able? Thanks!

stephenhensley commented 2 years ago

@ndonald2 sorry for the delay!

I think this is good to merge!

Some sort of eventual-addition might include a threshold of some-sort, separate from the gain that would control the overall amplitude once folding starts to occur. However, this is totally doable externally with a few multiplies by the user, and would otherwise, and definitely isn't always needed or useful.

stephenhensley commented 2 years ago

Thanks again for the awesome contribution!