History

keep up with the Joneses

Jeffrey Snyder committed 4 years ago

Commit 30ed1911 parent c353a6b5 files · +568 −196Browse files

Unified · Split

5 files
  1. leaf/Inc/leaf-math.h +0 −5
  2. leaf/Inc/leaf-oscillators.h +75 −12
  3. leaf/Src/leaf-filters.c +29 −5
  4. leaf/Src/leaf-math.c +33 −33
  5. leaf/Src/leaf-oscillators.c +431 −141
leaf/Inc/leaf-math.h+0−5
@@ -18,7 +18,6 @@ extern "C" { · 17 unmodified lines
18#include "stdint.h"18#include "stdint.h"
19#include "stdlib.h"19#include "stdlib.h"
20#include "limits.h"20#include "limits.h"
21
22 //==============================================================================21 //==============================================================================
23 22
24 //==============================================================================23 //==============================================================================
@@ -234,11 +233,7 @@ extern "C" { · 209 unmodified lines
234 float median3f(float a, float b, float c);233 float median3f(float a, float b, float c);
235 234
236 void place_step_dd(float *buffer, int index, float phase, float w, float scale);235 void place_step_dd(float *buffer, int index, float phase, float w, float scale);
237
238 void place_slope_dd(float *buffer, int index, float phase, float w, float slope_delta);236 void place_slope_dd(float *buffer, int index, float phase, float w, float slope_delta);
239
240 /*! @} */
241
242 //==============================================================================237 //==============================================================================
243 238
244#ifdef __cplusplus239#ifdef __cplusplus
leaf/Inc/leaf-oscillators.h+75−12
@@ -721,8 +721,6 @@ extern "C" { · 720 unmodified lines
721 721
722 tMempool mempool;722 tMempool mempool;
723 float out;723 float out;
724 float amp;
725 float last_amp;
726 float freq;724 float freq;
727 float waveform; // duty cycle, must be in [-1, 1]725 float waveform; // duty cycle, must be in [-1, 1]
728 float lastsyncin;726 float lastsyncin;
@@ -732,7 +730,6 @@ extern "C" { · 3 unmodified lines
732 float _p, _w, _b, _x, _z;730 float _p, _w, _b, _x, _z;
733 int _j, _k;731 int _j, _k;
734 float _f [FILLEN + STEP_DD_PULSE_LENGTH];732 float _f [FILLEN + STEP_DD_PULSE_LENGTH];
735 bool _init;
736 float invSampleRate;733 float invSampleRate;
737 } _tMBPulse;734 } _tMBPulse;
738 735
@@ -748,7 +745,7 @@ extern "C" { · 9 unmodified lines
748 float tMBPulse_sync(tMBPulse* const osc, float sync);745 float tMBPulse_sync(tMBPulse* const osc, float sync);
749 void tMBPulse_setPhase(tMBPulse* const osc, float phase);746 void tMBPulse_setPhase(tMBPulse* const osc, float phase);
750 void tMBPulse_setSyncMode(tMBPulse* const osc, int hardOrSoft);747 void tMBPulse_setSyncMode(tMBPulse* const osc, int hardOrSoft);
751 void tMBPulse_setBufferOffset(tMBPulse* const osc, int offset);748 void tMBPulse_setBufferOffset(tMBPulse* const osc, uint32_t offset);
752 void tMBPulse_setSampleRate (tMBPulse* const osc, float sr);749 void tMBPulse_setSampleRate (tMBPulse* const osc, float sr);
753 750
754 /*!751 /*!
@@ -796,8 +793,6 @@ extern "C" { · 41 unmodified lines
796 793
797 tMempool mempool;794 tMempool mempool;
798 float out;795 float out;
799 float amp;
800 float last_amp;
801 float freq;796 float freq;
802 float waveform; // duty cycle, must be in [-1, 1]797 float waveform; // duty cycle, must be in [-1, 1]
803 float lastsyncin;798 float lastsyncin;
@@ -807,7 +802,6 @@ extern "C" { · 3 unmodified lines
807 float _p, _w, _b, _z;802 float _p, _w, _b, _z;
808 int _j, _k;803 int _j, _k;
809 float _f [FILLEN + LONGEST_DD_PULSE_LENGTH];804 float _f [FILLEN + LONGEST_DD_PULSE_LENGTH];
810 bool _init;
811 float invSampleRate;805 float invSampleRate;
812 } _tMBTriangle;806 } _tMBTriangle;
813 807
@@ -823,7 +817,7 @@ extern "C" { · 9 unmodified lines
823 float tMBTriangle_sync(tMBTriangle* const osc, float sync);817 float tMBTriangle_sync(tMBTriangle* const osc, float sync);
824 void tMBTriangle_setPhase(tMBTriangle* const osc, float phase);818 void tMBTriangle_setPhase(tMBTriangle* const osc, float phase);
825 void tMBTriangle_setSyncMode(tMBTriangle* const osc, int hardOrSoft);819 void tMBTriangle_setSyncMode(tMBTriangle* const osc, int hardOrSoft);
826 void tMBTriangle_setBufferOffset(tMBTriangle* const osc, int offset);820 void tMBTriangle_setBufferOffset(tMBTriangle* const osc, uint32_t offset);
827 void tMBTriangle_setSampleRate (tMBTriangle* const osc, float sr);821 void tMBTriangle_setSampleRate (tMBTriangle* const osc, float sr);
828 822
829 823
@@ -871,8 +865,6 @@ extern "C" { · 41 unmodified lines
871 {865 {
872 tMempool mempool;866 tMempool mempool;
873 float out;867 float out;
874 float amp;
875 float last_amp;
876 float freq;868 float freq;
877 float lastsyncin;869 float lastsyncin;
878 float sync;870 float sync;
@@ -881,7 +873,6 @@ extern "C" { · 2 unmodified lines
881 float _p, _w, _z;873 float _p, _w, _z;
882 int _j;874 int _j;
883 float _f [FILLEN + STEP_DD_PULSE_LENGTH];875 float _f [FILLEN + STEP_DD_PULSE_LENGTH];
884 bool _init;
885 float invSampleRate;876 float invSampleRate;
886 } _tMBSaw;877 } _tMBSaw;
887 878
@@ -896,11 +887,83 @@ extern "C" { · 8 unmodified lines
896 float tMBSaw_sync(tMBSaw* const osc, float sync);887 float tMBSaw_sync(tMBSaw* const osc, float sync);
897 void tMBSaw_setPhase(tMBSaw* const osc, float phase);888 void tMBSaw_setPhase(tMBSaw* const osc, float phase);
898 void tMBSaw_setSyncMode(tMBSaw* const osc, int hardOrSoft);889 void tMBSaw_setSyncMode(tMBSaw* const osc, int hardOrSoft);
899 void tMBSaw_setBufferOffset(tMBSaw* const osc, int offset);890 void tMBSaw_setBufferOffset(tMBSaw* const osc, uint32_t offset);
900 void tMBSaw_setSampleRate (tMBSaw* const osc, float sr);891 void tMBSaw_setSampleRate (tMBSaw* const osc, float sr);
901 892
902 //==============================================================================893 //==============================================================================
894 /*!
895 @defgroup tmbsaw tMBSawPulse
896 @ingroup oscillators
897 @brief Saw wave mixed with Pulse wave oscillator with minBLEP anti-aliasing.
898 @{
899
900 @fn void tMBSaw_init(tMBSaw* const osc, LEAF* const leaf)
901 @brief Initialize a tMBSaw to the default mempool of a LEAF instance.
902 @param osc A pointer to the tMBSaw to initialize.
903
904 @fn void tMBSaw_initToPool(tMBSaw* const osc, tMempool* const mempool)
905 @brief Initialize a tMBSaw to a specified mempool.
906 @param osc A pointer to the tMBSaw to initialize.
907
908 @fn void tMBSaw_free(tMBSaw* const osc)
909 @brief Free a tMBSaw from its mempool.
910 @param osc A pointer to the tMBSaw to free.
911
912 @fn float tMBSaw_tick(tMBSaw* const osc)
913 @brief Tick the oscillator.
914 @param osc A pointer to the relevant tMBSaw.
915 @return The ticked sample.
916
917 @fn void tMBSaw_setFreq(tMBSaw* const osc, float f)
918 @brief Set the frequency of the oscillator.
919 @param osc A pointer to the relevant tMBSaw.
920 @param freq The new frequency.
921
922 @fn float tMBSaw_sync(tMBSaw* const osc, float sync)
923 @brief Sync this oscillator to another signal.
924 @param osc A pointer to the relevant tMBSaw.
925 @param sync A sample of the signal to sync to.
926 @return The passed in sample.
927
928 @fn void tMBSaw_setSyncMode(tMBSaw* const osc, int hardOrSoft)
929 @brief Set the sync behavior of the oscillator.
930 @param hardOrSoft 0 for hard sync, 1 for soft sync
931 
932 @} */
933
934 typedef struct _tMBSawPulse
935 {
936 tMempool mempool;
937 float out;
938 float freq;
939 float lastsyncin;
940 float sync;
941 float syncdir;
942 int softsync;
943 float waveform;
944 float _p, _w, _b, _x, _z, _k;
945 int _j;
946 float _f [FILLEN + STEP_DD_PULSE_LENGTH];
947 float invSampleRate;
948 float shape;
949 } _tMBSawPulse;
903 950
951 typedef _tMBSawPulse* tMBSawPulse;
952
953 void tMBSawPulse_init(tMBSawPulse* const osc, LEAF* const leaf);
954 void tMBSawPulse_initToPool(tMBSawPulse* const osc, tMempool* const mempool);
955 void tMBSawPulse_free(tMBSawPulse* const osc);
956
957 float tMBSawPulse_tick(tMBSawPulse* const osc);
958 void tMBSawPulse_setFreq(tMBSawPulse* const osc, float f);
959 float tMBSawPulse_sync(tMBSawPulse* const osc, float sync);
960 void tMBSawPulse_setPhase(tMBSawPulse* const osc, float phase);
961 void tMBSawPulse_setShape(tMBSawPulse* const osc, float shape);
962 void tMBSawPulse_setSyncMode(tMBSawPulse* const osc, int hardOrSoft);
963 void tMBSawPulse_setBufferOffset(tMBSawPulse* const osc, uint32_t offset);
964 void tMBSawPulse_setSampleRate (tMBSawPulse* const osc, float sr);
965
966 //==============================================================================
904 /*!967 /*!
905 @defgroup ttable tTable968 @defgroup ttable tTable
906 @ingroup oscillators969 @ingroup oscillators
leaf/Src/leaf-filters.c+29−5
@@ -17,7 +17,10 @@ · 16 unmodified lines
17#include "../Inc/leaf-filters.h"17#include "../Inc/leaf-filters.h"
18#include "../Inc/leaf-tables.h"18#include "../Inc/leaf-tables.h"
19#include "../leaf.h"19#include "../leaf.h"
20//#include "tim.h"20#endif
21
22#ifdef ARM_MATH_CM7
23#include "arm_math.h"
21#endif24#endif
22 25
23// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OnePole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //26// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OnePole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
@@ -1821,12 +1824,15 @@ float tanhXdX(float x) · 1797 unmodified lines
1821 }1824 }
1822 return ((a + 105.0f)*a + 945.0f) / output;1825 return ((a + 105.0f)*a + 945.0f) / output;
1823}1826}
1827
1824volatile int errorCheckCheck = 0;1828volatile int errorCheckCheck = 0;
1829//#define SAFE_FILTER
1825float tDiodeFilter_tick (tDiodeFilter* const vf, float in)1830float tDiodeFilter_tick (tDiodeFilter* const vf, float in)
1826{1831{
1827 _tDiodeFilter* f = *vf;1832 _tDiodeFilter* f = *vf;
1828 1833#ifdef SAFE_FILTER
1829 int errorCheck = 0;1834 int errorCheck = 0;
1835#endif
1830 // the input x[n+1] is given by 'in', and x[n] by zi1836 // the input x[n+1] is given by 'in', and x[n] by zi
1831 // input with half delay1837 // input with half delay
1832 float ih = 0.5f * (in + f->zi);1838 float ih = 0.5f * (in + f->zi);
@@ -1840,24 +1846,30 @@ float tDiodeFilter_tick (tDiodeFilter* const vf, float in) · 7 unmodified lines
1840 1846
1841 // This formula gives the result for y3 thanks to MATLAB1847 // This formula gives the result for y3 thanks to MATLAB
1842 float y3 = (f->s2 + f->s3 + t2*(f->s1 + f->s2 + f->s3 + t1*(f->s0 + f->s1 + f->s2 + f->s3 + t0*in)) + t1*(2.0f*f->s2 + 2.0f*f->s3))*t3 + f->s3 + 2.0f*f->s3*t1 + t2*(2.0f*f->s3 + 3.0f*f->s3*t1);1848 float y3 = (f->s2 + f->s3 + t2*(f->s1 + f->s2 + f->s3 + t1*(f->s0 + f->s1 + f->s2 + f->s3 + t0*in)) + t1*(2.0f*f->s2 + 2.0f*f->s3))*t3 + f->s3 + 2.0f*f->s3*t1 + t2*(2.0f*f->s3 + 3.0f*f->s3*t1);
1849#ifdef SAFE_FILTER
1843 if (isnan(y3))1850 if (isnan(y3))
1844 {1851 {
1845 errorCheck = 1;1852 errorCheck = 1;
1846 }1853 }
1854#endif
1847 float tempy3denom = (t4 + t1*(2.0f*t4 + 4.0f) + t2*(t4 + t1*(t4 + f->r*t0 + 4.0f) + 3.0f) + 2.0f)*t3 + t4 + t1*(2.0f*t4 + 2.0f) + t2*(2.0f*t4 + t1*(3.0f*t4 + 3.0f) + 2.0f) + 1.0f;1855 float tempy3denom = (t4 + t1*(2.0f*t4 + 4.0f) + t2*(t4 + t1*(t4 + f->r*t0 + 4.0f) + 3.0f) + 2.0f)*t3 + t4 + t1*(2.0f*t4 + 2.0f) + t2*(2.0f*t4 + t1*(3.0f*t4 + 3.0f) + 2.0f) + 1.0f;
1856#ifdef SAFE_FILTER
1848 if (isnan(tempy3denom))1857 if (isnan(tempy3denom))
1849 {1858 {
1850 errorCheck = 2;1859 errorCheck = 2;
1851 }1860 }
1861#endif
1852 if (tempy3denom == 0.0f)1862 if (tempy3denom == 0.0f)
1853 {1863 {
1854 tempy3denom = 0.000001f;1864 tempy3denom = 0.000001f;
1855 }1865 }
1856 y3 = y3 / tempy3denom;1866 y3 = y3 / tempy3denom;
1867#ifdef SAFE_FILTER
1857 if (isnan(y3))1868 if (isnan(y3))
1858 {1869 {
1859 errorCheck = 3;1870 errorCheck = 3;
1860 }1871 }
1872#endif
1861 if (t1 == 0.0f)1873 if (t1 == 0.0f)
1862 {1874 {
1863 t1 = 0.000001f;1875 t1 = 0.000001f;
@@ -1878,19 +1890,22 @@ float tDiodeFilter_tick (tDiodeFilter* const vf, float in) · 14 unmodified lines
1878 1890
1879 // update state1891 // update state
1880 f->s0 += 2.0f * (t0*xx + t1*(y1-y0));1892 f->s0 += 2.0f * (t0*xx + t1*(y1-y0));
1893#ifdef SAFE_FILTER
1881 if (isnan(f->s0))1894 if (isnan(f->s0))
1882 {1895 {
1883 errorCheck = 4;1896 errorCheck = 4;
1884 }1897 }
1885 1898
1886 if (isinf(f->s0))1899 if (isinf(f->s0))
1887 {1900 {
1888 errorCheck = 5;1901 errorCheck = 5;
1889 }1902 }
1903
1890 if (errorCheck != 0)1904 if (errorCheck != 0)
1891 {1905 {
1892 errorCheckCheck = 1;1906 errorCheckCheck = errorCheck;
1893 }1907 }
1908#endif
1894 f->s1 += 2.0f * (t2*(y2-y1) - t1*(y1-y0));1909 f->s1 += 2.0f * (t2*(y2-y1) - t1*(y1-y0));
1895 f->s2 += 2.0f * (t3*(y3-y2) - t2*(y2-y1));1910 f->s2 += 2.0f * (t3*(y3-y2) - t2*(y2-y1));
1896 f->s3 += 2.0f * (-t4*(y3) - t3*(y3-y2));1911 f->s3 += 2.0f * (-t4*(y3) - t3*(y3-y2));
@@ -1975,7 +1990,16 @@ void tLadderFilter_free (tLadderFilter* const vf) · 78 unmodified lines
1975 1990
1976float smoothABS ( float x, const float y) // y controls 'smoothness' usually between 0.002 -> 0.041991float smoothABS ( float x, const float y) // y controls 'smoothness' usually between 0.002 -> 0.04
1977{1992{
1978 return (sqrtf((x * x) + y)) - sqrtf(y);1993 //possible speedup with sqrt CMSIS-DSP approximation? seems to resolve to just a normal call to sqrt. Maybe the vector version since there are two square roots to determine? -JS
1994// #ifdef ARM_MATH_CM7
1995// float output1;
1996// float output2;
1997// arm_sqrt_f32((x * x) + y, &output1);
1998// arm_sqrt_f32(y, &output2);
1999// return output1 - output2;
2000// #else
2001 return (sqrtf((x * x) + y)) - sqrtf(y);
2002// #endif
1979}2003}
1980 2004
1981float smoothclip (float x, const float a, const float b) // assuming symmetrical clipping2005float smoothclip (float x, const float a, const float b) // assuming symmetrical clipping
leaf/Src/leaf-math.c+33−33
@@ -847,39 +847,39 @@ float median3f(float a, float b, float c) · 846 unmodified lines
847/// MINBLEPS847/// MINBLEPS
848// https://github.com/MrBlueXav/Dekrispator_v2 blepvco.c848// https://github.com/MrBlueXav/Dekrispator_v2 blepvco.c
849void place_step_dd(float *buffer, int index, float phase, float w, float scale)849void place_step_dd(float *buffer, int index, float phase, float w, float scale)
850{850 {
851 float r;851 float r;
852 long i;852 long i;
853 853
854 r = MINBLEP_PHASES * phase / w;854 r = MINBLEP_PHASES * phase / w;
855 i = lrintf(r - 0.5f);855 i = lrintf(r - 0.5f);
856 r -= (float)i;856 r -= (float)i;
857 i &= MINBLEP_PHASE_MASK; /* extreme modulation can cause i to be out-of-range */857 i &= MINBLEP_PHASE_MASK; /* extreme modulation can cause i to be out-of-range */
858 858
859 while (i < MINBLEP_PHASES * STEP_DD_PULSE_LENGTH) {859 while (i < MINBLEP_PHASES * STEP_DD_PULSE_LENGTH) {
860 buffer[index] += scale * (step_dd_table[i].value + r * step_dd_table[i].delta);860 buffer[index] += scale * (step_dd_table[i].value + r * step_dd_table[i].delta);
861 i += MINBLEP_PHASES;861 i += MINBLEP_PHASES;
862 index++;862 index++;
863 }
863 }864 }
864}
865//----------------------------------------------------------------------------------------------------------
866
867void place_slope_dd(float *buffer, int index, float phase, float w, float slope_delta)865void place_slope_dd(float *buffer, int index, float phase, float w, float slope_delta)
868{866 {
869 float r;867 float r;
870 long i;868 long i;
871 869
872 r = MINBLEP_PHASES * phase / w;870 r = MINBLEP_PHASES * phase / w;
873 i = lrintf(r - 0.5f);871 i = lrintf(r - 0.5f);
874 r -= (float)i;872 r -= (float)i;
875 i &= MINBLEP_PHASE_MASK; /* extreme modulation can cause i to be out-of-range */873 i &= MINBLEP_PHASE_MASK; /* extreme modulation can cause i to be out-of-range */
876 874
877 slope_delta *= w;875 slope_delta *= w;
878 876
879 while (i < MINBLEP_PHASES * SLOPE_DD_PULSE_LENGTH) {877 while (i < MINBLEP_PHASES * SLOPE_DD_PULSE_LENGTH) {
880 buffer[index] += slope_delta * (slope_dd_table[i] + r * (slope_dd_table[i + 1] - slope_dd_table[i]));878 buffer[index] += slope_delta * (slope_dd_table[i] + r * (slope_dd_table[i + 1] - slope_dd_table[i]));
881 i += MINBLEP_PHASES;879 i += MINBLEP_PHASES;
882 index++;880 index++;
883 }881 }
884}882 }
885#endif // LEAF_INCLUDE_MINBLEP_TABLES883#endif // LEAF_INCLUDE_MINBLEP_TABLES
884 /*! @} */
885
leaf/Src/leaf-oscillators.c+431−141
@@ -938,8 +938,7 @@ void tMBPulse_initToPool(tMBPulse* const osc, tMempool* const pool) · 937 unmodified lines
938 938
939 c->invSampleRate = leaf->invSampleRate;939 c->invSampleRate = leaf->invSampleRate;
940 940
941 c->_init = true;941
942 c->amp = 1.0f;
943 c->freq = 440.f;942 c->freq = 440.f;
944 c->lastsyncin = 0.0f;943 c->lastsyncin = 0.0f;
945 c->sync = 0.0f;944 c->sync = 0.0f;
@@ -948,6 +947,12 @@ void tMBPulse_initToPool(tMBPulse* const osc, tMempool* const pool) · 2 unmodified lines
948 c->waveform = 0.0f;947 c->waveform = 0.0f;
949 c->_z = 0.0f;948 c->_z = 0.0f;
950 c->_j = 0;949 c->_j = 0;
950 c->_p = 0.0f; /* phase [0, 1) */
951 c->_w = c->freq * c->invSampleRate; /* phase increment */
952 c->_b = 0.5f * (1.0f + c->waveform); /* duty cycle (0, 1) */
953 c->_x = 0.5f; /* temporary output variable */
954 c->_k = 0.0f; /* output state, 0 = high (0.5f), 1 = low (-0.5f) */
955
951 memset (c->_f, 0, (FILLEN + STEP_DD_PULSE_LENGTH) * sizeof (float));956 memset (c->_f, 0, (FILLEN + STEP_DD_PULSE_LENGTH) * sizeof (float));
952}957}
953 958
@@ -962,11 +967,11 @@ float tMBPulse_tick(tMBPulse* const osc) · 8 unmodified lines
962 _tMBPulse* c = *osc;967 _tMBPulse* c = *osc;
963 968
964 int j, k;969 int j, k;
965 float freq, sync;970 float sync;
966 float a, b, p, w, x, z, sw;971 float b, p, w, x, z, sw;
967 972
968 sync = c->sync;973 sync = c->sync;
969 freq = c->freq;974
970 p = c->_p; /* phase [0, 1) */975 p = c->_p; /* phase [0, 1) */
971 w = c->_w; /* phase increment */976 w = c->_w; /* phase increment */
972 b = c->_b; /* duty cycle (0, 1) */977 b = c->_b; /* duty cycle (0, 1) */
@@ -974,30 +979,7 @@ float tMBPulse_tick(tMBPulse* const osc) · 1 unmodified line
974 z = c->_z; /* low pass filter state */979 z = c->_z; /* low pass filter state */
975 j = c->_j; /* index into buffer _f */980 j = c->_j; /* index into buffer _f */
976 k = c->_k; /* output state, 0 = high (0.5f), 1 = low (-0.5f) */981 k = c->_k; /* output state, 0 = high (0.5f), 1 = low (-0.5f) */
977 //982
978 if (c->_init) {
979 p = 0.0f;
980
981 w = freq * c->invSampleRate;
982 b = 0.5f * (1.0f + c->waveform );
983
984 /* for variable-width rectangular wave, we could do DC compensation with:
985 * x = 1.0f - b;
986 * but that doesn't work well with highly modulated hard sync. Instead,
987 * we keep things in the range [-0.5f, 0.5f]. */
988 x = 0.5f;
989 /* if we valued alias-free startup over low startup time, we could do:
990 * p -= w;
991 * place_step_dd(_f, j, 0.0f, w, 0.5f); */
992 k = 0;
993 c->_init = false;
994 }
995 //
996 // a = 0.2 + 0.8 * vco->_port [FILT];
997 a = 0.5f; // when a = 1, LPfilter is disabled
998
999 w = freq * c->invSampleRate;
1000 b = 0.5f * (1.0f + c->waveform);
1001 983
1002 if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;984 if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;
1003 985
@@ -1163,8 +1145,8 @@ float tMBPulse_tick(tMBPulse* const osc) · 159 unmodified lines
1163 }1145 }
1164 c->_f[j + DD_SAMPLE_DELAY] += x;1146 c->_f[j + DD_SAMPLE_DELAY] += x;
1165 1147
1166 z += a * (c->_f[j] - z);1148 z += 0.5f * (c->_f[j] - z);
1167 c->out = c->amp * z;1149 c->out = z;
1168 1150
1169 if (++j == FILLEN)1151 if (++j == FILLEN)
1170 {1152 {
@@ -1188,6 +1170,7 @@ void tMBPulse_setFreq(tMBPulse* const osc, float f) · 17 unmodified lines
1188{1170{
1189 _tMBPulse* c = *osc;1171 _tMBPulse* c = *osc;
1190 c->freq = f;1172 c->freq = f;
1173 c->_w = c->freq * c->invSampleRate; /* phase increment */
1191}1174}
1192 1175
1193void tMBPulse_setWidth(tMBPulse* const osc, float w)1176void tMBPulse_setWidth(tMBPulse* const osc, float w)
@@ -1219,10 +1202,10 @@ void tMBPulse_setPhase(tMBPulse* const osc, float phase) · 25 unmodified lines
1219}1202}
1220 1203
1221//useful if you have several oscillators so the buffer refill is not synchronized1204//useful if you have several oscillators so the buffer refill is not synchronized
1222void tMBPulse_setBufferOffset(tMBPulse* const osc, int offset)1205void tMBPulse_setBufferOffset(tMBPulse* const osc, uint32_t offset)
1223{1206{
1224 _tMBPulse* c = *osc;1207 _tMBPulse* c = *osc;
1225 offset = LEAF_clip(0,offset, FILLEN-1);1208 offset = offset & (FILLEN-1);
1226 c->_j = offset;1209 c->_j = offset;
1227}1210}
1228 1211
@@ -1254,16 +1237,18 @@ void tMBTriangle_initToPool(tMBTriangle* const osc, tMempool* const pool) · 25 unmodified lines
1254 LEAF* leaf = c->mempool->leaf;1237 LEAF* leaf = c->mempool->leaf;
1255 1238
1256 c->invSampleRate = leaf->invSampleRate;1239 c->invSampleRate = leaf->invSampleRate;
1257 c->amp = 1.0f;
1258 c->freq = 440.f;1240 c->freq = 440.f;
1259 c->lastsyncin = 0.0f;1241 c->lastsyncin = 0.0f;
1260 c->sync = 0.0f;1242 c->sync = 0.0f;
1261 c->syncdir = 1.0f;1243 c->syncdir = 1.0f;
1262 c->softsync = 0;1244 c->softsync = 0;
1263 c->waveform = 0.0f;1245 c->waveform = 0.0f;
1264 c->_init = true;
1265 c->_z = 0.0f;1246 c->_z = 0.0f;
1266 c->_j = 0;1247 c->_j = 0;
1248 c->_p = 0.0f; /* phase [0, 1) */
1249 c->_w = c->freq * c->invSampleRate; /* phase increment */
1250 c->_b = 0.5f * (1.0f + c->waveform); /* duty cycle (0, 1) */
1251 c->_k = 0.0f; /* output state, 0 = high (0.5f), 1 = low (-0.5f) */
1267 memset (c->_f, 0, (FILLEN + STEP_DD_PULSE_LENGTH) * sizeof (float));1252 memset (c->_f, 0, (FILLEN + STEP_DD_PULSE_LENGTH) * sizeof (float));
1268}1253}
1269 1254
@@ -1277,41 +1262,27 @@ float tMBTriangle_tick(tMBTriangle* const osc) · 7 unmodified lines
1277{1262{
1278 _tMBTriangle* c = *osc;1263 _tMBTriangle* c = *osc;
1279 1264
1280 int j, k, dir;1265 int j, k;
1281 float freq, sync;1266 float sync;
1282 float a, b, b1, p, w, sw, x, z;1267 float b, b1, invB, invB1, p, w, sw, z;
1268 float x = 0.5f;
1283 1269
1284 sync = c->sync;1270 sync = c->sync;
1285 dir = c->syncdir;1271
1286 freq = c->freq;1272
1287 p = c->_p; /* phase [0, 1) */1273 p = c->_p; /* phase [0, 1) */
1288 w = c->_w; /* phase increment */1274 w = c->_w; /* phase increment */
1289 b = c->_b; /* duty cycle (0, 1) */1275 b = c->_b; /* duty cycle (0, 1) */
1276 invB = 1.0f / b;
1290 z = c->_z; /* low pass filter state */1277 z = c->_z; /* low pass filter state */
1291 j = c->_j; /* index into buffer _f */1278 j = c->_j; /* index into buffer _f */
1292 k = c->_k; /* output state, 0 = positive slope, 1 = negative slope */1279 k = c->_k; /* output state, 0 = positive slope, 1 = negative slope */
1293 1280
1294 if (c->_init) {
1295 // w = (exp2ap (freq[1] + vco->_port[OCTN] + vco->_port[TUNE] + expm[1] * vco->_port[EXPG] + 8.03136)
1296 // + 1e3 * linm[1] * vco->_port[LING]) / SAMPLERATE;
1297 w = freq * c->invSampleRate;
1298 b = 0.5f * (1.0f + c->waveform);
1299// p = 0.5f * b;
1300 p = 0.f;
1301 /* if we valued alias-free startup over low startup time, we could do:
1302 * p -= w;
1303 * place_slope_dd(_f, j, 0.0f, w, 1.0f / b); */
1304 k = 0;
1305 c->_init = false;
1306 }
1307 1281
1308 // a = 0.2 + 0.8 * vco->_port [FILT];1282
1309 a = 0.5f; // when a = 1, LPfilter is disabled
1310
1311 w = freq * c->invSampleRate;
1312 b = 0.5f * (1.0f + c->waveform);1283 b = 0.5f * (1.0f + c->waveform);
1313 b1 = 1.0f - b;1284 b1 = 1.0f - b;
1314 1285 invB1 = 1.0f / b1;
1315 if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;1286 if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;
1316 1287
1317 sw = w * c->syncdir;1288 sw = w * c->syncdir;
@@ -1327,18 +1298,18 @@ float tMBTriangle_tick(tMBTriangle* const osc) · 9 unmodified lines
1327 /* place any DDs that may have occurred in subsample before reset */1298 /* place any DDs that may have occurred in subsample before reset */
1328 1299
1329 if (!k) {1300 if (!k) {
1330 x = -0.5f + p_at_reset / b;1301 x = -0.5f + p_at_reset * invB;
1331 if (sw > 0)1302 if (sw > 0)
1332 {1303 {
1333 if (p_at_reset >= b) {1304 if (p_at_reset >= b) {
1334 x = 0.5f - (p_at_reset - b) / b1;1305 x = 0.5f - (p_at_reset - b) * invB1;
1335 place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, sw, -1.0f / b1 - 1.0f / b);1306 place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, sw, -invB1 - invB);
1336 k = 1;1307 k = 1;
1337 }1308 }
1338 if (p_at_reset >= 1.0f) {1309 if (p_at_reset >= 1.0f) {
1339 p_at_reset -= 1.0f;1310 p_at_reset -= 1.0f;
1340 x = -0.5f + p_at_reset / b;1311 x = -0.5f + p_at_reset * invB;
1341 place_slope_dd(c->_f, j, p_at_reset + eof_offset, sw, 1.0f / b + 1.0f / b1);1312 place_slope_dd(c->_f, j, p_at_reset + eof_offset, sw, invB + invB1);
1342 k = 0;1313 k = 0;
1343 }1314 }
1344 }1315 }
@@ -1346,43 +1317,43 @@ float tMBTriangle_tick(tMBTriangle* const osc) · 1 unmodified line
1346 {1317 {
1347 if (p_at_reset < 0.0f) {1318 if (p_at_reset < 0.0f) {
1348 p_at_reset += 1.0f;1319 p_at_reset += 1.0f;
1349 x = 0.5f - (p_at_reset - b) / b1;1320 x = 0.5f - (p_at_reset - b) * invB1;
1350 place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, 1.0f / b + 1.0f / b1);1321 place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, invB + invB1);
1351 k = 1;1322 k = 1;
1352 }1323 }
1353 if (k && p_at_reset < b) {1324 if (k && p_at_reset < b) {
1354 x = -0.5f + p_at_reset / b;1325 x = -0.5f + p_at_reset * invB;
1355 place_slope_dd(c->_f, j, b - p_at_reset - eof_offset, -sw, -1.0f / b1 - 1.0f / b);1326 place_slope_dd(c->_f, j, b - p_at_reset - eof_offset, -sw, -invB1 - invB);
1356 k = 0;1327 k = 0;
1357 }1328 }
1358 }1329 }
1359 } else {1330 } else {
1360 x = 0.5f - (p_at_reset - b) / b1;1331 x = 0.5f - (p_at_reset - b) * invB1;
1361 if (sw > 0)1332 if (sw > 0)
1362 {1333 {
1363 if (p_at_reset >= 1.0f) {1334 if (p_at_reset >= 1.0f) {
1364 p_at_reset -= 1.0f;1335 p_at_reset -= 1.0f;
1365 x = -0.5f + p_at_reset / b;1336 x = -0.5f + p_at_reset * invB;
1366 place_slope_dd(c->_f, j, p_at_reset + eof_offset, sw, 1.0f / b + 1.0f / b1);1337 place_slope_dd(c->_f, j, p_at_reset + eof_offset, sw, invB + invB1);
1367 k = 0;1338 k = 0;
1368 }1339 }
1369 if (!k && p_at_reset >= b) {1340 if (!k && p_at_reset >= b) {
1370 x = 0.5f - (p_at_reset - b) / b1;1341 x = 0.5f - (p_at_reset - b) * invB1;
1371 place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, sw, -1.0f / b1 - 1.0f / b);1342 place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, sw, -invB1 - invB);
1372 k = 1;1343 k = 1;
1373 }1344 }
1374 }1345 }
1375 else if (sw < 0)1346 else if (sw < 0)
1376 {1347 {
1377 if (p_at_reset < b) {1348 if (p_at_reset < b) {
1378 x = -0.5f + p_at_reset / b;1349 x = -0.5f + p_at_reset * invB;
1379 place_slope_dd(c->_f, j, b - p_at_reset - eof_offset, -sw, -1.0f / b1 - 1.0f / b);1350 place_slope_dd(c->_f, j, b - p_at_reset - eof_offset, -sw, -invB1 - invB);
1380 k = 0;1351 k = 0;
1381 }1352 }
1382 if (p_at_reset < 0.0f) {1353 if (p_at_reset < 0.0f) {
1383 p_at_reset += 1.0f;1354 p_at_reset += 1.0f;
1384 x = 0.5f - (p_at_reset - b) / b1;1355 x = 0.5f - (p_at_reset - b) * invB1;
1385 place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, 1.0f / b + 1.0f / b1);1356 place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, invB + invB1);
1386 k = 1;1357 k = 1;
1387 }1358 }
1388 }1359 }
@@ -1392,43 +1363,43 @@ float tMBTriangle_tick(tMBTriangle* const osc) · 3 unmodified lines
1392 if (sw > 0)1363 if (sw > 0)
1393 {1364 {
1394 if (k)1365 if (k)
1395 place_slope_dd(c->_f, j, p, sw, 1.0f / b + 1.0f / b1);1366 place_slope_dd(c->_f, j, p, sw, invB + invB1);
1396 place_step_dd(c->_f, j, p, sw, -0.5f - x);1367 place_step_dd(c->_f, j, p, sw, -0.5f - x);
1397 x = -0.5f + p / b;1368 x = -0.5f + p * invB;
1398 k = 0;1369 k = 0;
1399 if (p >= b) {1370 if (p >= b) {
1400 x = 0.5f - (p - b) / b1;1371 x = 0.5f - (p - b) * invB1;
1401 place_slope_dd(c->_f, j, p - b, sw, -1.0f / b1 - 1.0f / b);1372 place_slope_dd(c->_f, j, p - b, sw, -invB1 - invB);
1402 k = 1;1373 k = 1;
1403 }1374 }
1404 }1375 }
1405 else if (sw < 0)1376 else if (sw < 0)
1406 {1377 {
1407 if (!k)1378 if (!k)
1408 place_slope_dd(c->_f, j, 1.0f - p, -sw, 1.0f / b + 1.0f / b1);1379 place_slope_dd(c->_f, j, 1.0f - p, -sw, invB + invB1);
1409 place_step_dd(c->_f, j, 1.0f - p, -sw, -0.5f - x);1380 place_step_dd(c->_f, j, 1.0f - p, -sw, -0.5f - x);
1410 x = 0.5f - (p - b) / b1;1381 x = 0.5f - (p - b) * invB1;
1411 k = 1;1382 k = 1;
1412 if (p < b) {1383 if (p < b) {
1413 x = -0.5f + p / b;1384 x = -0.5f + p * invB;
1414 place_slope_dd(c->_f, j, b - p, -sw, -1.0f / b1 - 1.0f / b);1385 place_slope_dd(c->_f, j, b - p, -sw, -invB1 - invB);
1415 k = 0;1386 k = 0;
1416 }1387 }
1417 }1388 }
1418 } else if (!k) { /* normal operation, slope currently up */1389 } else if (!k) { /* normal operation, slope currently up */
1419 1390
1420 x = -0.5f + p / b;1391 x = -0.5f + p * invB;
1421 if (sw > 0)1392 if (sw > 0)
1422 {1393 {
1423 if (p >= b) {1394 if (p >= b) {
1424 x = 0.5f - (p - b) / b1;1395 x = 0.5f - (p - b) * invB1;;
1425 place_slope_dd(c->_f, j, p - b, sw, -1.0f / b1 - 1.0f / b);1396 place_slope_dd(c->_f, j, p - b, sw, -invB1 - invB);
1426 k = 1;1397 k = 1;
1427 }1398 }
1428 if (p >= 1.0f) {1399 if (p >= 1.0f) {
1429 p -= 1.0f;1400 p -= 1.0f;
1430 x = -0.5f + p / b;1401 x = -0.5f + p * invB;
1431 place_slope_dd(c->_f, j, p, sw, 1.0f / b + 1.0f / b1);1402 place_slope_dd(c->_f, j, p, sw, invB + invB1);
1432 k = 0;1403 k = 0;
1433 }1404 }
1434 }1405 }
@@ -1436,53 +1407,53 @@ float tMBTriangle_tick(tMBTriangle* const osc) · 1 unmodified line
1436 {1407 {
1437 if (p < 0.0f) {1408 if (p < 0.0f) {
1438 p += 1.0f;1409 p += 1.0f;
1439 x = 0.5f - (p - b) / b1;1410 x = 0.5f - (p - b) * invB1;
1440 place_slope_dd(c->_f, j, 1.0f - p, -sw, 1.0f / b + 1.0f / b1);1411 place_slope_dd(c->_f, j, 1.0f - p, -sw, invB + invB1);
1441 k = 1;1412 k = 1;
1442 }1413 }
1443 if (k && p < b) {1414 if (k && p < b) {
1444 x = -0.5f + p / b;1415 x = -0.5f + p * invB;
1445 place_slope_dd(c->_f, j, b - p, -sw, -1.0f / b1 - 1.0f / b);1416 place_slope_dd(c->_f, j, b - p, -sw, -invB1 - invB);
1446 k = 0;1417 k = 0;
1447 }1418 }
1448 }1419 }
1449 1420
1450 } else { /* normal operation, slope currently down */1421 } else { /* normal operation, slope currently down */
1451 1422
1452 x = 0.5f - (p - b) / b1;1423 x = 0.5f - (p - b) * invB1;
1453 if (sw > 0)1424 if (sw > 0)
1454 {1425 {
1455 if (p >= 1.0f) {1426 if (p >= 1.0f) {
1456 p -= 1.0f;1427 p -= 1.0f;
1457 x = -0.5f + p / b;1428 x = -0.5f + p * invB;
1458 place_slope_dd(c->_f, j, p, sw, 1.0f / b + 1.0f / b1);1429 place_slope_dd(c->_f, j, p, sw, invB + invB1);
1459 k = 0;1430 k = 0;
1460 }1431 }
1461 if (!k && p >= b) {1432 if (!k && p >= b) {
1462 x = 0.5f - (p - b) / b1;1433 x = 0.5f - (p - b) * invB1;
1463 place_slope_dd(c->_f, j, p - b, sw, -1.0f / b1 - 1.0f / b);1434 place_slope_dd(c->_f, j, p - b, sw, -invB1 - invB);
1464 k = 1;1435 k = 1;
1465 }1436 }
1466 }1437 }
1467 else if (sw < 0)1438 else if (sw < 0)
1468 {1439 {
1469 if (p < b) {1440 if (p < b) {
1470 x = -0.5f + p / b;1441 x = -0.5f + p * invB;
1471 place_slope_dd(c->_f, j, b - p, -sw, -1.0f / b1 - 1.0f / b);1442 place_slope_dd(c->_f, j, b - p, -sw, -invB1 - invB);
1472 k = 0;1443 k = 0;
1473 }1444 }
1474 if (p < 0.0f) {1445 if (p < 0.0f) {
1475 p += 1.0f;1446 p += 1.0f;
1476 x = 0.5f - (p - b) / b1;1447 x = 0.5f - (p - b) * invB1;
1477 place_slope_dd(c->_f, j, 1.0f - p, -sw, 1.0f / b + 1.0f / b1);1448 place_slope_dd(c->_f, j, 1.0f - p, -sw, invB + invB1);
1478 k = 1;1449 k = 1;
1479 }1450 }
1480 }1451 }
1481 }1452 }
1482 c->_f[j + DD_SAMPLE_DELAY] += x;1453 c->_f[j + DD_SAMPLE_DELAY] += x;
1483 1454
1484 z += a * (c->_f[j] - z);1455 z += 0.5f * (c->_f[j] - z);
1485 c->out = c->amp * z;1456 c->out = z;
1486 1457
1487 if (++j == FILLEN)1458 if (++j == FILLEN)
1488 {1459 {
@@ -1505,6 +1476,7 @@ void tMBTriangle_setFreq(tMBTriangle* const osc, float f) · 16 unmodified lines
1505{1476{
1506 _tMBTriangle* c = *osc;1477 _tMBTriangle* c = *osc;
1507 c->freq = f;1478 c->freq = f;
1479 c->_w = c->freq * c->invSampleRate; /* phase increment */
1508}1480}
1509 1481
1510void tMBTriangle_setWidth(tMBTriangle* const osc, float w)1482void tMBTriangle_setWidth(tMBTriangle* const osc, float w)
@@ -1542,10 +1514,10 @@ void tMBTriangle_setSyncMode(tMBTriangle* const osc, int hardOrSoft) · 31 unmodified lines
1542}1514}
1543 1515
1544//useful if you have several oscillators so the buffer refill is not synchronized1516//useful if you have several oscillators so the buffer refill is not synchronized
1545void tMBTriangle_setBufferOffset(tMBTriangle* const osc, int offset)1517void tMBTriangle_setBufferOffset(tMBTriangle* const osc, uint32_t offset)
1546{1518{
1547 _tMBTriangle* c = *osc;1519 _tMBTriangle* c = *osc;
1548 offset = LEAF_clip(0,offset, FILLEN-1);1520 offset = offset & (FILLEN-1);
1549 c->_j = offset;1521 c->_j = offset;
1550}1522}
1551 1523
@@ -1571,8 +1543,6 @@ void tMBSaw_initToPool(tMBSaw* const osc, tMempool* const pool) · 19 unmodified lines
1571 LEAF* leaf = c->mempool->leaf;1543 LEAF* leaf = c->mempool->leaf;
1572 1544
1573 c->invSampleRate = leaf->invSampleRate;1545 c->invSampleRate = leaf->invSampleRate;
1574 c->_init = true;
1575 c->amp = 1.0f;
1576 c->freq = 440.f;1546 c->freq = 440.f;
1577 c->lastsyncin = 0.0f;1547 c->lastsyncin = 0.0f;
1578 c->sync = 0.0f;1548 c->sync = 0.0f;
@@ -1580,6 +1550,9 @@ void tMBSaw_initToPool(tMBSaw* const osc, tMempool* const pool) · 1 unmodified line
1580 c->softsync = 0;1550 c->softsync = 0;
1581 c->_z = 0.0f;1551 c->_z = 0.0f;
1582 c->_j = 0;1552 c->_j = 0;
1553 c->_p = 0.0f; /* phase [0, 1) */
1554 c->_w = c->freq * c->invSampleRate; /* phase increment */
1555
1583 memset (c->_f, 0, (FILLEN + STEP_DD_PULSE_LENGTH) * sizeof (float));1556 memset (c->_f, 0, (FILLEN + STEP_DD_PULSE_LENGTH) * sizeof (float));
1584}1557}
1585 1558
@@ -1594,45 +1567,30 @@ float tMBSaw_tick(tMBSaw* const osc) · 8 unmodified lines
1594 _tMBSaw* c = *osc;1567 _tMBSaw* c = *osc;
1595 1568
1596 int j;1569 int j;
1597 float freq, sync;1570 float sync;
1598 float a, p, w, sw, z;1571 float p, w, sw, z;
1599 1572
1600 sync = c->sync;1573 sync = c->sync;
1601 freq = c->freq;1574
1602 1575
1603 p = c->_p; /* phase [0, 1) */1576 p = c->_p; /* phase [0, 1) */
1604 w = c->_w; /* phase increment */1577 w = c->_w; /* phase increment */
1605 z = c->_z; /* low pass filter state */1578 z = c->_z; /* low pass filter state */
1606 j = c->_j; /* index into buffer _f */1579 j = c->_j; /* index into buffer _f */
1607 1580
1608 if (c->_init) {
1609// p = 0.5f;
1610 p = 0.f;
1611 w = freq * c->invSampleRate;
1612
1613 /* if we valued alias-free startup over low startup time, we could do:
1614 * p -= w;
1615 * place_slope_dd(_f, j, 0.0f, w, -1.0f); */
1616 c->_init = false;
1617 }
1618
1619 //a = 0.2 + 0.8 * vco->_port [FILT];
1620 a = 0.5f; // when a = 1, LPfilter is disabled
1621
1622 w = freq * c->invSampleRate;
1623 1581
1624 if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;1582 if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;
1625 // Should insert minblep for softsync?1583 // Should insert minblep for softsync?
1626 // if (p_at_reset >= 1.0f) {1584 // if (p_at_reset >= 1.0f) {
1627 // p_at_reset -= (int)p_at_reset;1585 // p_at_reset -= (int)p_at_reset;
1628 // place_slope_dd(c->_f, j, p_at_reset + eof_offset, sw, 2.0f);1586 // place_slope_dd(c->_f, j, p_at_reset + eof_offset, sw, 2.0f);
1629 // }1587 // }
1630 // if (p_at_reset < 0.0f) {1588 // if (p_at_reset < 0.0f) {
1631 // p_at_reset += 1.0f - (int)p_at_reset;1589 // p_at_reset += 1.0f - (int)p_at_reset;
1632 // place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, -2.0f);1590 // place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, -2.0f);
1633 // }1591 // }
1634 // if (sw > 0) place_slope_dd(c->_f, j, p, sw, 2.0f);1592 // if (sw > 0) place_slope_dd(c->_f, j, p, sw, 2.0f);
1635 // else if (sw < 0) place_slope_dd(c->_f, j, 1.0f - p, -sw, -2.0f);1593 // else if (sw < 0) place_slope_dd(c->_f, j, 1.0f - p, -sw, -2.0f);
1636 1594
1637 sw = w * c->syncdir;1595 sw = w * c->syncdir;
1638 p += sw - (int)sw;1596 p += sw - (int)sw;
@@ -1670,8 +1628,8 @@ float tMBSaw_tick(tMBSaw* const osc) · 31 unmodified lines
1670 }1628 }
1671 c->_f[j + DD_SAMPLE_DELAY] += 0.5f - p;1629 c->_f[j + DD_SAMPLE_DELAY] += 0.5f - p;
1672 1630
1673 z += a * (c->_f[j] - z); // LP filtering1631 z += 0.5f * (c->_f[j] - z); // LP filtering
1674 c->out = c->amp * z;1632 c->out = z;
1675 1633
1676 if (++j == FILLEN)1634 if (++j == FILLEN)
1677 {1635 {
@@ -1692,6 +1650,8 @@ void tMBSaw_setFreq(tMBSaw* const osc, float f) · 14 unmodified lines
1692{1650{
1693 _tMBSaw* c = *osc;1651 _tMBSaw* c = *osc;
1694 c->freq = f;1652 c->freq = f;
1653
1654 c->_w = c->freq * c->invSampleRate;
1695}1655}
1696 1656
1697float tMBSaw_sync(tMBSaw* const osc, float value)1657float tMBSaw_sync(tMBSaw* const osc, float value)
@@ -1723,10 +1683,10 @@ void tMBSaw_setSyncMode(tMBSaw* const osc, int hardOrSoft) · 25 unmodified lines
1723}1683}
1724 1684
1725//useful if you have several oscillators so the buffer refill is not synchronized1685//useful if you have several oscillators so the buffer refill is not synchronized
1726void tMBSaw_setBufferOffset(tMBSaw* const osc, int offset)1686void tMBSaw_setBufferOffset(tMBSaw* const osc, uint32_t offset)
1727{1687{
1728 _tMBSaw* c = *osc;1688 _tMBSaw* c = *osc;
1729 offset = LEAF_clip(0,offset, FILLEN-1);1689 offset = offset & (FILLEN-1);
1730 c->_j = offset;1690 c->_j = offset;
1731}1691}
1732 1692
@@ -1737,6 +1697,336 @@ void tMBSaw_setSampleRate(tMBSaw* const osc, float sr) · 4 unmodified lines
1737}1697}
1738 1698
1739 1699
1700//==================================================================================================
1701
1702void tMBSawPulse_init(tMBSawPulse* const osc, LEAF* const leaf)
1703{
1704 tMBSawPulse_initToPool(osc, &leaf->mempool);
1705}
1706
1707void tMBSawPulse_initToPool(tMBSawPulse* const osc, tMempool* const pool)
1708{
1709 _tMempool* m = *pool;
1710 _tMBSawPulse* c = *osc = (_tMBSawPulse*) mpool_alloc(sizeof(_tMBSawPulse), m);
1711 c->mempool = m;
1712 LEAF* leaf = c->mempool->leaf;
1713
1714 c->invSampleRate = leaf->invSampleRate;
1715 c->freq = 440.f;
1716 c->lastsyncin = 0.0f;
1717 c->sync = 0.0f;
1718 c->syncdir = 1.0f;
1719 c->softsync = 0;
1720 c->waveform = 0.0f;
1721 c->_z = 0.0f;
1722 c->_j = 0;
1723 c->_p = 0.0f; /* phase [0, 1) */
1724 c->_w = c->freq * c->invSampleRate; /* phase increment */
1725 c->_b = 0.5f * (1.0f + c->waveform); /* duty cycle (0, 1) */
1726 c->_x = 0.5f; /* temporary output variable */
1727 c->_k = 0.0f; /* output state, 0 = high (0.5f), 1 = low (-0.5f) */
1728
1729 memset (c->_f, 0, (FILLEN + STEP_DD_PULSE_LENGTH) * sizeof (float));
1730}
1731
1732void tMBSawPulse_free(tMBSawPulse* const osc)
1733{
1734 _tMBSawPulse* c = *osc;
1735 mpool_free((char*)c, c->mempool);
1736}
1737
1738
1739
1740
1741
1742
1743
1744float tMBSawPulse_tick(tMBSawPulse* const osc)
1745{
1746 _tMBSawPulse* c = *osc;
1747
1748 int j, k;
1749 float sync;
1750 float b, p, w, x, z, sw;
1751 float shape = c->shape;
1752 float sawShape = 1.0f - c->shape;
1753 sync = c->sync;
1754 p = c->_p; /* phase [0, 1) */
1755 w = c->_w; /* phase increment */
1756 b = c->_b; /* duty cycle (0, 1) */
1757 x = c->_x; /* temporary output variable */
1758 z = c->_z; /* low pass filter state */
1759 j = c->_j; /* index into buffer _f */
1760 k = c->_k; /* output state, 0 = high (0.5f), 1 = low (-0.5f) */
1761
1762 if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;
1763
1764 sw = w * c->syncdir;
1765 p += sw - (int)sw;
1766
1767 if (sync > 0.0f && c->softsync == 0)
1768 { /* sync to master */
1769 float eof_offset = sync * sw;
1770 float p_at_reset = p - eof_offset;
1771
1772 if (sw > 0) p = eof_offset;
1773 else if (sw < 0) p = 1.0f - eof_offset;
1774
1775 //pulse stuff
1776 /* place any DDs that may have occurred in subsample before reset */
1777 if (!k)
1778 {
1779 if (sw > 0)
1780 {
1781 if (p_at_reset >= b)
1782 {
1783 place_step_dd(c->_f, j, p_at_reset - b + eof_offset, sw, -1.0f * shape);
1784 k = 1;
1785 x = -0.5f;
1786 }
1787 if (p_at_reset >= 1.0f)
1788 {
1789 p_at_reset -= 1.0f;
1790 place_step_dd(c->_f, j, p_at_reset + eof_offset, sw, 1.0f);
1791 k = 0;
1792 x = 0.5f;
1793 }
1794 }
1795 else if (sw < 0)
1796 {
1797 if (p_at_reset < 0.0f)
1798 {
1799 p_at_reset += 1.0f;
1800 place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, -1.0f);
1801 k = 1;
1802 x = -0.5f;
1803 }
1804 if (k && p_at_reset < b)
1805 {
1806 place_step_dd(c->_f, j, b - p_at_reset - eof_offset, -sw, 1.0f * shape);
1807 k = 0;
1808 x = 0.5f;
1809 }
1810 }
1811 }
1812 else
1813 {
1814 if (sw > 0)
1815 {
1816 if (p_at_reset >= 1.0f)
1817 {
1818 p_at_reset -= 1.0f;
1819 place_step_dd(c->_f, j, p_at_reset + eof_offset, sw, 1.0f);
1820 k = 0;
1821 x = 0.5f;
1822 }
1823 if (!k && p_at_reset >= b)
1824 {
1825 place_step_dd(c->_f, j, p_at_reset - b + eof_offset, sw, -1.0f * shape);
1826 k = 1;
1827 x = -0.5f;
1828 }
1829 }
1830 else if (sw < 0)
1831 {
1832 if (p_at_reset < b)
1833 {
1834 place_step_dd(c->_f, j, b - p_at_reset - eof_offset, -sw, 1.0f * shape);
1835 k = 0;
1836 x = 0.5f;
1837 }
1838 if (p_at_reset < 0.0f)
1839 {
1840 p_at_reset += 1.0f;
1841 place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, -1.0f);
1842 k = 1;
1843 x = -0.5f;
1844 }
1845 }
1846 }
1847
1848
1849 /* now place reset DD for pulse */
1850 if (sw > 0)
1851 {
1852 if (k) {
1853 place_step_dd(c->_f, j, p, sw, 1.0f * shape);
1854 k = 0;
1855 x = 0.5f;
1856 }
1857 if (p >= b) {
1858 place_step_dd(c->_f, j, p - b, sw, -1.0f * shape);
1859 k = 1;
1860 x = -0.5f;
1861 }
1862 }
1863 else if (sw < 0)
1864 {
1865 if (!k) {
1866 place_step_dd(c->_f, j, 1.0f - p, -sw, -1.0f * shape);
1867 k = 1;
1868 x = -0.5f;
1869 }
1870 if (p < b) {
1871 place_step_dd(c->_f, j, b - p, -sw, 1.0f * shape);
1872 k = 0;
1873 x = 0.5f;
1874 }
1875 }
1876 /* now place reset DD for saw*/
1877 if (sw > 0)
1878 place_step_dd(c->_f, j, p, sw, p_at_reset * sawShape);
1879 else if (sw < 0)
1880 place_step_dd(c->_f, j, 1.0f - p, -sw, -p_at_reset * sawShape);
1881
1882 }
1883
1884
1885 else if (!k)
1886 { /* normal operation for pulse, signal currently high */
1887
1888 if (sw > 0)
1889 {
1890 if (p >= b) {
1891 place_step_dd(c->_f, j, p - b, sw, -1.0f * shape);
1892 k = 1;
1893 x = -0.5f;
1894 }
1895 if (p >= 1.0f) {
1896 p -= 1.0f;
1897 place_step_dd(c->_f, j, p, sw, 1.0f);
1898 k = 0;
1899 x = 0.5f;
1900 }
1901 }
1902 else if (sw < 0)
1903 {
1904 if (p < 0.0f) {
1905 p += 1.0f;
1906 place_step_dd(c->_f, j, 1.0f - p, -sw, -1.0f);
1907 k = 1;
1908 x = -0.5f;
1909 }
1910 if (k && p < b) {
1911 place_step_dd(c->_f, j, b - p, -sw, 1.0f * shape);
1912 k = 0;
1913 x = 0.5f;
1914 }
1915 }
1916
1917 } else { /* normal operation, signal currently low */
1918
1919 if (sw > 0)
1920 {
1921 if (p >= 1.0f) {
1922 p -= 1.0f;
1923 place_step_dd(c->_f, j, p, sw, 1.0f);
1924 k = 0;
1925 x = 0.5f;
1926 }
1927 if (!k && p >= b) {
1928 place_step_dd(c->_f, j, p - b, sw, -1.0f * shape);
1929 k = 1;
1930 x = -0.5f;
1931 }
1932 }
1933 else if (sw < 0)
1934 {
1935 if (p < b) {
1936 place_step_dd(c->_f, j, b - p, -sw, 1.0f * shape);
1937 k = 0;
1938 x = 0.5f;
1939 }
1940 if (p < 0.0f) {
1941 p += 1.0f;
1942 place_step_dd(c->_f, j, 1.0f - p, -sw, -1.0f);
1943 k = 1;
1944 x = -0.5f;
1945 }
1946 }
1947 }
1948
1949 c->_f[j + DD_SAMPLE_DELAY] += ((0.5f - p) * sawShape); //saw
1950
1951 c->_f[j + DD_SAMPLE_DELAY] += (x * shape);//pulse
1952
1953 z += 0.5f * (c->_f[j] - z); // LP filtering
1954 c->out = z;
1955
1956 if (++j == FILLEN)
1957 {
1958 j = 0;
1959 memcpy (c->_f, c->_f + FILLEN, STEP_DD_PULSE_LENGTH * sizeof (float));
1960 memset (c->_f + STEP_DD_PULSE_LENGTH, 0, FILLEN * sizeof (float));
1961 }
1962
1963 c->_p = p;
1964 c->_w = w;
1965 c->_b = b;
1966 c->_x = x;
1967 c->_z = z;
1968 c->_j = j;
1969 c->_k = k;
1970
1971 return -c->out;
1972}
1973
1974void tMBSawPulse_setFreq(tMBSawPulse* const osc, float f)
1975{
1976 _tMBSawPulse* c = *osc;
1977 c->freq = f;
1978 c->_w = c->freq * c->invSampleRate; /* phase increment */
1979}
1980
1981float tMBSawPulse_sync(tMBSawPulse* const osc, float value)
1982{
1983 _tMBSawPulse* c = *osc;
1984
1985 //based on https://github.com/VCVRack/Fundamental/blob/5799ee2a9b21492b42ebcb9b65d5395ef5c1cbe2/src/VCO.cpp#L123
1986 float last = c->lastsyncin;
1987 float delta = value - last;
1988 float crossing = -last / delta;
1989 c->lastsyncin = value;
1990 if ((0.f < crossing) && (crossing <= 1.f) && (value >= 0.f))
1991 c->sync = (1.f - crossing) * delta;
1992 else c->sync = 0.f;
1993
1994 return value;
1995}
1996
1997void tMBSawPulse_setPhase(tMBSawPulse* const osc, float phase)
1998{
1999 _tMBSawPulse* c = *osc;
2000 c->_p = phase;
2001}
2002
2003void tMBSawPulse_setShape(tMBSawPulse* const osc, float shape)
2004{
2005 _tMBSawPulse* c = *osc;
2006 c->shape = shape;
2007}
2008
2009void tMBSawPulse_setSyncMode(tMBSawPulse* const osc, int hardOrSoft)
2010{
2011 _tMBSawPulse* c = *osc;
2012 c->softsync = hardOrSoft > 0 ? 1 : 0;
2013}
2014
2015//useful if you have several oscillators so the buffer refill is not synchronized
2016void tMBSawPulse_setBufferOffset(tMBSawPulse* const osc, uint32_t offset)
2017{
2018 _tMBSawPulse* c = *osc;
2019 offset = offset & (FILLEN-1);
2020 c->_j = offset;
2021}
2022
2023void tMBSawPulse_setSampleRate(tMBSawPulse* const osc, float sr)
2024{
2025 _tMBSawPulse* c = *osc;
2026 c->invSampleRate = 1.0f/sr;
2027}
2028
2029
1740// WaveTable2030// WaveTable
1741void tTable_init(tTable* const cy, float* waveTable, int size, LEAF* const leaf)2031void tTable_init(tTable* const cy, float* waveTable, int size, LEAF* const leaf)
1742{2032{

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t