1 /*
2     shaker.c:
3 
4     Copyright (C) 1996, 1997 Perry Cook, 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 /*    Maracha SImulation by Perry R. Cook, 1996         */
26 /********************************************************/
27 /********************************************************/
28 /*    In real life, each grain has an individual
29         sound and envelope, but if you buy the
30         notion that each sound is independent
31         noise, the sum of a bunch of independent
32         exponentially decaying enveloped noises
33         is a single exponentially decaying enveloped
34         noise.  shakeEnergy is an exponentially
35         decaying, but reexcitable by shaking, energy
36         expressing how loud a single collision will be.
37 
38 This code would implement individual grain envelopes
39 
40             if (random(8) < 1) {
41                 noises[which] = 1024 * shakeEnergy;
42                 which += 1;
43                 if (which==MAX) which = 0;
44             }
45             input = 0.0;
46             for (i=0;i<MAX;i++)     {
47                 input += noises[i] * noise_tick();
48                 noises[i] *= COLL_DECAY;
49             }
50 
51 But we're smarter than that!!!  See below
52 */
53 // #include "csdl.h"
54 #include "csoundCore.h"
55 #include "shaker.h"
56 
shakerset(CSOUND * csound,SHAKER * p)57 int32_t shakerset(CSOUND *csound, SHAKER *p)
58 {
59     MYFLT       amp = (*p->amp)*AMP_RSCALE; /* Normalise */
60 
61     p->shake_speed = FL(0.0008) + (amp * FL(0.0004));
62     make_BiQuad(&p->filter);
63     make_ADSR(&p->envelope);
64     p->res_freq = FL(3200.0);
65     BiQuad_setFreqAndReson(p->filter, p->res_freq, FL(0.96));
66     BiQuad_setEqualGainZeroes(p->filter);
67     BiQuad_setGain(p->filter, FL(1.0));
68     p->shakeEnergy = FL(0.0);
69     p->noiseGain = FL(0.0);
70     p->coll_damp = FL(0.95);
71 /*     p->shake_damp = 0.999f; */
72 /*     p->num_beans = 8; */
73     ADSR_setAll(csound, &p->envelope,
74                 p->shake_speed,  p->shake_speed, FL(0.0),  p->shake_speed);
75     p->num_beans = (int32_t)*p->beancount;
76     if (p->num_beans<1) p->num_beans = 1;
77     p->wait_time = 0x7FFFFFFE / p->num_beans;
78     p->gain_norm = FL(0.0005);
79     p->shake_num = (int32_t)*p->times;
80     ADSR_keyOn(&p->envelope);
81     p->kloop = (int32_t)(p->h.insdshead->offtim * CS_EKR)
82                - (int32_t)(CS_EKR * *p->dettack);
83     p->freq = -FL(1.0);        /* So will get changed */
84     return OK;
85 }
86 
shaker(CSOUND * csound,SHAKER * p)87 int32_t shaker(CSOUND *csound, SHAKER *p)
88 {
89     MYFLT *ar = p->ar;
90     uint32_t offset = p->h.insdshead->ksmps_offset;
91     uint32_t early  = p->h.insdshead->ksmps_no_end;
92     uint32_t n, nsmps = CS_KSMPS;
93     MYFLT amp = (*p->amp)*AMP_RSCALE; /* Normalise */
94     MYFLT shake = amp + amp;
95     MYFLT damp = *p->shake_damp;
96     MYFLT gain = p->gain_norm;
97     MYFLT ngain = p->noiseGain;
98     MYFLT sEnergy = p->shakeEnergy;
99     MYFLT shake_speed = FL(0.0008) + amp * FL(0.0004);
100 
101     if (p->freq != *p->kfreq)
102       BiQuad_setFreqAndReson(p->filter, p->freq = *p->kfreq, FL(0.96));
103     if (p->num_beans != (int32_t)*p->beancount) { /* Bean Count */
104       p->num_beans = (int32_t
105                       )*p->beancount;
106       p->wait_time = 0x7FFFFFFE / p->num_beans;
107     }
108     if (shake_speed != p->shake_speed) {
109       p->shake_speed = shake_speed;
110       ADSR_setAll(csound,
111                   &p->envelope, shake_speed, shake_speed, FL(0.0), shake_speed);
112     }
113     if (p->kloop>0 && p->h.insdshead->relesing) p->kloop=1;
114     if ((--p->kloop) == 0) {
115       p->shake_num = 0;
116     }
117     if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
118     if (UNLIKELY(early)) {
119       nsmps -= early;
120       memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
121     }
122     gain *= p->num_beans;       /* Save work in loop */
123     for (n=offset; n<nsmps; n++) {
124         MYFLT   lastOutput;
125         MYFLT   temp;
126 
127         ADSR_tick(&p->envelope);
128         temp = p->envelope.value * shake;
129         if (p->shake_num>0) {
130           if (p->envelope.state==SUSTAIN) {
131             if (p->shake_num < 64)
132               p->shake_num -= 1;
133             ADSR_keyOn(&p->envelope);
134           }
135         }
136         if (temp > sEnergy)
137           sEnergy = temp;
138         sEnergy *= damp;   /*   Exponential System Decay */
139 
140     /* There's Roughly Constant Probablity of a Collision, and */
141     /* Energy of Each Collision is Weighted by Exponentially   */
142     /* Decaying System Energy.  All add together for total     */
143     /* exponentially decaying sound energy.                    */
144 
145         if (csound->Rand31(&(csound->randSeed1)) <= p->wait_time) {
146           ngain += gain * sEnergy;
147         }
148         /* Actual Sound is Random */
149         lastOutput = ngain * ((MYFLT) csound->Rand31(&(csound->randSeed1))
150                               - FL(1073741823.5))
151                            * (MYFLT) (1.0 / 1073741823.0);
152         /* Each (all) event(s) decay(s) exponentially */
153         ngain *= p->coll_damp;
154 
155         lastOutput = BiQuad_tick(&p->filter, lastOutput);
156         ar[n] = lastOutput * AMP_SCALE * FL(7.0); /* As too quiet */
157     }
158     p->noiseGain = ngain;
159     p->shakeEnergy = sEnergy;
160     return OK;
161 }
162 
163