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