aboutsummaryrefslogtreecommitdiff
path: root/cyclone/sickle/linedrive.c
blob: 99c37201249c73f3f8958f3977d09e8e52adb82b (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
/* Copyright (c) 2002-2005 krzYszcz and others.
 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
 * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

#include <math.h>
#include "m_pd.h"
#include "common/fitter.h"

#if defined(NT) || defined(MACOSX)
#define logf  log
#define expf  exp
#endif

#define LINEDRIVE_MININPUT   .5  /* CHECKED */
#define LINEDRIVE_MINCURVE  1.   /* CHECKED */

#define LINEDRIVE_INPUTEPSILON  1e-19f
#define LINEDRIVE_CURVEEPSILON  1e-19f

typedef struct _linedrive
{
    t_object  x_ob;
    t_float   x_usermaxin;
    t_float   x_usermaxout;
    t_float   x_usercurve;
    t_float   x_maxin;
    t_float   x_maxout;
    t_float   x_expcoef;
    t_float   x_lincoef;
    int       x_islinear;
    int       x_iscompatible;
    t_atom    x_outvec[2];
} t_linedrive;

static t_class *linedrive_class;

static void linedrive_float(t_linedrive *x, t_floatarg f)
{
    t_float outval;
    if (x->x_iscompatible)
    {
	if (f < LINEDRIVE_MININPUT)  /* CHECKED */
	    outval = 0.;
	else if (f >= x->x_maxin)  /* CHECKED */
	    outval = x->x_maxin;
	else
	    outval = expf((f - x->x_maxin) * x->x_expcoef) * x->x_maxout;
    }
    else
    {
	if (x->x_islinear)
	    outval = x->x_maxout + (f - x->x_maxin) * x->x_lincoef;
	else if (f < -LINEDRIVE_INPUTEPSILON)
	    outval = -expf((-f - x->x_maxin) * x->x_expcoef) * x->x_maxout;
	else if (f > LINEDRIVE_INPUTEPSILON)
	    outval = expf((f - x->x_maxin) * x->x_expcoef) * x->x_maxout;
	else
	    outval = 0.;
    }
    SETFLOAT(x->x_outvec, outval);
    outlet_list(((t_object *)x)->ob_outlet, 0, 2, x->x_outvec);
}

static void linedrive_calculate(t_linedrive *x)
{
    t_float maxin = x->x_usermaxin;
    t_float maxout = x->x_usermaxout;
    t_float curve = x->x_usercurve;
    if (x->x_iscompatible = fittermax_get())
    {
	/* CHECKED */
	x->x_maxin = (maxin > LINEDRIVE_MININPUT ? maxin : LINEDRIVE_MININPUT);
	/* CHECKED */
	x->x_expcoef = (curve > LINEDRIVE_MINCURVE ? logf(curve) : 0.);
	x->x_lincoef = 0.;
	x->x_islinear = 0;
    }
    else
    {
	if (maxin >= -LINEDRIVE_INPUTEPSILON && maxin <= LINEDRIVE_INPUTEPSILON)
	{
	    x->x_maxin = 0.;
	    x->x_expcoef = 0.;
	    x->x_lincoef = 0.;
	    x->x_islinear = 1;
	}
	else if (curve >= (1. - LINEDRIVE_CURVEEPSILON) &&
		 curve <= (1. + LINEDRIVE_CURVEEPSILON))
	{
	    x->x_maxin = maxin;
	    x->x_expcoef = 0.;
	    x->x_lincoef = maxout / maxin;
	    x->x_islinear = 1;
	}
	else
	{
	    if (maxin < 0.)
	    {
		x->x_maxin = -maxin;
		maxout = -maxout;
	    }
	    else x->x_maxin = maxin;
	    if (curve < LINEDRIVE_CURVEEPSILON)
		curve = LINEDRIVE_CURVEEPSILON;
	    x->x_expcoef = logf(curve);
	    x->x_lincoef = 0.;
	    x->x_islinear = 0;
	}
    }
    x->x_maxout = maxout;  /* CHECKED negative value accepted and used */
}

static void *linedrive_new(t_floatarg maxin, t_floatarg maxout,
			   t_floatarg curve, t_floatarg deltime)
{
    t_linedrive *x = (t_linedrive *)pd_new(linedrive_class);
    x->x_usermaxin = maxin;
    x->x_usermaxout = maxout;
    x->x_usercurve = curve;
    linedrive_calculate(x);
    SETFLOAT(&x->x_outvec[1], deltime);  /* CHECKED any value accepted */
    floatinlet_new((t_object *)x, &x->x_outvec[1].a_w.w_float);
    outlet_new((t_object *)x, &s_list);
    return (x);
}

static void linedrive_fitter(void)
{
    /* FIXME for all objects in scope do recalculate */
}

void linedrive_setup(void)
{
    linedrive_class = class_new(gensym("linedrive"),
				(t_newmethod)linedrive_new, 0,
				sizeof(t_linedrive), 0,
				A_DEFFLOAT, A_DEFFLOAT,
				A_DEFFLOAT, A_DEFFLOAT, 0);
    class_addfloat(linedrive_class, linedrive_float);
    fitter_setup(linedrive_class, linedrive_fitter);
}