Added DaisySP
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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_;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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_;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user