shithub: leaf

Download patch

ref: 9368ed952223b1e15427cbbf8860700ae02ce8e6
parent: b0f54b934de962a04c77ec53da5d6916ea150843
author: Jeff Snyder <jeff@snyderphonics.com>
date: Thu Feb 21 06:21:45 EST 2019

added bitcrusher to master branch

--- /dev/null
+++ b/LEAF/Inc/leaf-crusher.h
@@ -1,0 +1,64 @@
+/*
+  ==============================================================================
+
+    leaf-crusher.h
+    Created: 7 Feb 2019 10:58:22am
+    Author:  airship
+
+  ==============================================================================
+*/
+
+#ifndef LEAF_CRUSHER_H_INCLUDED
+#define LEAF_CRUSHER_H_INCLUDED
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-globals.h"
+#include "leaf-math.h"
+
+//==============================================================================
+
+typedef struct _tCrusher
+{
+    float srr;
+    float mult, div;
+    float rnd;
+
+    uint32_t  op; //which bitwise operation (0-7)
+
+    float gain;
+
+} tCrusher;
+
+
+void    tCrusher_init    (tCrusher* const);
+void    tCrusher_free    (tCrusher* const);
+
+float   tCrusher_tick    (tCrusher* const, float input);
+
+// 0.0 - 1.0
+void    tCrusher_setOperation (tCrusher* const, float op);
+
+// 0.0 - 1.0
+void    tCrusher_setQuality (tCrusher* const, float val);
+
+// what division to round to
+void    tCrusher_setRound (tCrusher* const, float rnd);
+
+// sampling ratio
+void    tCrusher_setSamplingRatio (tCrusher* const, float ratio);
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_WAVEFOLDER_H_INCLUDED
+
+//==============================================================================
--- a/LEAF/Inc/leaf-globals.h
+++ b/LEAF/Inc/leaf-globals.h
@@ -48,6 +48,13 @@
 #define     DELAY_LENGTH        16000   // The maximum delay length of all Delay/DelayL/DelayA components.
                                             // Feel free to change to suit memory constraints or desired delay max length / functionality.
 
-#define TALKBOX_BUFFER_LENGTH   1600    // Every talkbox instance introduces 5 buffers of this size
+//#define TALKBOX_BUFFER_LENGTH   1600    // Every talkbox instance introduces 5 buffers of this size
+
+
+union unholy_t { /* a union between a float and an integer */
+    float f;
+    int i;
+};
+
 
 #endif  // OPPSGLOBALS_H_INCLUDED
--- a/LEAF/Inc/leaf-math.h
+++ b/LEAF/Inc/leaf-math.h
@@ -1,20 +1,24 @@
-/*
-  ==============================================================================
+/*==============================================================================
 
-    LEAFMath.h
+    leaf-math.h
     Created: 22 Jan 2017 7:02:56pm
     Author:  Michael R Mulshine
 
-  ==============================================================================
-*/
+==============================================================================*/
 
-#ifndef LEAFMATH_H_INCLUDED
-#define LEAFMATH_H_INCLUDED
+#ifndef LEAF_MATH_H_INCLUDED
+#define LEAF_MATH_H_INCLUDED
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "math.h"
 #include "stdint.h"
 #include "stdlib.h"
 
