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