Wavefolding?
- KVRAF
- 3426 posts since 15 Nov, 2006 from Pacific NW
Try this:joshb wrote:Can anyone give me any insight into a wavefolding algorithm? I believe it's also referred to as foldover?
Thx
out = sinf(gain*in);
As gain gets larger, the output will start to fold back on itself. Very similar to the Serge wave multiplier, but with some nice sine curving, instead of the triangle wave folding found in the Serge circuit.
-
- KVRian
- 631 posts since 21 Jun, 2013
-
- KVRist
- Topic Starter
- 134 posts since 13 Apr, 2016
Wow, thank you. That's very cool. Both the demo animation and the actual function.
"apply triangle"...is that a known function? Never heard of it and it really beats the hell out of the 18 ugly lines of code I threw together:
"apply triangle"...is that a known function? Never heard of it and it really beats the hell out of the 18 ugly lines of code I threw together:
Code: Select all
float fold(float x)
{
float sign = 1.0f;
if(x < 0.0f)
sign = -1.0;
x *= sign;
if(x > threshold)
{
const float remainder = std::fmod(x, threshold);
const int numFolds = (int)std::floor(x / threshold);
float y;
if(numFolds % 2 == 0)
y = remainder;
else
y = threshold - remainder;
return y * sign;
}
return x * sign;
}
- KVRAF
- 7899 posts since 12 Feb, 2006 from Helsinki, Finland
Oh... that round() trick is really neat, saves some remapping when compared to using fmod(). Have to try to remember it.
-
- KVRian
- 631 posts since 21 Jun, 2013
mystran wrote: Oh... that round() trick is really neat, saves some remapping when compared to using fmod(). Have to try to remember it.
Code: Select all
//Range (-0.5,0.5)
__m128 fold(__m128 x)
{
__m128i int_round = _mm_cvtps_epi32(x);
__m128 frac = _mm_sub_ps(x,_mm_cvtepi32_ps(int_round));
return _mm_xor_ps(frac,_mm_castsi128_ps(_mm_slli_epi32(int_round,31)));
}
-
- KVRian
- 631 posts since 21 Jun, 2013
Have a look at:joshb wrote: "apply triangle"...is that a known function? Never heard of it and it really beats the hell out of the 18 ugly lines of code I threw together:
https://en.wikipedia.org/wiki/Triangle_wave
-
Smashed Transistors Smashed Transistors https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=339459
- KVRist
- 142 posts since 10 Oct, 2014
Polynomial integration/differentiation can be used to limit aliasing.
With this method, instead of using a punctual sample, you get a mean value over a sampling interval.
This method can be combined with x2 oversampling.
Here is a simplified code snippet from an Axoloti object.
With this method, instead of using a punctual sample, you get a mean value over a sampling interval.
This method can be combined with x2 oversampling.
Here is a simplified code snippet from an Axoloti object.
Code: Select all
//init code
float x0 = 0, x1 = 0, y0 = 0, y1 = 0;
//sample rate code
x1 = x0; y1 = y0;
x0 = input * drive; // input drive
float f0 = x0+16.5f;
int i0 = (int)f0; //rounding
if(i0 & 1){
f0 = 2 * (f0 - i0) - 1.0f; //wavefold segment
y0 = 0.25f*(f0*f0-1); // and its smooth integral
} else {
f0 = -2 * (f0 - i0) + 1.0f; //wavefold segment
y0 = -0.25f*(f0*f0-1); // and its smooth integral
}
float x1_x0 = x1 - x0;
if(fabs(x1_x0) > 0.001f){ // if the interval is large enough,
out = (y1 - y0) / (x1_x0); // we differentiate
}else{ // else we take the
out = f0; // direct value
}
- KVRAF
- 12555 posts since 7 Dec, 2004
While there is a very narrow focus on abs(), it is important to recognize that abs() is merely one possible non-linear function, while any non-linear function can be used to create this effect.
http://xhip.net/effects/?p=Multiplier
https://soundcloud.com/xhip/multiplier
abs() is an infinite order non-linearity while it is also possible to use low order (2nd, 3rd) to approximate it very well. These can be trivially anti-aliased because they generate a limited number of harmonics. (N^2 = at most 2x the bandwidth.)
The famous "Serge wave multiplier" used a diode clamp (NOT APPROXIMATED BY TANH()!) as the non-linear function.
Search for past threads on the topic, I'm not going to go into detail just repeating what has already been said.
http://xhip.net/effects/?p=Multiplier
https://soundcloud.com/xhip/multiplier
abs() is an infinite order non-linearity while it is also possible to use low order (2nd, 3rd) to approximate it very well. These can be trivially anti-aliased because they generate a limited number of harmonics. (N^2 = at most 2x the bandwidth.)
The famous "Serge wave multiplier" used a diode clamp (NOT APPROXIMATED BY TANH()!) as the non-linear function.
Search for past threads on the topic, I'm not going to go into detail just repeating what has already been said.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
- KVRist
- Topic Starter
- 134 posts since 13 Apr, 2016
The algorithm that 2DaT most generously gave:
is really close to what I'm trying to do. But I played around with this in Logic:
and was hoping to achieve that. I played around with that really elegant algorithm, but couldn't get there.
Any help would be greatly appreciated.
Code: Select all
out = 4.0 * (std::abs(0.25 * in + 0.25 - std::round(0.25 * in + 0.25)) - 0.25);
and was hoping to achieve that. I played around with that really elegant algorithm, but couldn't get there.
Any help would be greatly appreciated.
You do not have the required permissions to view the files attached to this post.
- KVRAF
- 12555 posts since 7 Dec, 2004
Code: Select all
float sign = x > 0 ? 1.0f : -1.0f;
float y = abs(x);
while (y >= 1.0f || y < 0.0f) {
if (y > 0.0f) {
y = 1.0f - y;
} else {
y = -y;
}
}
return sign * y;
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
- KVRAF
- 12555 posts since 7 Dec, 2004
Just a tip: give up on DSP and do something else with your time.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
-
- KVRian
- 631 posts since 21 Jun, 2013
- KVRAF
- 12555 posts since 7 Dec, 2004
Although that wraps at 1/2 which is a major problem.
A simple solution is to scale the input/output like so:
https://www.desmos.com/calculator/f9cedeyybp
Noting of course that these operations can be applied to the bits of the float value far more efficiently using some mask magic. I know it can be done trivially as an optimization but I won't get in to it: anyone in need of the performance boost can invest that time themselves.
Unfortunately nothing will cure the atrocious aliasing resulting from such an implementation; you're limited to over-sampling and 6 dB per power of 2.
Better functions are like this:
https://www.desmos.com/calculator/yay1rwvk2w
Which is only third order and so can be perfectly anti-aliased with only 3x over-sampling.
Since this example uses 3 stages it requires a 3^3 (27x) over-sample, but it may make sense to go for 8x, 12x or other values for optimization purposes. Practically speaking such a wave-multiplier has little benefit on super-sonic partials anyway so pre-filtering the input can make a lot of sense to decrease over-sampling needs.
It's also possible to apply dynamic range processing (limiter or compressor) to set the maximum depth of the effect so as to ensure the bandwidth is limited far below the absolute maximum of the function. In many cases an expander and limiter combination (inverted compansion) can make the depth effect more exponential (DX series FM-like) and limit the maximum bandwidth with minimal processing expense compared to over-sampling methods.
A simple solution is to scale the input/output like so:
https://www.desmos.com/calculator/f9cedeyybp
Noting of course that these operations can be applied to the bits of the float value far more efficiently using some mask magic. I know it can be done trivially as an optimization but I won't get in to it: anyone in need of the performance boost can invest that time themselves.
Unfortunately nothing will cure the atrocious aliasing resulting from such an implementation; you're limited to over-sampling and 6 dB per power of 2.
Better functions are like this:
https://www.desmos.com/calculator/yay1rwvk2w
Which is only third order and so can be perfectly anti-aliased with only 3x over-sampling.
Since this example uses 3 stages it requires a 3^3 (27x) over-sample, but it may make sense to go for 8x, 12x or other values for optimization purposes. Practically speaking such a wave-multiplier has little benefit on super-sonic partials anyway so pre-filtering the input can make a lot of sense to decrease over-sampling needs.
It's also possible to apply dynamic range processing (limiter or compressor) to set the maximum depth of the effect so as to ensure the bandwidth is limited far below the absolute maximum of the function. In many cases an expander and limiter combination (inverted compansion) can make the depth effect more exponential (DX series FM-like) and limit the maximum bandwidth with minimal processing expense compared to over-sampling methods.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.