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