1 /*
2 bowedbar.c:
3
4 Copyright (C) 1999 Perry Cook, Georg Essl, 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 /*********************************************/
25 /* Bowed Bar model */
26 /* by Georg Essl, 1999 */
27 /* For details refer to: */
28 /* G.Essl, P.R.Cook: "Banded Waveguides: */
29 /* Towards Physical Modelling of Bar */
30 /* Percussion Instruments", ICMC'99 */
31 /*********************************************/
32 // #include "csdl.h"
33 #include "csoundCore.h"
34 #include "bowedbar.h"
35
36 /* Number of banded waveguide modes */
37
make_DLineN(CSOUND * csound,DLINEN * p,int32 length)38 static void make_DLineN(CSOUND *csound, DLINEN *p, int32 length)
39 {
40 /* Writing before reading allows delays from 0 to length-1.
41 Thus, if we want to allow a delay of max_length, we need
42 a delay-line of length = max_length+1. */
43 p->length = length = length+1;
44 csound->AuxAlloc(csound, length * sizeof(MYFLT), &p->inputs);
45 p->inPoint = 0;
46 p->outPoint = length >> 1;
47 p->lastOutput = FL(0.0);
48 }
49
DLineN_setDelay(CSOUND * csound,DLINEN * p,int32_t lag)50 static void DLineN_setDelay(CSOUND *csound, DLINEN *p, int32_t lag)
51 {
52 if (UNLIKELY(lag > p->length-1)) { /* if delay is too big, */
53 csound->Warning(csound, Str("DLineN: Delay length too big ... setting to "
54 "maximum length of %d.\n"), p->length - 1);
55 p->outPoint = p->inPoint + 1; /* force delay to max_length */
56 }
57 else
58 p->outPoint = p->inPoint - (int32) lag; /* read chases write */
59 while (p->outPoint<0)
60 p->outPoint += p->length; /* modulo maximum length */
61 }
62
DLineN_tick(DLINEN * p,MYFLT sample)63 static void DLineN_tick(DLINEN *p, MYFLT sample) /* Take one, yield one */
64 {
65 MYFLT *xx = (MYFLT*)p->inputs.auxp;
66 xx[p->inPoint++] = sample; /* Input next sample */
67 if (UNLIKELY(p->inPoint == p->length)) /* Check for end condition */
68 p->inPoint -= p->length;
69 p->lastOutput = xx[p->outPoint++]; /* Read nxt value */
70 if (UNLIKELY(p->outPoint>=p->length)) /* Check for end condition */
71 p->outPoint -= p->length;
72 }
73
bowedbarset(CSOUND * csound,BOWEDBAR * p)74 int32_t bowedbarset(CSOUND *csound, BOWEDBAR *p)
75 {
76 int32 i;
77 MYFLT amplitude = *p->amp * AMP_RSCALE;
78
79 p->modes[0] = FL(1.0);
80 p->modes[1] = FL(2.756);
81 p->modes[2] = FL(5.404);
82 p->modes[3] = FL(8.933);
83
84 make_BiQuad(&p->bandpass[0]);
85 make_BiQuad(&p->bandpass[1]);
86 make_BiQuad(&p->bandpass[2]);
87 make_BiQuad(&p->bandpass[3]);
88 make_ADSR(&p->adsr);
89 ADSR_setAllTimes(csound, &p->adsr, FL(0.02), FL(0.005), FL(0.9), FL(0.01));
90
91 if (LIKELY(*p->lowestFreq>=FL(0.0))) { /* If no init skip */
92 if (*p->lowestFreq!=FL(0.0))
93 p->length = (int32) (CS_ESR / *p->lowestFreq + FL(1.0));
94 else if (*p->frequency!=FL(0.0))
95 p->length = (int32) (CS_ESR / *p->frequency + FL(1.0));
96 else {
97 csound->Warning(csound,
98 Str("unknown lowest frequency for bowed bar -- "
99 "assuming 50Hz\n"));
100 p->length = (int32) (CS_ESR / FL(50.0) + FL(1.0));
101 }
102 }
103
104 p->nr_modes = NR_MODES;
105 for (i = 0; i<NR_MODES; i++) {
106 make_DLineN(csound, &p->delay[i], p->length);
107 DLineN_setDelay(csound, &p->delay[i], (int32_t)(p->length/p->modes[i]));
108 BiQuad_clear(&p->bandpass[i]);
109 }
110 /* p->gains[0] = FL(0.0); */
111 /* p->gains[1] = FL(0.0); */
112 /* p->gains[2] = FL(0.0); */
113 /* p->gains[3] = FL(0.0); */
114 p->adsr.target = FL(0.0);
115 p->adsr.value = FL(0.0);
116 p->adsr.rate = amplitude * FL(0.001);
117 p->adsr.state = ATTACK;
118 p->lastBowPos = FL(0.0);
119 p->bowTarg = FL(0.0);
120 p->freq = -FL(1.0);
121 p->lastpos = -FL(1.0);
122 p->lastpress = p->bowvel = p->velinput = FL(0.0);
123 p->kloop = 0;
124 p->bowTabl.offSet = p->bowTabl.slope = FL(0.0);
125 return OK;
126 }
127
bowedbar(CSOUND * csound,BOWEDBAR * p)128 int32_t bowedbar(CSOUND *csound, BOWEDBAR *p)
129 {
130 MYFLT *ar = p->ar;
131 uint32_t offset = p->h.insdshead->ksmps_offset;
132 uint32_t early = p->h.insdshead->ksmps_no_end;
133 uint32_t n, nsmps = CS_KSMPS;
134 MYFLT amp = (*p->amp)*AMP_RSCALE; /* Normalise */
135 int32 k;
136 int32_t i;
137 MYFLT maxVelocity;
138 MYFLT integration_const = *p->integration_const;
139
140 if (p->lastpress != *p->bowPress)
141 p->bowTabl.slope = p->lastpress = *p->bowPress;
142 if (p->freq != *p->frequency) {
143 p->freq = *p->frequency;
144 if (p->freq > FL(1568.0)) p->freq = FL(1568.0);
145
146 p->length = (int32_t)(CS_ESR/p->freq);
147 p->nr_modes = NR_MODES; /* reset for frequency shift */
148 for (i = 0; i<NR_MODES; i++) {
149 if ((int32_t)(p->length/p->modes[i]) > 4)
150 DLineN_setDelay(csound, &p->delay[i], (int32_t)(p->length/p->modes[i]));
151 else {
152 p->nr_modes = i;
153 break;
154 }
155 }
156 if (UNLIKELY(p->nr_modes==0))
157 return csound->InitError(csound,
158 Str("Bowedbar: cannot have zero modes\n"));
159 for (i=0; i<p->nr_modes; i++) {
160 MYFLT R = FL(1.0) - p->freq * p->modes[i] * csound->pidsr;
161 BiQuad_clear(&p->bandpass[i]);
162 BiQuad_setFreqAndReson(p->bandpass[i], p->freq * p->modes[i], R);
163 BiQuad_setEqualGainZeroes(p->bandpass[i]);
164 BiQuad_setGain(p->bandpass[i], (FL(1.0)-R*R)*FL(0.5));
165 }
166 }
167 /* Bow position as well */
168 if (*p->position != p->lastpos) {
169 MYFLT temp2 = *p->position * PI_F;
170 p->gains[0] = FABS(SIN(temp2 * FL(0.5))) /* * pow(0.9,0))*/;
171 p->gains[1] = FABS(SIN(temp2) * FL(0.9));
172 p->gains[2] = FABS(SIN(temp2 * FL(1.5)) * FL(0.9)*FL(0.9));
173 p->gains[3] = FABS(SIN(temp2 * FL(2.0)) * FL(0.9)*FL(0.9)*FL(0.9));
174 p->lastpos = *p->position;
175 }
176 if (*p->bowposition != p->lastBowPos) { /* Not sure what this control is? */
177 p->bowTarg += FL(0.02) * (*p->bowposition - p->lastBowPos);
178 p->lastBowPos = *p->bowposition;
179 ADSR_setTarget(csound, &p->adsr, p->lastBowPos);
180 p->lastBowPos = *p->bowposition;
181 }
182 if (p->kloop>0 && p->h.insdshead->relesing) p->kloop=1;
183 if ((--p->kloop) == 0) {
184 ADSR_setReleaseRate(csound, &p->adsr, (FL(1.0) - amp) * FL(0.005));
185 p->adsr.target = FL(0.0);
186 p->adsr.rate = p->adsr.releaseRate;
187 p->adsr.state = RELEASE;
188 }
189 maxVelocity = FL(0.03) + (FL(0.5) * amp);
190
191 if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
192 if (UNLIKELY(early)) {
193 nsmps -= early;
194 memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
195 }
196 for (n=offset; n<nsmps; n++) {
197 MYFLT data = FL(0.0);
198 MYFLT input = FL(0.0);
199 if (integration_const == FL(0.0))
200 p->velinput = FL(0.0);
201 else
202 p->velinput = integration_const * p->velinput;
203
204 for (k=0; k<p->nr_modes; k++) {
205 p->velinput += *p->GAIN * p->delay[k].lastOutput;
206 }
207
208 if (*p->trackVel) {
209 p->bowvel *= FL(0.9995);
210 p->bowvel += p->bowTarg;
211 p->bowTarg *= FL(0.995);
212 }
213 else
214 p->bowvel = ADSR_tick(&p->adsr)*maxVelocity;
215
216 input = p->bowvel - p->velinput;
217 input = input * BowTabl_lookup(csound, &p->bowTabl, input);
218 input = input/(MYFLT)p->nr_modes;
219
220 for (k=0; k<p->nr_modes; k++) {
221 BiQuad_tick(&p->bandpass[k],
222 input*p->gains[k] + *p->GAIN * p->delay[k].lastOutput);
223 DLineN_tick(&p->delay[k], p->bandpass[k].lastOutput);
224 data += p->bandpass[k].lastOutput;
225 }
226
227 ar[n] = data * AMP_SCALE * FL(20.0); /* 20 is an experimental value */
228 }
229 return OK;
230 }
231
232
233