zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit 62f75704339db9307948f5934ba7ca02d68602ed
parent d36c18abd3dc4125057765c6f8b0a5cee3fe50bd
Author: Hans Petter Selasky <[email protected]>
Date:   Sun,  7 Feb 2021 18:31:22 +0100

Implement new oscillator function in ZynAddSubFX based on a power wave
function, which smoothly transform between square, triangle and sinus
waves using a single floating point parameter.

Signed-off-by: Hans Petter Selasky <[email protected]>

Diffstat:
Msrc/Synth/OscilGen.cpp | 76+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/UI/OscilGenUI.fl | 4++++
2 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -2,6 +2,7 @@ ZynAddSubFX - a software synthesizer OscilGen.cpp - Waveform generator for ADnote + Copyright (C) 2021 Hans Petter Selasky Copyright (C) 2002-2005 Nasca Octavian Paul Author: Nasca Octavian Paul @@ -44,7 +45,7 @@ const rtosc::Ports OscilGen::non_realtime_ports = { rOptions(sine, triangle, pulse, saw, power, gauss, diode, abssine, pulsesine, stretchsine, chirp, absstretchsine, chebyshev, sqr, - spike, circle), rOpt(127,use-as-base waveform), + spike, circle, powersinus), rOpt(127,use-as-base waveform), rDefault(sine), "Base Waveform for harmonics"), rParamZyn(Pbasefuncpar, rShort("shape"), rDefault(64), @@ -1629,6 +1630,78 @@ FUNC(circle) return y; } +static float +power_cosinus_32(float _x, double _power) +{ + uint32_t x = (_x - floorf(_x)) * (1ULL << 32); + double retval; + uint8_t num; + + /* Handle special cases, if any */ + switch (x) { + case 0xFFFFFFFFU: + case 0x00000000U: + return (1.0f); + case 0x3FFFFFFFU: + case 0x40000000U: + case 0xBFFFFFFFU: + case 0xC0000000U: + return (0.0f); + case 0x7FFFFFFFU: + case 0x80000000U: + return (-1.0f); + } + + /* Apply "grey" encoding */ + for (uint32_t mask = 1U << 31; mask != 1; mask /= 2) { + if (x & mask) + x ^= (mask - 1); + } + + /* Find first set bit */ + for (num = 0; num != 30; num++) { + if (x & (1U << num)) { + num++; + break; + } + } + + /* Initialize return value */ + retval = 0.0; + + /* Compute the rest of the power series */ + for (; num != 30; num++) { + if (x & (1U << num)) + retval = pow((1.0 - retval) / 2.0, _power); + else + retval = pow((1.0 + retval) / 2.0, _power); + } + + /* Check if halfway */ + if (x & (1ULL << 30)) + retval = -retval; + + return (retval); +} + +// +// power argument magic values: +// 0.0: Converges to a square wave +// 0.5: Sinus wave +// 1.0: Triangle wave +// x: phase value [0..1> +// +static float +power_sinus_32(float _x, double _power) +{ + return (power_cosinus_32(_x + 0.75f, _power)); +} + +FUNC(powersinus) +{ + return (power_sinus_32(x, 2.0 * a)); +} + base_func_t *getBaseFunction(unsigned char func) { static base_func_t * const functions[] = { @@ -1647,6 +1720,7 @@ base_func_t *getBaseFunction(unsigned char func) basefunc_sqr, basefunc_spike, basefunc_circle, + basefunc_powersinus, }; if(!func) diff --git a/src/UI/OscilGenUI.fl b/src/UI/OscilGenUI.fl @@ -440,6 +440,10 @@ setbfmodstatus(o->value()); label Circle xywh {127 127 100 20} labelfont 1 labelsize 11 } + MenuItem {} { + label PowerSinus + xywh {127 127 100 20} labelfont 1 labelsize 11 + } MenuItem {} { label User xywh {127 127 100 20} labelfont 1 labelsize 11 hide