Added DaisySP

This commit is contained in:
2026-04-24 14:46:05 +02:00
parent 82190216c3
commit dd63b3aed4
96 changed files with 10613 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
#include "autowah.h"
#include <math.h>
using namespace daisysp;
void Autowah::Init(float sample_rate)
{
sampling_freq_ = sample_rate;
const1_ = 1413.72f / sampling_freq_;
const2_ = expf(0.0f - (100.0f / sampling_freq_));
const4_ = expf(0.0f - (10.0f / sampling_freq_));
wet_dry_ = 100.0f;
level_ = 0.1f;
wah_ = 0.0;
for(int i = 0; i < 2; i++)
{
rec1_[i] = rec2_[i] = rec3_[i] = rec4_[i] = rec5_[i] = 0.0f;
}
for(int i = 0; i < 3; i++)
{
rec0_[i] = 0.0f;
}
}
float Autowah::Process(float in)
{
float out;
float fSlow2 = (0.01f * (wet_dry_ * level_));
float fSlow3 = (1.0f - 0.01f * wet_dry_) + (1.f - wah_);
float fTemp1 = fabs(in);
rec3_[0]
= fmaxf(fTemp1, (const4_ * rec3_[1]) + ((1.0f - const4_) * fTemp1));
rec2_[0] = (const2_ * rec2_[1]) + ((1.0f - const2_) * rec3_[0]);
float fTemp2 = fminf(1.0f, rec2_[0]);
float fTemp3 = powf(2.0f, (2.3f * fTemp2));
float fTemp4
= 1.0f
- (const1_ * fTemp3 / powf(2.0f, (1.0f + 2.0f * (1.0f - fTemp2))));
rec1_[0]
= ((0.999f * rec1_[1])
+ (0.001f
* (0.0f - (2.0f * (fTemp4 * cosf((const1_ * 2 * fTemp3)))))));
rec4_[0] = ((0.999f * rec4_[1]) + (0.001f * fTemp4 * fTemp4));
rec5_[0] = ((0.999f * rec5_[1]) + (0.0001f * powf(4.0f, fTemp2)));
rec0_[0] = (0.0f
- (((rec1_[0] * rec0_[1]) + (rec4_[0] * rec0_[2]))
- (fSlow2 * (rec5_[0] * in))));
out = ((wah_ * (rec0_[0] - rec0_[1])) + (fSlow3 * in));
rec3_[1] = rec3_[0];
rec2_[1] = rec2_[0];
rec1_[1] = rec1_[0];
rec4_[1] = rec4_[0];
rec5_[1] = rec5_[0];
rec0_[2] = rec0_[1];
rec0_[1] = rec0_[0];
return out;
}
+60
View File
@@ -0,0 +1,60 @@
/*
Copyright (c) 2020 Electrosmith, Corp, Paul Batchelor
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
*/
#pragma once
#ifndef DSY_AUTOWAH_H
#define DSY_AUTOWAH_H
#include <stdint.h>
#ifdef __cplusplus
namespace daisysp
{
/** Autowah module
Original author(s) :
Ported from soundpipe by Ben Sergentanis, May 2020
*/
class Autowah
{
public:
Autowah() {}
~Autowah() {}
/** Initializes the Autowah module.
\param sample_rate - The sample rate of the audio engine being run.
*/
void Init(float sample_rate);
/** Initializes the Autowah module.
\param in - input signal to be wah'd
*/
float Process(float in);
/** sets wah
\param wah : set wah amount, , 0...1.0
*/
inline void SetWah(float wah) { wah_ = wah; }
/** sets mix amount
\param drywet : set effect dry/wet, 0...100.0
*/
inline void SetDryWet(float drywet) { wet_dry_ = drywet; }
/** sets wah level
\param level : set wah level, 0...1.0
*/
inline void SetLevel(float level) { level_ = level; }
private:
float sampling_freq_, const1_, const2_, const4_, wah_, level_, wet_dry_,
rec0_[3], rec1_[2], rec2_[2], rec3_[2], rec4_[2], rec5_[2];
};
} // namespace daisysp
#endif
#endif
+187
View File
@@ -0,0 +1,187 @@
#include "dsp.h"
#include "chorus.h"
#include <math.h>
using namespace daisysp;
//ChorusEngine stuff
void ChorusEngine::Init(float sample_rate)
{
sample_rate_ = sample_rate;
del_.Init();
lfo_amp_ = 0.f;
feedback_ = .2f;
SetDelay(.75);
lfo_phase_ = 0.f;
SetLfoFreq(.3f);
SetLfoDepth(.9f);
}
float ChorusEngine::Process(float in)
{
float lfo_sig = ProcessLfo();
del_.SetDelay(lfo_sig + delay_);
float out = del_.Read();
del_.Write(in + out * feedback_);
return (in + out) * .5f; //equal mix
}
void ChorusEngine::SetLfoDepth(float depth)
{
depth = fclamp(depth, 0.f, .93f);
lfo_amp_ = depth * delay_;
}
void ChorusEngine::SetLfoFreq(float freq)
{
freq = 4.f * freq / sample_rate_;
freq *= lfo_freq_ < 0.f ? -1.f : 1.f; //if we're headed down, keep going
lfo_freq_ = fclamp(freq, -.25f, .25f); //clip at +/- .125 * sr
}
void ChorusEngine::SetDelay(float delay)
{
delay = (.1f + delay * 7.9f); //.1 to 8 ms
SetDelayMs(delay);
}
void ChorusEngine::SetDelayMs(float ms)
{
ms = fmax(.1f, ms);
delay_ = ms * .001f * sample_rate_; //ms to samples
lfo_amp_ = fmin(lfo_amp_, delay_); //clip this if needed
}
void ChorusEngine::SetFeedback(float feedback)
{
feedback_ = fclamp(feedback, 0.f, 1.f);
}
float ChorusEngine::ProcessLfo()
{
lfo_phase_ += lfo_freq_;
//wrap around and flip direction
if(lfo_phase_ > 1.f)
{
lfo_phase_ = 1.f - (lfo_phase_ - 1.f);
lfo_freq_ *= -1.f;
}
else if(lfo_phase_ < -1.f)
{
lfo_phase_ = -1.f - (lfo_phase_ + 1.f);
lfo_freq_ *= -1.f;
}
return lfo_phase_ * lfo_amp_;
}
//Chorus Stuff
void Chorus::Init(float sample_rate)
{
engines_[0].Init(sample_rate);
engines_[1].Init(sample_rate);
SetPan(.25f, .75f);
gain_frac_ = .5f;
sigl_ = sigr_ = 0.f;
}
float Chorus::Process(float in)
{
sigl_ = 0.f;
sigr_ = 0.f;
for(int i = 0; i < 2; i++)
{
float sig = engines_[i].Process(in);
sigl_ += (1.f - pan_[i]) * sig;
sigr_ += pan_[i] * sig;
}
sigl_ *= gain_frac_;
sigr_ *= gain_frac_;
return sigl_;
}
float Chorus::GetLeft()
{
return sigl_;
}
float Chorus::GetRight()
{
return sigr_;
}
void Chorus::SetPan(float panl, float panr)
{
pan_[0] = fclamp(panl, 0.f, 1.f);
pan_[1] = fclamp(panr, 0.f, 1.f);
}
void Chorus::SetPan(float pan)
{
SetPan(pan, pan);
}
void Chorus::SetLfoDepth(float depthl, float depthr)
{
engines_[0].SetLfoDepth(depthl);
engines_[1].SetLfoDepth(depthr);
}
void Chorus::SetLfoDepth(float depth)
{
SetLfoDepth(depth, depth);
}
void Chorus::SetLfoFreq(float freql, float freqr)
{
engines_[0].SetLfoFreq(freql);
engines_[1].SetLfoFreq(freqr);
}
void Chorus::SetLfoFreq(float freq)
{
SetLfoFreq(freq, freq);
}
void Chorus::SetDelay(float delayl, float delayr)
{
engines_[0].SetDelay(delayl);
engines_[1].SetDelay(delayr);
}
void Chorus::SetDelay(float delay)
{
SetDelay(delay, delay);
}
void Chorus::SetDelayMs(float msl, float msr)
{
engines_[0].SetDelayMs(msl);
engines_[1].SetDelayMs(msr);
}
void Chorus::SetDelayMs(float ms)
{
SetDelayMs(ms, ms);
}
void Chorus::SetFeedback(float feedbackl, float feedbackr)
{
engines_[0].SetFeedback(feedbackl);
engines_[1].SetFeedback(feedbackr);
}
void Chorus::SetFeedback(float feedback)
{
SetFeedback(feedback, feedback);
}
+190
View File
@@ -0,0 +1,190 @@
/*
Copyright (c) 2020 Electrosmith, Corp
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
*/
#pragma once
#ifndef DSY_CHORUS_H
#define DSY_CHORUS_H
#ifdef __cplusplus
#include <stdint.h>
#include "Utility/delayline.h"
/** @file chorus.h */
namespace daisysp
{
/**
@brief Single Chorus engine. Used in Chorus.
@author Ben Sergentanis
*/
class ChorusEngine
{
public:
ChorusEngine() {}
~ChorusEngine() {}
/** Initialize the module
\param sample_rate Audio engine sample rate.
*/
void Init(float sample_rate);
/** Get the next sample
\param in Sample to process
*/
float Process(float in);
/** How much to modulate the delay by.
\param depth Works 0-1.
*/
void SetLfoDepth(float depth);
/** Set lfo frequency.
\param freq Frequency in Hz
*/
void SetLfoFreq(float freq);
/** Set the internal delay rate.
\param delay Tuned for 0-1. Maps to .1 to 50 ms.
*/
void SetDelay(float delay);
/** Set the delay time in ms.
\param ms Delay time in ms, 0 to 50 ms.
*/
void SetDelayMs(float ms);
/** Set the feedback amount.
\param feedback Amount from 0-1.
*/
void SetFeedback(float feedback);
private:
float sample_rate_;
static constexpr int32_t kDelayLength
= 2400; // 50 ms at 48kHz = .05 * 48000
//triangle lfos
float lfo_phase_;
float lfo_freq_;
float lfo_amp_;
float feedback_;
float delay_;
DelayLine<float, kDelayLength> del_;
float ProcessLfo();
};
//wraps up all of the chorus engines
/**
@brief Chorus Effect.
@author Ben Sergentanis
@date Jan 2021
Based on https://www.izotope.com/en/learn/understanding-chorus-flangers-and-phasers-in-audio-production.html \n
and https://www.researchgate.net/publication/236629475_Implementing_Professional_Audio_Effects_with_DSPs \n
*/
class Chorus
{
public:
Chorus() {}
~Chorus() {}
/** Initialize the module
\param sample_rate Audio engine sample rate
*/
void Init(float sample_rate);
/** Get the net floating point sample. Defaults to left channel.
\param in Sample to process
*/
float Process(float in);
/** Get the left channel's last sample */
float GetLeft();
/** Get the right channel's last sample */
float GetRight();
/** Pan both channels individually.
\param panl Pan the left channel. 0 is left, 1 is right.
\param panr Pan the right channel.
*/
void SetPan(float panl, float panr);
/** Pan both channels.
\param pan Where to pan both channels to. 0 is left, 1 is right.
*/
void SetPan(float pan);
/** Set both lfo depths individually.
\param depthl Left channel lfo depth. Works 0-1.
\param depthr Right channel lfo depth.
*/
void SetLfoDepth(float depthl, float depthr);
/** Set both lfo depths.
\param depth Both channels lfo depth. Works 0-1.
*/
void SetLfoDepth(float depth);
/** Set both lfo frequencies individually.
\param depthl Left channel lfo freq in Hz.
\param depthr Right channel lfo freq in Hz.
*/
void SetLfoFreq(float freql, float freqr);
/** Set both lfo frequencies.
\param depth Both channel lfo freqs in Hz.
*/
void SetLfoFreq(float freq);
/** Set both channel delay amounts individually.
\param delayl Left channel delay amount. Works 0-1.
\param delayr Right channel delay amount.
*/
void SetDelay(float delayl, float delayr);
/** Set both channel delay amounts.
\param delay Both channel delay amount. Works 0-1.
*/
void SetDelay(float delay);
/** Set both channel delay individually.
\param msl Left channel delay in ms.
\param msr Right channel delay in ms.
*/
void SetDelayMs(float msl, float msr);
/** Set both channel delay in ms.
\param ms Both channel delay amounts in ms.
*/
void SetDelayMs(float ms);
/** Set both channels feedback individually.
\param feedbackl Left channel feedback. Works 0-1.
\param feedbackr Right channel feedback.
*/
void SetFeedback(float feedbackl, float feedbackr);
/** Set both channels feedback.
\param feedback Both channel feedback. Works 0-1.
*/
void SetFeedback(float feedback);
private:
ChorusEngine engines_[2];
float gain_frac_;
float pan_[2];
float sigl_, sigr_;
};
} //namespace daisysp
#endif
#endif
+46
View File
@@ -0,0 +1,46 @@
#include "decimator.h"
using namespace daisysp;
void Decimator::Init()
{
downsample_factor_ = 1.0f;
bitcrush_factor_ = 0.0f;
downsampled_ = 0.0f;
bitcrushed_ = 0.0f;
inc_ = 0;
threshold_ = 0;
smooth_crushing_ = false;
bit_overflow_ = 1.0f;
}
float Decimator::Process(float input)
{
int32_t temp;
//downsample
threshold_ = (uint32_t)((downsample_factor_ * downsample_factor_) * 96.0f);
inc_ += 1;
if(inc_ > threshold_)
{
inc_ = 0;
downsampled_ = input;
}
//bitcrush
if(smooth_crushing_)
{
temp = (int32_t)(downsampled_ * 65536.0f * bit_overflow_);
temp >>= bits_to_crush_ + 1; // shift off
temp <<= bits_to_crush_ + 1; // move back with zeros
bitcrushed_ = (float)temp / (65536.0f * bit_overflow_);
}
else
{
temp = (int32_t)(downsampled_ * 65536.0f);
temp >>= bits_to_crush_; // shift off
temp <<= bits_to_crush_; // move back with zeros
bitcrushed_ = (float)temp / 65536.0f;
}
return bitcrushed_;
}
+94
View File
@@ -0,0 +1,94 @@
/*
Copyright (c) 2020 Electrosmith, Corp
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
*/
#pragma once
#ifndef DECIMATOR_H
#define DECIMATOR_H
#include <stdint.h>
#ifdef __cplusplus
namespace daisysp
{
/** Performs downsampling and bitcrush effects
*/
class Decimator
{
public:
Decimator() {}
~Decimator() {}
/** Initializes downsample module
*/
void Init();
/** Applies downsample and bitcrush effects to input signal.
\return one sample. This should be called once per sample period.
*/
float Process(float input);
/** Sets amount of downsample
Input range:
*/
inline void SetDownsampleFactor(float downsample_factor)
{
downsample_factor_ = downsample_factor;
}
/** Sets amount of bitcrushing
Input range: 0...1.0
*/
inline void SetBitcrushFactor(float bitcrush_factor)
{
bitcrush_factor_ = bitcrush_factor;
bits_to_crush_ = (uint32_t)(bitcrush_factor * kMaxBitsToCrush);
bit_overflow_
= 2.0f - (bitcrush_factor * 16.0f) + (float)(bits_to_crush_);
}
/** Sets the exact number of bits to crush and disables smooth crushing
0-16 bits
*/
inline void SetBitsToCrush(const uint8_t &bits)
{
bits_to_crush_ = bits <= kMaxBitsToCrush ? bits : kMaxBitsToCrush;
smooth_crushing_ = false;
}
/** Sets the smooth crushing on or off
true/false
*/
inline void SetSmoothCrushing(bool smooth_crushing)
{
smooth_crushing_ = smooth_crushing;
}
/** Returns current setting of smooth crushing
*/
inline bool GetSmoothCrushing() { return smooth_crushing_; }
/** Returns current setting of downsample
*/
inline float GetDownsampleFactor() { return downsample_factor_; }
/** Returns current setting of bitcrush
*/
inline float GetBitcrushFactor() { return bitcrush_factor_; }
/** Returns current bitcrush setting in bits
*/
inline int GetBitsToCrush() { return bits_to_crush_; }
private:
const uint8_t kMaxBitsToCrush = 16;
float downsample_factor_, bitcrush_factor_;
uint32_t bits_to_crush_;
float downsampled_, bitcrushed_;
uint32_t inc_, threshold_;
bool smooth_crushing_;
float bit_overflow_;
};
} // namespace daisysp
#endif
#endif
+83
View File
@@ -0,0 +1,83 @@
#include "dsp.h"
#include "flanger.h"
#include <math.h>
using namespace daisysp;
void Flanger::Init(float sample_rate)
{
sample_rate_ = sample_rate;
SetFeedback(.2f);
del_.Init();
lfo_amp_ = 0.f;
SetDelay(.75);
lfo_phase_ = 0.f;
SetLfoFreq(.3);
SetLfoDepth(.9);
}
float Flanger::Process(float in)
{
float lfo_sig = ProcessLfo();
del_.SetDelay(1.f + lfo_sig + delay_);
float out = del_.Read();
del_.Write(in + out * feedback_);
return (in + out) * .5f; //equal mix
}
void Flanger::SetFeedback(float feedback)
{
feedback_ = fclamp(feedback, 0.f, 1.f);
feedback_ *= .97f;
}
void Flanger::SetLfoDepth(float depth)
{
depth = fclamp(depth, 0.f, .93f);
lfo_amp_ = depth * delay_;
}
void Flanger::SetLfoFreq(float freq)
{
freq = 4.f * freq / sample_rate_;
freq *= lfo_freq_ < 0.f ? -1.f : 1.f; //if we're headed down, keep going
lfo_freq_ = fclamp(freq, -.25f, .25f); //clip at +/- .125 * sr
}
void Flanger::SetDelay(float delay)
{
delay = (.1f + delay * 6.9); //.1 to 7 ms
SetDelayMs(delay);
}
void Flanger::SetDelayMs(float ms)
{
ms = fmax(.1, ms);
delay_ = ms * .001f * sample_rate_; //ms to samples
lfo_amp_ = fmin(lfo_amp_, delay_); //clip this if needed
}
float Flanger::ProcessLfo()
{
lfo_phase_ += lfo_freq_;
//wrap around and flip direction
if(lfo_phase_ > 1.f)
{
lfo_phase_ = 1.f - (lfo_phase_ - 1.f);
lfo_freq_ *= -1.f;
}
else if(lfo_phase_ < -1.f)
{
lfo_phase_ = -1.f - (lfo_phase_ + 1.f);
lfo_freq_ *= -1.f;
}
return lfo_phase_ * lfo_amp_;
}
+83
View File
@@ -0,0 +1,83 @@
/*
Copyright (c) 2020 Electrosmith, Corp
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
*/
#pragma once
#ifndef DSY_FLANGER_H
#define DSY_FLANGER_H
#ifdef __cplusplus
#include <stdint.h>
#include "Utility/delayline.h"
/** @file flanger.h */
namespace daisysp
{
/** @brief Flanging Audio Effect
*
* Generates a modulating phase shifted copy of a signal, and recombines
* with the original to create a 'flanging' sound effect.
*/
class Flanger
{
public:
/** Initialize the modules
\param sample_rate Audio engine sample rate.
*/
void Init(float sample_rate);
/** Get the next sample
\param in Sample to process
*/
float Process(float in);
/** How much of the signal to feedback into the delay line.
\param feedback Works 0-1.
*/
void SetFeedback(float feedback);
/** How much to modulate the delay by.
\param depth Works 0-1.
*/
void SetLfoDepth(float depth);
/** Set lfo frequency.
\param freq Frequency in Hz
*/
void SetLfoFreq(float freq);
/** Set the internal delay rate.
\param delay Tuned for 0-1. Maps to .1 to 7 ms.
*/
void SetDelay(float delay);
/** Set the delay time in ms.
\param ms Delay time in ms, .1 to 7 ms.
*/
void SetDelayMs(float ms);
private:
float sample_rate_;
static constexpr int32_t kDelayLength = 960; // 20 ms at 48kHz = .02 * 48000
float feedback_;
//triangle lfos
float lfo_phase_;
float lfo_freq_;
float lfo_amp_;
float delay_;
DelayLine<float, kDelayLength> del_;
float ProcessLfo();
};
} //namespace daisysp
#endif
#endif
+32
View File
@@ -0,0 +1,32 @@
#include "dsp.h"
#include "overdrive.h"
#include <algorithm>
namespace daisysp
{
void Overdrive::Init()
{
SetDrive(.5f);
}
float Overdrive::Process(float in)
{
float pre = pre_gain_ * in;
return SoftClip(pre) * post_gain_;
}
void Overdrive::SetDrive(float drive)
{
drive = fclamp(drive, 0.f, 1.f);
drive_ = 2.f * drive;
const float drive_2 = drive_ * drive_;
const float pre_gain_a = drive_ * 0.5f;
const float pre_gain_b = drive_2 * drive_2 * drive_ * 24.0f;
pre_gain_ = pre_gain_a + (pre_gain_b - pre_gain_a) * drive_2;
const float drive_squashed = drive_ * (2.0f - drive_);
post_gain_ = 1.0f / SoftClip(0.33f + drive_squashed * (pre_gain_ - 0.33f));
}
} // namespace daisysp
+54
View File
@@ -0,0 +1,54 @@
/*
Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
*/
#pragma once
#ifndef DSY_OVERDRIVE_H
#define DSY_OVERDRIVE_H
#include <stdint.h>
#ifdef __cplusplus
/** @file overdrive.h */
namespace daisysp
{
/**
@brief Distortion / Overdrive Module
@author Ported by Ben Sergentanis
@date Jan 2021
Ported from pichenettes/eurorack/plaits/dsp/fx/overdrive.h \n
to an independent module. \n
Original code written by Emilie Gillet in 2014. \n
*/
class Overdrive
{
public:
Overdrive() {}
~Overdrive() {}
/** Initializes the module with 0 gain */
void Init();
/** Get the next sample
\param in Input to be overdriven
*/
float Process(float in);
/** Set the amount of drive
\param drive Works from 0-1
*/
void SetDrive(float drive);
private:
float drive_;
float pre_gain_;
float post_gain_;
};
} // namespace daisysp
#endif
#endif
+138
View File
@@ -0,0 +1,138 @@
#include "dsp.h"
#include "phaser.h"
#include <math.h>
using namespace daisysp;
//PhaserEngine stuff
void PhaserEngine::Init(float sample_rate)
{
sample_rate_ = sample_rate;
del_.Init();
lfo_amp_ = 0.f;
feedback_ = .2f;
SetFreq(200.f);
del_.SetDelay(0.f);
os_ = 30.f; //30 hertz frequency offset, lower than this introduces crunch
deltime_ = 0.f;
last_sample_ = 0.f;
lfo_phase_ = 0.f;
SetLfoFreq(.3);
SetLfoDepth(.9);
}
float PhaserEngine::Process(float in)
{
float lfo_sig = ProcessLfo();
fonepole(deltime_, sample_rate_ / (lfo_sig + ap_freq_ + os_), .0001f);
last_sample_ = del_.Allpass(in + feedback_ * last_sample_, deltime_, .3f);
return (in + last_sample_) * .5f; //equal mix
}
void PhaserEngine::SetLfoDepth(float depth)
{
lfo_amp_ = fclamp(depth, 0.f, 1.f);
}
void PhaserEngine::SetLfoFreq(float lfo_freq)
{
lfo_freq = 4.f * lfo_freq / sample_rate_;
lfo_freq *= lfo_freq_ < 0.f ? -1.f : 1.f; //if we're headed down, keep going
lfo_freq_ = fclamp(lfo_freq, -.25f, .25f); //clip at +/- .125 * sr
}
void PhaserEngine::SetFreq(float ap_freq)
{
ap_freq_ = fclamp(ap_freq, 0.f, 20000.f); //0 - 20kHz
}
void PhaserEngine::SetFeedback(float feedback)
{
feedback_ = fclamp(feedback, 0.f, .75f);
}
float PhaserEngine::ProcessLfo()
{
lfo_phase_ += lfo_freq_;
//wrap around and flip direction
if(lfo_phase_ > 1.f)
{
lfo_phase_ = 1.f - (lfo_phase_ - 1.f);
lfo_freq_ *= -1.f;
}
else if(lfo_phase_ < -1.f)
{
lfo_phase_ = -1.f - (lfo_phase_ + 1.f);
lfo_freq_ *= -1.f;
}
return lfo_phase_ * lfo_amp_ * ap_freq_;
}
//Phaser Stuff
void Phaser::Init(float sample_rate)
{
for(size_t i = 0; i < kMaxPoles; i++)
{
engines_[i].Init(sample_rate);
}
poles_ = 4;
gain_frac_ = .5f;
}
float Phaser::Process(float in)
{
float sig = 0.f;
for(int i = 0; i < poles_; i++)
{
sig += engines_[i].Process(in);
}
return sig;
}
void Phaser::SetPoles(int poles)
{
poles_ = DSY_CLAMP(poles, 1, 8);
}
void Phaser::SetLfoDepth(float depth)
{
for(int i = 0; i < kMaxPoles; i++)
{
engines_[i].SetLfoDepth(depth);
}
}
void Phaser::SetLfoFreq(float lfo_freq)
{
for(int i = 0; i < kMaxPoles; i++)
{
engines_[i].SetLfoFreq(lfo_freq);
}
}
void Phaser::SetFreq(float ap_freq)
{
for(int i = 0; i < kMaxPoles; i++)
{
engines_[i].SetFreq(ap_freq);
}
}
void Phaser::SetFeedback(float feedback)
{
for(int i = 0; i < kMaxPoles; i++)
{
engines_[i].SetFeedback(feedback);
}
}
+139
View File
@@ -0,0 +1,139 @@
/*
Copyright (c) 2020 Electrosmith, Corp
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
*/
#pragma once
#ifndef DSY_PHASER_H
#define DSY_PHASER_H
#ifdef __cplusplus
#include <stdint.h>
#include "Utility/delayline.h"
/** @file phaser.h */
namespace daisysp
{
/**
@brief Single Phaser engine. Used in Phaser.
@author Ben Sergentanis
*/
class PhaserEngine
{
public:
PhaserEngine() {}
~PhaserEngine() {}
/** Initialize the module
\param sample_rate Audio engine sample rate.
*/
void Init(float sample_rate);
/** Get the next sample
\param in Sample to process
*/
float Process(float in);
/** How much to modulate the allpass filter by.
\param depth Works 0-1.
*/
void SetLfoDepth(float depth);
/** Set lfo frequency.
\param lfo_freq Frequency in Hz
*/
void SetLfoFreq(float lfo_freq);
/** Set the allpass frequency
\param ap_freq Frequency in Hz.
*/
void SetFreq(float ap_freq);
/** Set the feedback amount.
\param feedback Amount from 0-1.
*/
void SetFeedback(float feedback);
private:
float sample_rate_;
static constexpr int32_t kDelayLength
= 2400; // 50 ms at 48kHz = .05 * 48000
//triangle lfo
float lfo_phase_;
float lfo_freq_;
float lfo_amp_;
float os_;
float feedback_;
float ap_freq_;
float deltime_;
float last_sample_;
DelayLine<float, kDelayLength> del_;
float ProcessLfo();
};
//wraps up all of the phaser engines
/**
@brief Phaser Effect.
@author Ben Sergentanis
@date Jan 2021
*/
class Phaser
{
public:
Phaser() {}
~Phaser() {}
/** Initialize the module
\param sample_rate Audio engine sample rate
*/
void Init(float sample_rate);
/** Get the next floating point sample.
\param in Sample to process
*/
float Process(float in);
/** Number of allpass stages.
\param poles Works 1 to 8.
*/
void SetPoles(int poles);
/** Set all lfo depths
\param depth Works 0-1.
*/
void SetLfoDepth(float depth);
/** Set all lfo frequencies.
\param lfo_freq Lfo freq in Hz.
*/
void SetLfoFreq(float lfo_freq);
/** Set all channel allpass freq in Hz.
\param ap_freq Frequency in Hz.
*/
void SetFreq(float ap_freq);
/** Set all channels feedback.
\param feedback Works 0-1.
*/
void SetFeedback(float feedback);
private:
static constexpr int kMaxPoles = 8;
PhaserEngine engines_[kMaxPoles];
float gain_frac_;
int poles_;
};
} //namespace daisysp
#endif
#endif
+219
View File
@@ -0,0 +1,219 @@
/*
Copyright (c) 2020 Electrosmith, Corp
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
*/
#pragma once
#ifndef DSY_PITCHSHIFTER_H
#define DSY_PITCHSHIFTER_H
#include <stdint.h>
#include <cmath>
#ifdef USE_ARM_DSP
#include "arm_math.h"
#endif
#include "Utility/dsp.h"
#include "Utility/delayline.h"
#include "Control/phasor.h"
/** Shift can be 30-100 ms lets just start with 50 for now.
0.050 * SR = 2400 samples (at 48kHz)
*/
#define SHIFT_BUFFER_SIZE 16384
//#define SHIFT_BUFFER_SIZE 4800
//#define SHIFT_BUFFER_SIZE 8192
//#define SHIFT_BUFFER_SIZE 1024
namespace daisysp
{
static inline uint32_t hash_xs32(uint32_t x)
{
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return x;
}
inline uint32_t myrand()
{
static uint32_t seed = 1;
seed = hash_xs32(seed);
return seed;
}
/** time-domain pitchshifter
Author: shensley
Based on "Pitch Shifting" from ucsd.edu
t = 1 - ((s *f) / R)
where:
s is the size of the delay
f is the frequency of the lfo
r is the sample_rate
solving for t = 12.0
f = (12 - 1) * 48000 / SHIFT_BUFFER_SIZE;
\todo - move hash_xs32 and myrand to dsp.h and give appropriate names
*/
class PitchShifter
{
public:
PitchShifter() {}
~PitchShifter() {}
/** Initialize pitch shifter
*/
void Init(float sr)
{
force_recalc_ = false;
sr_ = sr;
mod_freq_ = 5.0f;
SetSemitones();
for(uint8_t i = 0; i < 2; i++)
{
gain_[i] = 0.0f;
d_[i].Init();
phs_[i].Init(sr, 50, i == 0 ? 0 : PI_F);
}
shift_up_ = true;
del_size_ = SHIFT_BUFFER_SIZE;
SetDelSize(del_size_);
fun_ = 0.0f;
}
/** process pitch shifter
*/
float Process(float &in)
{
float val, fade1, fade2;
// First Process delay mod/crossfade
fade1 = phs_[0].Process();
fade2 = phs_[1].Process();
if(prev_phs_a_ > fade1)
{
mod_a_amt_ = fun_ * ((float)(myrand() % 255) / 255.0f)
* (del_size_ * 0.5f);
mod_coeff_[0]
= 0.0002f + (((float)(myrand() % 255) / 255.0f) * 0.001f);
}
if(prev_phs_b_ > fade2)
{
mod_b_amt_ = fun_ * ((float)(myrand() % 255) / 255.0f)
* (del_size_ * 0.5f);
mod_coeff_[1]
= 0.0002f + (((float)(myrand() % 255) / 255.0f) * 0.001f);
}
slewed_mod_[0] += mod_coeff_[0] * (mod_a_amt_ - slewed_mod_[0]);
slewed_mod_[1] += mod_coeff_[1] * (mod_b_amt_ - slewed_mod_[1]);
prev_phs_a_ = fade1;
prev_phs_b_ = fade2;
if(shift_up_)
{
fade1 = 1.0f - fade1;
fade2 = 1.0f - fade2;
}
mod_[0] = fade1 * (del_size_ - 1);
mod_[1] = fade2 * (del_size_ - 1);
#ifdef USE_ARM_DSP
gain_[0] = arm_sin_f32(fade1 * (float)M_PI);
gain_[1] = arm_sin_f32(fade2 * (float)M_PI);
#else
gain_[0] = sinf(fade1 * PI_F);
gain_[1] = sinf(fade2 * PI_F);
#endif
// Handle Delay Writing
d_[0].Write(in);
d_[1].Write(in);
// Modulate Delay Lines
//mod_a_amt = mod_b_amt = 0.0f;
d_[0].SetDelay(mod_[0] + mod_a_amt_);
d_[1].SetDelay(mod_[1] + mod_b_amt_);
d_[0].SetDelay(mod_[0] + slewed_mod_[0]);
d_[1].SetDelay(mod_[1] + slewed_mod_[1]);
val = 0.0f;
val += (d_[0].Read() * gain_[0]);
val += (d_[1].Read() * gain_[1]);
return val;
}
/** sets transposition in semitones
*/
void SetTransposition(const float &transpose)
{
float ratio;
uint8_t idx;
if(transpose_ != transpose || force_recalc_)
{
transpose_ = transpose;
idx = (uint8_t)fabsf(transpose);
ratio = semitone_ratios_[idx % 12];
ratio *= (uint8_t)(fabsf(transpose) / 12) + 1;
if(transpose > 0.0f)
{
shift_up_ = true;
}
else
{
shift_up_ = false;
}
mod_freq_ = ((ratio - 1.0f) * sr_) / del_size_;
if(mod_freq_ < 0.0f)
{
mod_freq_ = 0.0f;
}
phs_[0].SetFreq(mod_freq_);
phs_[1].SetFreq(mod_freq_);
if(force_recalc_)
{
force_recalc_ = false;
}
}
}
/** sets delay size changing the timbre of the pitchshifting
*/
void SetDelSize(uint32_t size)
{
del_size_ = size < SHIFT_BUFFER_SIZE ? size : SHIFT_BUFFER_SIZE;
force_recalc_ = true;
SetTransposition(transpose_);
}
/** sets an amount of internal random modulation, kind of sounds like tape-flutter
*/
inline void SetFun(float f) { fun_ = f; }
private:
inline void SetSemitones()
{
for(size_t i = 0; i < 12; i++)
{
semitone_ratios_[i] = powf(2.0f, (float)i / 12);
}
}
typedef DelayLine<float, SHIFT_BUFFER_SIZE> ShiftDelay;
ShiftDelay d_[2];
float pitch_shift_, mod_freq_;
uint32_t del_size_;
/** lfo stuff
*/
bool force_recalc_;
float sr_;
bool shift_up_;
Phasor phs_[2];
float gain_[2], mod_[2], transpose_;
float fun_, mod_a_amt_, mod_b_amt_, prev_phs_a_, prev_phs_b_;
float slewed_mod_[2], mod_coeff_[2];
/** pitch stuff
*/
float semitone_ratios_[12];
};
} // namespace daisysp
#endif
+43
View File
@@ -0,0 +1,43 @@
#include "dsp.h"
#include "sampleratereducer.h"
#include <math.h>
using namespace daisysp;
void SampleRateReducer::Init()
{
frequency_ = .2f;
phase_ = 0.0f;
sample_ = 0.0f;
next_sample_ = 0.0f;
previous_sample_ = 0.0f;
}
float SampleRateReducer::Process(float in)
{
float this_sample = next_sample_;
next_sample_ = 0.f;
phase_ += frequency_;
if(phase_ >= 1.0f)
{
phase_ -= 1.0f;
float t = phase_ / frequency_;
// t = 0: the transition occurred right at this sample.
// t = 1: the transition occurred at the previous sample.
// Use linear interpolation to recover the fractional sample.
float new_sample
= previous_sample_ + (in - previous_sample_) * (1.0f - t);
float discontinuity = new_sample - sample_;
this_sample += discontinuity * ThisBlepSample(t);
next_sample_ = discontinuity * NextBlepSample(t);
sample_ = new_sample;
}
next_sample_ += sample_;
previous_sample_ = in;
return this_sample;
}
void SampleRateReducer::SetFreq(float frequency)
{
frequency_ = fclamp(frequency, 0.f, 1.f);
}
+56
View File
@@ -0,0 +1,56 @@
/*
Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
*/
#pragma once
#ifndef DSY_SR_REDUCER_H
#define DSY_SR_REDUCER_H
#include <stdint.h>
#ifdef __cplusplus
/** @file sampleratereducer.h */
namespace daisysp
{
/**
@brief Sample rate reducer.
@author Ben Sergentanis
@date Jan 2021
Ported from pichenettes/eurorack/plaits/dsp/fx/sample_rate_reducer.h \n
to an independent module. \n
Original code written by Emilie Gillet in 2014. \n
*/
class SampleRateReducer
{
public:
SampleRateReducer() {}
~SampleRateReducer() {}
/** Initialize the module */
void Init();
/** Get the next floating point sample
\param in Sample to be processed.
*/
float Process(float in);
/** Set the new sample rate.
\param frequency over 0-1. 1 is full quality, .5 is half sample rate, etc.
*/
void SetFreq(float frequency);
private:
float frequency_;
float phase_;
float sample_;
float previous_sample_;
float next_sample_;
};
} // namespace daisysp
#endif
#endif
+36
View File
@@ -0,0 +1,36 @@
#include "tremolo.h"
#include <math.h>
using namespace daisysp;
void Tremolo::Init(float sample_rate)
{
sample_rate_ = sample_rate;
osc_.Init(sample_rate_);
SetDepth(1.f);
SetFreq(1.f);
}
float Tremolo::Process(float in)
{
float modsig = dc_os_ + osc_.Process();
return in * modsig;
}
void Tremolo::SetFreq(float freq)
{
osc_.SetFreq(freq);
}
void Tremolo::SetWaveform(int waveform)
{
osc_.SetWaveform(waveform);
}
void Tremolo::SetDepth(float depth)
{
depth = fclamp(depth, 0.f, 1.f);
depth *= .5f;
osc_.SetAmp(depth);
dc_os_ = 1.f - depth;
}
+68
View File
@@ -0,0 +1,68 @@
/*
Copyright (c) 2020 Electrosmith, Corp
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
*/
#pragma once
#ifndef DSY_TREMOLO_H
#define DSY_TREMOLO_H
#include <stdint.h>
#ifdef __cplusplus
#include <math.h>
#include "Synthesis/oscillator.h"
/** @file tremolo.h */
namespace daisysp
{
/**
@brief Tremolo effect.
@author Ben Sergentanis
@date Jan 2021
Based on https://christianfloisand.wordpress.com/2012/04/18/coding-some-tremolo/ \n
*/
class Tremolo
{
public:
Tremolo() {}
~Tremolo() {}
/** Initializes the module
\param sample_rate The sample rate of the audio engine being run.
*/
void Init(float sample_rate);
/**
\param in Input sample.
\return Next floating point sample.
*/
float Process(float in);
/** Sets the tremolo rate.
\param freq Tremolo freq in Hz.
*/
void SetFreq(float freq);
/** Shape of the modulating lfo
\param waveform Oscillator waveform. Use Oscillator::WAVE_SIN for example.
*/
void SetWaveform(int waveform);
/** How much to modulate your volume.
\param depth Works 0-1.
*/
void SetDepth(float depth);
private:
float sample_rate_, dc_os_;
Oscillator osc_;
};
} // namespace daisysp
#endif
#endif
+20
View File
@@ -0,0 +1,20 @@
#include "wavefolder.h"
#include <math.h>
using namespace daisysp;
void Wavefolder::Init()
{
gain_ = 1.0f;
offset_ = 0.0f;
}
float Wavefolder::Process(float in)
{
float ft, sgn;
in += offset_;
in *= gain_;
ft = floorf((in + 1.0f) * 0.5f);
sgn = static_cast<int>(ft) % 2 == 0 ? 1.0f : -1.0f;
return sgn * (in - 2.0f * ft);
}
+53
View File
@@ -0,0 +1,53 @@
/*
Copyright (c) 2020 Electrosmith, Corp, Nick Donaldson
Use of this source code is governed by an MIT-style
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
*/
#pragma once
#ifndef DSY_WAVEFOFOLDER_H
#define DSY_WAVEFOFOLDER_H
#include <stdint.h>
#include "Utility/dcblock.h"
#ifdef __cplusplus
namespace daisysp
{
/** Basic wavefolder module.
Amplitude of input determines level of folding.
Amplitudes of magnitude > 1.0 will start to fold.
Original author(s) : Nick Donaldson
Year : 2022
*/
class Wavefolder
{
public:
Wavefolder() {}
~Wavefolder() {}
/** Initializes the wavefolder module.
*/
void Init();
/** applies wavefolding to input
*/
float Process(float in);
/**
\param gain Set input gain.
Supports negative values for thru-zero
*/
inline void SetGain(float gain) { gain_ = gain; }
/**
\param offset Offset odded to input (pre-gain) for asymmetrical folding.
*/
inline void SetOffset(float offset) { offset_ = offset; }
private:
float gain_, offset_;
};
} // namespace daisysp
#endif
#endif