+//==============================================================================
+
 typedef enum oBool
 {
     OTRUE  = 1,
@@ -74,16 +78,21 @@
 float LEAF_shaper     (float input, float m_drive);
 float LEAF_reedTable  (float input, float offset, float slope);
 
+float LEAF_reduct (float input, float ratio);
+float LEAF_round (float input, float rnd);
+float LEAF_bitwise_xor(float input, uint32_t op);
+
 float       LEAF_clip               (float min, float val, float max);
-float   	LEAF_softClip						(float val, float thresh);
-oBool       LEAF_isPrime            (uint64_t number );
+int         LEAF_clipInt            (int min, int val, int max);
+float   	LEAF_softClip		    (float val, float thresh);
+oBool       LEAF_isPrime            (uint64_t number );
 
-float       LEAF_midiToFrequency    (float f);
-float       LEAF_frequencyToMidi(float f);
-
-void        LEAF_generate_sine     (float* buffer, int size);
-void        LEAF_generate_sawtooth (float* buffer, float basefreq, int size);
-void        LEAF_generate_triangle (float* buffer, float basefreq, int size);
+float       LEAF_midiToFrequency    (float f);
+float       LEAF_frequencyToMidi(float f);
+
+void        LEAF_generate_sine     (float* buffer, int size);
+void        LEAF_generate_sawtooth (float* buffer, float basefreq, int size);
+void        LEAF_generate_triangle (float* buffer, float basefreq, int size);
 void        LEAF_generate_square   (float* buffer, float basefreq, int size);
 
 // dope af
@@ -90,54 +99,28 @@
 float       LEAF_chebyshevT(float in, int n);
 float       LEAF_CompoundChebyshevT(float in, int n, float* amps);
 
-static inline float interpolate3max(float *buf, const int peakindex)
-{
-    float a = buf[peakindex-1];
-    float b = buf[peakindex];
-    float c = buf[peakindex+1];
-    float realpeak;
-    
-    realpeak = b + (float)0.125 * (c - a) * (c - a) / ((float)2. * b - a - c);
-    
-    return(realpeak);
-}
 
-static inline float interpolate3phase(float *buf, const int peakindex)
-{
-    float a = buf[peakindex-1];
-    float b = buf[peakindex];
-    float c = buf[peakindex+1];
-    float fraction;
-    
-    fraction = ((float)0.5 * (c - a)) / ((float)2. * b - a - c);
-    
-    return(fraction);
-}
+// Hermite interpolation
+float LEAF_interpolate_hermite (float A, float B, float C, float D, float t);
+float LEAF_interpolation_linear (float A, float B, float t);
 
+float interpolate3max(float *buf, const int peakindex);
+float interpolate3phase(float *buf, const int peakindex);
+
 // alternative implementation for abs()
 // REQUIRES: 32 bit integers
-static inline int fastabs_int(int in){
-    unsigned int r;
-    int const mask = in >> 31;
-    
-    r = (in ^ mask) - mask;
-    
-    return (r);
-}
+int fastabs_int(int in);
 
 // alternative implementation for abs()
 // REQUIRES: 32 bit floats
-static inline float fastabs(float f)
-{
-    union
-    {
-        float f;
-        unsigned int ui;
-    }alias;
+float fastabs(float f);
+
+//==============================================================================
     
-    alias.f = f;
-    alias.ui &= 0x7fffffff;
-    return alias.f;
+#ifdef __cplusplus
 }
+#endif
 
-#endif  // LEAFMATH_H_INCLUDED
+#endif  // LEAF_MATH_H_INCLUDED
+
+//==============================================================================
--- /dev/null
+++ b/LEAF/Src/leaf-crusher.c
@@ -1,0 +1,84 @@
+/*==============================================================================
+
+    leaf-crusher.c
+    Created: 30 Nov 2018 11:56:49am
+    Author:  airship
+
+==============================================================================*/
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-crusher.h"
+
+#else
+
+#include "../Inc/leaf-crusher.h"
+
+#endif
+
+//==============================================================================
+
+#define SCALAR 5000.f
+
+void    tCrusher_init    (tCrusher* const c)
+{
+    c->op = 4;
+    c->div = SCALAR;
+    c->rnd = 0.25f;
+    c->srr = 0.25f;
+
+    c->gain = (c->div / SCALAR) * 0.7f + 0.3f;
+}
+
+void    tCrusher_free    (tCrusher* const c)
+{
+    leaf_free(c);
+}
+
+float   tCrusher_tick    (tCrusher* const c, float input)
+{
+    float sample = input;
+
+    sample *= SCALAR; // SCALAR is 5000 by default
+
+    sample = (int32_t) sample;
+
+    sample /= c->div;
+
+    sample = LEAF_bitwise_xor(sample, c->op << 23);
+
+    sample = LEAF_clip(-1.f, sample, 1.f);
+
+    sample = LEAF_round(sample, c->rnd);
+
+    sample = LEAF_reduct(sample, c->srr);
+
+    return sample * c->gain;
+
+}
+
+void    tCrusher_setOperation (tCrusher* const c, float op)
+{
+	c->op = (uint32_t) (op * 8.0f);
+}
+
+// 0.0 - 1.0
+void    tCrusher_setQuality (tCrusher* const c, float val)
+{
+    val = LEAF_clip(0.0f, val, 1.0f);
+
+    c->div = 0.01f + val * SCALAR;
+
+    c->gain = (c->div / SCALAR) * 0.7f + 0.3f;
+}
+
+// what decimal to round to
+void    tCrusher_setRound (tCrusher* const c, float rnd)
+{
+    c->rnd = fabsf(rnd);
+}
+
+void    tCrusher_setSamplingRatio (tCrusher* const c, float ratio)
+{
+    c->srr = ratio;
+}
--- a/LEAF/Src/leaf-math.c
+++ b/LEAF/Src/leaf-math.c
@@ -1,12 +1,10 @@
-/*
-  ==============================================================================
+/*==============================================================================
 
-    LEAFMath.c
+    leaf-math.c
     Created: 22 Jan 2017 7:02:56pm
     Author:  Michael R Mulshine
 
-  ==============================================================================
-*/
+==============================================================================*/
 
 #if _WIN32 || _WIN64
 
@@ -26,9 +24,56 @@
 #define EXPONENTIAL_TABLE_SIZE 65536
 
 
+float interpolate3max(float *buf, const int peakindex)
+{
+    float a = buf[peakindex-1];
+    float b = buf[peakindex];
+    float c = buf[peakindex+1];
+    float realpeak;
 
+    realpeak = b + (float)0.125 * (c - a) * (c - a) / ((float)2. * b - a - c);
 
+    return(realpeak);
+}
 
+float interpolate3phase(float *buf, const int peakindex)
+{
+    float a = buf[peakindex-1];
+    float b = buf[peakindex];
+    float c = buf[peakindex+1];
+    float fraction;
+
+    fraction = ((float)0.5 * (c - a)) / ((float)2. * b - a - c);
+
+    return(fraction);
+}
+
+// alternative implementation for abs()
+// REQUIRES: 32 bit integers
+int fastabs_int(int in){
+    unsigned int r;
+    int const mask = in >> 31;
+
+    r = (in ^ mask) - mask;
+
+    return (r);
+}
+
+// alternative implementation for abs()
+// REQUIRES: 32 bit floats
+float fastabs(float f)
+{
+    union
+    {
+        float f;
+        unsigned int ui;
+    }alias;
+
+    alias.f = f;
+    alias.ui &= 0x7fffffff;
+    return alias.f;
+}
+
 // dope af
 float LEAF_chebyshevT(float in, int n){
 	if (n == 0) return 1;
@@ -74,6 +119,45 @@
     return shaperOut;
 }
 
+// reduce sample resolution
+float hold = 0.f;
+int reduct_count = 0;
+
+
+float LEAF_reduct (float input, float ratio)
+{
+    reduct_count++;
+    if (reduct_count > 1.f / ratio)
+    {
+        hold = input;
+        reduct_count = 0;
+    }
+
+    return hold;
+}
+
+// round input to nearest rnd
+float LEAF_round (float input, float rnd)
+{
+    rnd = fabsf(rnd);
+
+    if (rnd <= 0.0000001f) return input;
+
+    float scale = 1.f / rnd;
+
+    return roundf(input * scale) / scale;
+}
+
+union unholy_t unholy;
+
+float LEAF_bitwise_xor(float input, uint32_t op)
+{
+    unholy.f = input;
+    unholy.i = (unholy.i ^ op);
+
+    return unholy.f;
+}
+
 float LEAF_reedTable(float input, float offset, float slope) 
 {
     float output = offset + (slope * input);
@@ -114,6 +198,18 @@
     }
 }
 
