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