aboutsummaryrefslogtreecommitdiff
path: root/valverect~.c
blob: 37ac5369d81d833752e33e84d5000b8ec608e737 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// sigpack
// for
// pure-data
// by weiss
// www.weiss-archive.de

#include "m_pd.h"
#include <math.h>
#include <string.h>
#include <stdint.h>
#ifdef _MSC_VER
#pragma warning( disable : 4244 )
#pragma warning( disable : 4305 )
#endif

// ------------------------ valverect~ ----------------------------- 
// valve rectifier
// code from swh_plugins by steve harris www.plugin.org.uk 

// 1.0 / ln(2)
#define LN2R 1.442695041f
/* Fast exponentiation function, y = e^x */
#define f_exp(x) f_pow2(x * LN2R) 

static t_class *valverect_tilde_class;

typedef struct _valverect_tilde
{
    t_object x_obj;
	t_sample x_sag;//sag level[0-1]
	t_sample x_dist_p;//distortion[0-1]
	unsigned int x_apos;
	float *x_avg;
	int x_avg_size;
	float x_avg_sizer;
	float x_avgs;
	float x_lp1tm1;
	float x_lp2tm1;
	float x_s_rate;
	float x_f;
} t_valverect_tilde;

static void *valverect_tilde_new(t_floatarg sag, t_floatarg dist)
{
    t_valverect_tilde *x = (t_valverect_tilde *)pd_new(valverect_tilde_class);
	x->x_sag = sag;
	x->x_dist_p = dist;
    outlet_new(&x->x_obj, gensym("signal"));
	floatinlet_new(&x->x_obj, &x->x_sag);
	floatinlet_new(&x->x_obj, &x->x_dist_p);
	x->x_s_rate = sys_getsr();
	x->x_avg_size = x->x_s_rate / 9;//number of samples in averaging buffer
	x->x_avg_sizer = 9.0f / x->x_s_rate;//reciprocal of above
	x->x_avg = (float *)getbytes(x->x_avg_size * sizeof(float));//averaging buffer
	memset(x->x_avg, 0, x->x_avg_size * sizeof(float));
	x->x_avgs = 0.0f;//sum of samples in averaging buffer
	x->x_apos = 0;//position in averaging buffer
	x->x_lp1tm1 = 0.0f;//last value in lowpass 1
	x->x_lp2tm1 = 0.0f;//last value in lowpass 2
	x->x_f = 0;
	if (sag) x->x_sag = sag;
	else x->x_sag = 0.0;
	if (dist) x->x_dist_p = dist;
	else x->x_dist_p = 0.0;
    return (x);
}

/* Andrew Simper's pow(2, x) aproximation from the music-dsp list */

/* 32 bit "pointer cast" union */
typedef union {
        float f;
        int32_t i;
} ls_pcast32;

/* union version */
static inline float f_pow2(float x)
{
        ls_pcast32 *px, tx, lx;
        float dx;

        px = (ls_pcast32 *)&x; // store address of float as long pointer
        tx.f = (x-0.5f) + (3<<22); // temporary value for truncation
        lx.i = tx.i - 0x4b400000; // integer power of 2
        dx = x - (float)lx.i; // float remainder of power of 2

        x = 1.0f + dx * (0.6960656421638072f + // cubic apporoximation of 2^x
                   dx * (0.224494337302845f +  // for x in the range [0, 1]
                   dx * (0.07944023841053369f)));
        (*px).i += (lx.i << 23); // add integer power of 2 to exponent

        return (*px).f;
}

static t_int *valverect_tilde_perform(t_int *w)
{
	t_valverect_tilde *x = (t_valverect_tilde *)(w[1]);
    t_float *in = (t_float *)(w[2]);
    t_float *out = (t_float *)(w[3]);
    int n = (int)(w[4]);
	float abs, q, fx;
	const float dist = x->x_dist_p * 40.0f + 0.1f;
	float f;
    while (n--)
    {
		f = *in++;
		abs = fabs(f);
		if(abs > x->x_lp1tm1) {
			x->x_lp1tm1 = abs;
		}
		else {
			x->x_lp1tm1 = 0.9999f * x->x_lp1tm1 + 0.0001f * abs;
		}
		x->x_avgs -= x->x_avg[x->x_apos];
		x->x_avgs += x->x_lp1tm1;
		x->x_avg[x->x_apos] = x->x_lp1tm1;
		x->x_apos %= x->x_avg_size;

		x->x_lp2tm1 = 0.999f * x->x_lp2tm1 + x->x_avgs * x->x_avg_sizer * 0.001f;
		q = x->x_lp1tm1 * x->x_sag - x->x_lp2tm1 * 1.02f - 1.0f;
		if(q > -0.01f) {
			q = -0.01f;
		}
		else if(q < -1.0f) {
			q = -1.0f;
		}

		if(f == q) {
			fx = 1.0f / dist + q / (1.0f - f_exp(dist * q));
		}
		else {
			fx = (f - q) / (1.0f - f_exp(-dist * (f - q))) + q / (1.0f - f_exp(dist * q));
		}
		*out++ = fx;
    }
    return (w+5);
}

static void valverect_tilde_dsp(t_valverect_tilde *x, t_signal **sp)
{
    dsp_add(valverect_tilde_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
}

static void valverect_tilde_free(t_valverect_tilde *x)
{
	freebytes(x->x_avg, x->x_avg_size * sizeof(float));
}

void valverect_tilde_setup(void)
{
    valverect_tilde_class = class_new(gensym("valverect~"), (t_newmethod)valverect_tilde_new, (t_method)valverect_tilde_free,
    	sizeof(t_valverect_tilde), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
    CLASS_MAINSIGNALIN(valverect_tilde_class, t_valverect_tilde, x_f);
    class_addmethod(valverect_tilde_class, (t_method)valverect_tilde_dsp, gensym("dsp"), 0);
}