+int   LEAF_clipInt(int min, int val, int max)
+{
+    if (val < min) {
+        return min;
+    } else if (val > max) {
+        return max;
+    } else {
+        return val;
+    }
+}
+
+
 oBool     LEAF_isPrime(uint64_t number )
 {
     if ( number == 2 ) return OTRUE;
@@ -136,92 +232,92 @@
     else
         return x * ( 27 + x * x ) / ( 27 + 9 * x * x );
 }
-
-
-void LEAF_generate_sine(float* buffer, int size)
-{
-    float phase;
-    for (int i = 0; i < size; i++)
-    {
-        phase = (float) i / (float) size;
-        buffer[i] = sinf(phase * TWO_PI);
-    }
-}
-
-void LEAF_generate_sawtooth(float* buffer, float basefreq, int size)
-{
-    int harmonic = 1;
-    float phase = 0.0f;
-    float freq = harmonic * basefreq;
-    float amp;
-    
-    while (freq < (leaf.sampleRate * 0.5))
-    {
-        amp = 1.0f / harmonic;
-        for (int i = 0; i < size; i++)
-        {
-            phase = (float) i / (float) size;
-            buffer[i] += (amp * sinf(harmonic * phase * TWO_PI));
-        }
-        
-        harmonic++;
-        freq = harmonic * basefreq;
-    }
-}
-
-
-void LEAF_generate_triangle(float* buffer, float basefreq, int size)
-{
-    int harmonic = 1;
-    float phase = 0.0f;
-    float freq = harmonic * basefreq;
-    float amp = 1.0f;
-    
-    int count = 0;
-    float mult = 1.0f;
-    
-    while (freq < (leaf.sampleRate * 0.5))
-    {
-        amp = 1.0f / (float)(harmonic * harmonic);
-        
-        if (count % 2)  mult = -1.0f;
-        else            mult =  1.0f;
-        
-        for (int i = 0; i < size; i++)
-        {
-            phase = (float) i / (float) size;
-            buffer[i] += (mult * amp * sinf(harmonic * phase * TWO_PI));
-        }
-        
-        count++;
-        harmonic += 2;
-        freq = harmonic * basefreq;
-    }
-}
-
-void LEAF_generate_square(float* buffer, float basefreq, int size)
-{
-    int harmonic = 1;
-    float phase = 0.0f;
-    float freq = harmonic * basefreq;
-    float amp = 1.0f;
-    
-    while (freq < (leaf.sampleRate * 0.5))
-    {
-        amp = 1.0f / (float)(harmonic);
-        
-        for (int i = 0; i < size; i++)
-        {
-            phase = (float) i / (float) size;
-            buffer[i] += (amp * sinf(harmonic * phase * TWO_PI));
-        }
-        
-        harmonic += 2;
-        freq = harmonic * basefreq;
-    }
-}
-
 
