1 /*
2     follow.c:
3 
4     Copyright (C) 1994, 1999 Paris Smaragdis, John ffitch
5 
6     This file is part of Csound.
7 
8     The Csound Library is free software; you can redistribute it
9     and/or modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation; either
11     version 2.1 of the License, or (at your option) any later version.
12 
13     Csound is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU Lesser General Public License for more details.
17 
18     You should have received a copy of the GNU Lesser General Public
19     License along with Csound; if not, write to the Free Software
20     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21     02110-1301 USA
22 */
23 
24         /*      Envelope follower by Paris Smaragdis    */
25         /*      Berklee College of Music Csound development team */
26         /*      Copyright (c) August 1994.  All rights reserve */
27         /*      Improvements 1999 John ffitch */
28 
29 #include "stdopcod.h"
30 #include <math.h>
31 #include "follow.h"
32 
flwset(CSOUND * csound,FOL * p)33 static int32_t flwset(CSOUND *csound, FOL *p)
34 {
35     p->wgh = p->max = FL(0.0);
36     p->length = (int32)(*p->len * CS_ESR);
37     if (UNLIKELY(p->length<=0L)) {           /* RWD's suggestion */
38       csound->Warning(csound, Str("follow - zero length!"));
39       p->length = (int32)CS_ESR;
40     }
41     p->count = p->length;
42     return OK;
43 }
44 
45                                 /* Use absolute value rather than max/min */
follow(CSOUND * csound,FOL * p)46 static int32_t follow(CSOUND *csound, FOL *p)
47 {
48      IGN(csound);
49     uint32_t offset = p->h.insdshead->ksmps_offset;
50     uint32_t early  = p->h.insdshead->ksmps_no_end;
51     uint32_t n, nsmps = CS_KSMPS;
52     MYFLT       *in = p->in, *out = p->out;
53     MYFLT       max = p->max;
54     int32       count = p->count;
55 
56     if (UNLIKELY(offset)) memset(out, '\0', offset*sizeof(MYFLT));
57     if (UNLIKELY(early)) {
58       nsmps -= early;
59       memset(&out[nsmps], '\0', early*sizeof(MYFLT));
60     }
61     for (n=offset; n<nsmps; n++) {
62       MYFLT sig = FABS(in[n]);
63       if (sig > max) max = sig;
64       if (UNLIKELY(--count == 0L)) {
65         p->wgh = max;
66         max = FL(0.0);
67         count = p->length;
68       }
69       out[n] = p->wgh;
70     }
71     p->max = max;
72     p->count = count;
73     return OK;
74 }
75 
76 /* The Jean-Marc Jot (IRCAM) envelope follower, from code by
77    Bram.DeJong@rug.ac.be and James Maccartney posted on music-dsp;
78    Transferred to csound by JPff, 2000 feb 12
79 */
envset(CSOUND * csound,ENV * p)80 static int32_t envset(CSOUND *csound, ENV *p)
81 {
82                                 /* Note - 6.90775527898 -- log(0.001) */
83     p->lastatt = *p->attack;
84     if (p->lastatt<=FL(0.0))
85       p->ga = EXP(- FL(69.0775527898)*csound->onedsr);
86     else
87       p->ga = EXP(- FL(6.90775527898)/(CS_ESR* p->lastatt));
88     p->lastrel = *p->release;
89     if (p->lastrel<=FL(0.0))
90       p->gr = EXP(- FL(69.0775527898)*csound->onedsr);
91     else
92       p->gr = EXP(- FL(6.90775527898)/(CS_ESR* p->lastrel));
93     p->envelope = FL(0.0);
94     return OK;
95 }
96 
envext(CSOUND * csound,ENV * p)97 static int32_t envext(CSOUND *csound, ENV *p)
98 {
99     uint32_t offset = p->h.insdshead->ksmps_offset;
100     uint32_t early  = p->h.insdshead->ksmps_no_end;
101     uint32_t n, nsmps = CS_KSMPS;
102     MYFLT       envelope = p->envelope;
103     MYFLT       ga, gr;
104     MYFLT       *in = p->in, *out = p->out;
105     if (p->lastatt!=*p->attack) {
106       p->lastatt = *p->attack;
107       if (p->lastatt<=FL(0.0))
108         ga = p->ga = EXP(- FL(69.0775527898)*csound->onedsr);
109       // EXP(-FL(10000.0)*csound->onedsr);
110       else
111         ga = p->ga = EXP(- FL(6.90775527898)/(CS_ESR* p->lastatt));
112       //EXP(-FL(1.0)/(CS_ESR* p->lastatt));
113     }
114     else ga = p->ga;
115     if (p->lastrel!=*p->release) {
116       p->lastrel = *p->release;
117       if (p->lastrel<=FL(0.0))
118         gr = p->gr = EXP(- FL(69.0775527898)*csound->onedsr);
119       //EXP(-FL(100.0)*csound->onedsr);
120       else
121         gr = p->gr = EXP(- FL(6.90775527898)/(CS_ESR* p->lastrel));
122       //EXP(-FL(1.0)/(CS_ESR* p->lastrel));
123     }
124     else gr = p->gr;
125     if (UNLIKELY(offset)) memset(out, '\0', offset*sizeof(MYFLT));
126     if (UNLIKELY(early)) {
127       nsmps -= early;
128       memset(&out[nsmps], '\0', early*sizeof(MYFLT));
129     }
130     for (n=offset;n<nsmps;n++) {
131       MYFLT inp = FABS(in[n]);  /* Absolute value */
132       if (envelope < inp) {
133         envelope = inp + ga*(envelope-inp);
134       }
135       else {
136         envelope = inp + gr*(envelope-inp);
137       }
138       out[n] = envelope;
139     }
140     p->envelope = envelope;
141     return OK;
142 }
143 
144 #define S(x)    sizeof(x)
145 
146 static OENTRY localops[] = {
147 { "follow",   S(FOL),   0, 3, "a",    "ai",   (SUBR)flwset,  (SUBR)follow  },
148 { "follow2",  S(ENV),   0, 3, "a",    "akk",  (SUBR)envset,  (SUBR)envext  }
149 };
150 
follow_init_(CSOUND * csound)151 int32_t follow_init_(CSOUND *csound)
152 {
153     return csound->AppendOpcodes(csound, &(localops[0]),
154                                  (int32_t
155                                   ) (sizeof(localops) / sizeof(OENTRY)));
156 }
157 
158