+
+void LEAF_generate_sine(float* buffer, int size)
+{
+    float phase;
+    for (int i = 0; i < size; i++)
+    {
+        phase = (float) i / (float) size;
+        buffer[i] = sinf(phase * TWO_PI);
+    }
+}
+
+void LEAF_generate_sawtooth(float* buffer, float basefreq, int size)
+{
+    int harmonic = 1;
+    float phase = 0.0f;
+    float freq = harmonic * basefreq;
+    float amp;
+    
+    while (freq < (leaf.sampleRate * 0.5))
+    {
+        amp = 1.0f / harmonic;
+        for (int i = 0; i < size; i++)
+        {
+            phase = (float) i / (float) size;
+            buffer[i] += (amp * sinf(harmonic * phase * TWO_PI));
+        }
+        
+        harmonic++;
+        freq = harmonic * basefreq;
+    }
+}
+
+
+void LEAF_generate_triangle(float* buffer, float basefreq, int size)
+{
+    int harmonic = 1;
+    float phase = 0.0f;
+    float freq = harmonic * basefreq;
+    float amp = 1.0f;
+    
+    int count = 0;
+    float mult = 1.0f;
+    
+    while (freq < (leaf.sampleRate * 0.5))
+    {
+        amp = 1.0f / (float)(harmonic * harmonic);
+        
+        if (count % 2)  mult = -1.0f;
+        else            mult =  1.0f;
+        
+        for (int i = 0; i < size; i++)
+        {
+            phase = (float) i / (float) size;
+            buffer[i] += (mult * amp * sinf(harmonic * phase * TWO_PI));
+        }
+        
+        count++;
+        harmonic += 2;
+        freq = harmonic * basefreq;
+    }
+}
+
+void LEAF_generate_square(float* buffer, float basefreq, int size)
+{
+    int harmonic = 1;
+    float phase = 0.0f;
+    float freq = harmonic * basefreq;
+    float amp = 1.0f;
+    
+    while (freq < (leaf.sampleRate * 0.5))
+    {
+        amp = 1.0f / (float)(harmonic);
+        
+        for (int i = 0; i < size; i++)
+        {
+            phase = (float) i / (float) size;
+            buffer[i] += (amp * sinf(harmonic * phase * TWO_PI));
+        }
+        
+        harmonic += 2;
+        freq = harmonic * basefreq;
+    }
+}
+
+
 //-----------------------------------------------------------------------------
 // name: mtof()
 // desc: midi to freq, from PD source
@@ -230,5 +326,34 @@
 {
     if( f <= -1500.0f ) return (0);
     else if( f > 1499.0f ) return (LEAF_midiToFrequency(1499.0f));
-    else return ( powf(2.0f, (f - 69.0f) / 12.0f) * 440.0f );
+    else return ( powf(2.0f, (f - 69.0f) * 0.083333333333333f) * 440.0f );
+}
+
+
+// alpha, [0.0, 1.0]
+float LEAF_interpolate_hermite (float A, float B, float C, float D, float alpha)
+{
+    alpha = LEAF_clip(0.0f, alpha, 1.0f);
+
+    float a = -A/2.0f + (3.0f*B)/2.0f - (3.0f*C)/2.0f + D/2.0f;
+    float b = A - (5.0f*B)/2.0f + 2.0f*C - D / 2.0f;
+    float c = -A/2.0f + C/2.0f;
+    float d = B;
+
+    return a*alpha*alpha*alpha + b*alpha*alpha + c*alpha + d;
+}
+
+// alpha, [0.0, 1.0]
+float LEAF_interpolation_linear (float A, float B, float alpha)
+{
+    alpha = LEAF_clip(0.0f, alpha, 1.0f);
+
+    float omAlpha = 1.0f - alpha;
+
+    // First 1/2 of interpolation
+    float out = A * omAlpha;
+
+    out += B * alpha;
+
+    return out;
 }
--- a/LEAF/leaf.h
+++ b/LEAF/leaf.h
@@ -28,6 +28,7 @@
 #include ".\Inc\leaf-midi.h"
 #include ".\Inc\leaf-wavefolder.h"
 #include ".\Inc\leaf-wavetables.h"
+#include ".\Inc\leaf-crusher.h"
 
 #else
 
@@ -46,6 +47,7 @@
 #include "./Inc/leaf-midi.h"
 #include "./Inc/leaf-wavefolder.h"
 #include "./Inc/leaf-wavetables.h"
+#include "./Inc/leaf-crusher.h"
 
 #endif