1 /*
2 grain4.c:
3
4 Copyright (C) 1994, 1995 Allan S C Lee, 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 /* Verson 4.0 - Mar 95 */
25 /* Verson 4.1 - 10 Mar 95 */
26 /* Lifted restriction on pitch, now accept */
27 /* anything greater than zero */
28 /* Improved code in handling the warp-round */
29 /* pointer. */
30 /* Verson 4.2 - 20 Apr 95 */
31 /* Add optional parameter ifnenv */
32 /* Function table to be used for the shape of the*/
33 /* envelop rise and decade curve */
34 /* Minor changes by John Fitch Dec 1995 */
35
36 // #include "csdl.h"
37 #include "csoundCore.h"
38 #include "interlocks.h"
39 #include "grain4.h"
40 #include <math.h>
41
42 #define RNDMUL 15625L
43
44 static MYFLT grand(GRAINV4 *);
45
grainsetv4(CSOUND * csound,GRAINV4 * p)46 static int32_t grainsetv4(CSOUND *csound, GRAINV4 *p)
47 {
48 FUNC *ftp, *ftp_env;
49 int32_t nvoice, cnt;
50 int32_t tmplong1, tmplong2;
51 MYFLT tmpfloat1;
52 MYFLT pitch[4];
53
54 /* call ftfind() to get the function table...*/
55 if (LIKELY((ftp = csound->FTnp2Find(csound, p->ifn)) != NULL)) {
56 p->ftp = ftp;
57 }
58 else {
59 return csound->InitError(csound, Str("granule_set: "
60 "Unable to find function table"));
61 }
62
63 /* call ftfind() to get the function table for the envelop...*/
64 if (*p->ifnenv > 0) {
65 if (LIKELY((ftp_env = csound->FTnp2Find(csound, p->ifnenv)) != NULL)) {
66 p->ftp_env = ftp_env;
67 }
68 else {
69 return csound->InitError(csound, Str("granule_set: Unable to find "
70 "function table for envelope"));
71 }
72 }
73
74 if (UNLIKELY(*p->ivoice > MAXVOICE)) {
75 return csound->InitError(csound, Str("granule_set: Too many voices"));
76 }
77 if (UNLIKELY(*p->iratio <= 0)) {
78 return csound->InitError(csound, Str("granule_set: "
79 "iratio must be greater then 0"));
80 }
81 if (UNLIKELY((*p->imode != 0) && ((*p->imode != -1) && (*p->imode != 1)))) {
82 return csound->InitError(csound, Str("granule_set: "
83 "imode must be -1, 0 or +1"));
84 }
85 if (UNLIKELY(*p->ithd < 0)) {
86 return csound->InitError(csound, Str("granule_set: Illegal ithd, "
87 "must be greater than zero"));
88 }
89 if (UNLIKELY((*p->ipshift != 1) && (*p->ipshift!=2) && (*p->ipshift!=3) &&
90 (*p->ipshift!=4) && (*p->ipshift!=0) )) {
91 return csound->InitError(csound, Str("granule_set: ipshift must be "
92 "integer between 0 and 4"));
93 }
94 if (UNLIKELY(((*p->ipshift >=1) && (*p->ipshift <=4)) &&
95 (*p->ivoice < *p->ipshift))) {
96 return csound->InitError(csound, Str("granule_set: Not enough voices "
97 "for the number of pitches"));
98 }
99 if ( *p->ipshift !=FL(0.0) ) {
100 if (UNLIKELY(*p->ipitch1 < FL(0.0) )) {
101 return
102 csound->InitError(csound,
103 Str("granule_set: ipitch1 must be greater then zero"));
104 }
105 if (UNLIKELY(*p->ipitch2 < FL(0.0) )) {
106 return
107 csound->InitError(csound,
108 Str("granule_set: ipitch2 must be greater then zero"));
109 }
110 if (UNLIKELY(*p->ipitch3 < FL(0.0) )) {
111 return
112 csound->InitError(csound,
113 Str("granule_set: ipitch3 must be greater then zero"));
114 }
115 if (UNLIKELY(*p->ipitch4 < FL(0.0) )) {
116 return
117 csound->InitError(csound,
118 Str("granule_set: ipitch4 must be greater then zero"));
119 }
120 }
121
122 if (UNLIKELY((*p->igskip < 0) || (*p->igskip * CS_ESR > ftp->flen) )) {
123 return csound->InitError(csound, Str("granule_set: must be positive and "
124 "less than function table length"));
125 }
126 if (UNLIKELY(*p->igskip_os < 0)) {
127 return csound->InitError(csound, Str("granule_set: "
128 "igskip_os must be greater then 0"));
129 }
130
131 p->gstart = (int32)(*p->igskip * CS_ESR);
132 p->glength = (int32)(*p->ilength * CS_ESR);
133 p->gend = p->gstart + p->glength;
134
135 if (UNLIKELY(*p->kgap < 0)) {
136 return csound->InitError(csound, Str("granule_set: "
137 "kgap must be greater then 0"));
138 }
139 if (UNLIKELY((*p->igap_os < 0) || (*p->igap_os > 100))) {
140 return csound->InitError(csound, Str("granule_set: "
141 "igap_os must be 0%% to 100%%"));
142 }
143 if (UNLIKELY(*p->kgsize < 0)) {
144 return csound->InitError(csound, Str("granule_set: "
145 "kgsize must be greater then 0"));
146 }
147 if (UNLIKELY((*p->igsize_os < 0) || (*p->igsize_os >100))) {
148 return csound->InitError(csound, Str("granule_set: "
149 "igsize_os must be 0%% to 100%%"));
150 }
151 if (UNLIKELY((*p->iatt < FL(0.0)) || (*p->idec < 0.0) ||
152 ((*p->iatt + *p->idec) > FL(100.0)))) {
153 return
154 csound->InitError(csound,
155 Str("granule_set: Illegal value of iatt and/or idec"));
156 } /* end if */
157
158 /* Initialize random number generator */
159 if (*p->iseed >=0) {
160 p->grnd = (int16)(*p->iseed * FL(32768.0)); /* IV - Jul 11 2002 */
161 }
162
163 /* Initialize variables....*/
164 p->gskip_os = (int32)(*p->igskip_os * CS_ESR);/* in number of samples */
165 p->gap_os = *p->igap_os / FL(100.0);
166 p->gsize_os = *p->igsize_os / FL(100.0);
167
168 for (nvoice = 0; nvoice < *p->ivoice; nvoice++) {
169 p->fpnt[nvoice] = 0;
170 p->cnt[nvoice] = 0;
171 p->phs[nvoice] = FL(0.0);
172 p->gskip[nvoice] = (int32)(*p->igskip * CS_ESR);
173 p->gap[nvoice] = (int32)(*p->kgap * CS_ESR);
174 }
175
176 if (*p->igap_os != 0) {
177 for (nvoice = 0; nvoice < *p->ivoice; nvoice++)
178 p->gap[nvoice] += (int32)((MYFLT)p->gap[nvoice] * p->gap_os * grand(p));
179 }
180
181 if (*p->imode == 0) {
182 for (nvoice = 0; nvoice < *p->ivoice; nvoice++)
183 p->mode[nvoice] = (grand(p) < 0) ? -1 : 1;
184 }
185 else {
186 for (nvoice = 0; nvoice < *p->ivoice; nvoice++)
187 p->mode[nvoice] = (int32)*p->imode;
188 }
189
190 if ((*p->ipshift >=1) && (*p->ipshift <=4)) {
191 pitch[0] = *p->ipitch1;
192 pitch[1] = *p->ipitch2;
193 pitch[2] = *p->ipitch3;
194 pitch[3] = *p->ipitch4;
195 cnt = 0;
196 for (nvoice = 0; nvoice < *p->ivoice; nvoice++) {
197 p->pshift[nvoice] = pitch[cnt++];
198 cnt = (cnt < *p->ipshift) ? cnt : 0;
199 }
200 }
201 if (*p->ipshift == 0) {
202 for (nvoice = 0; nvoice < *p->ivoice; nvoice++) {
203 tmpfloat1 = grand(p);
204 p->pshift[nvoice] =
205 (tmpfloat1 <FL(0.0)) ? (tmpfloat1*FL(0.5))+FL(1.0) : tmpfloat1+1.0f;
206 }
207 }
208
209 for (nvoice = 0; nvoice < *p->ivoice; nvoice++)
210 p->gsize[nvoice] = (int32)(*p->kgsize * CS_ESR * p->pshift[nvoice]);
211
212 if (*p->igsize_os != 0) {
213 for (nvoice = 0; nvoice < *p->ivoice; nvoice++)
214 p->gsize[nvoice] += (int32)(p->gsize[nvoice] * p->gsize_os * grand(p));
215 }
216
217 for (nvoice = 0; nvoice < *p->ivoice; nvoice++)
218 p->stretch[nvoice] = p->gsize[nvoice] + p->gap[nvoice];
219
220 if (*p->igskip_os != 0)
221 for (nvoice = 0; nvoice < *p->ivoice; nvoice++) {
222 tmplong1 = ((p->gskip_os * grand(p)) + (MYFLT)p->gskip[nvoice]);
223 p->gskip[nvoice] =
224 (tmplong1 < p->gstart) ? p->gstart : tmplong1;
225 p->gskip[nvoice]=
226 ((p->gskip[nvoice]+p->stretch[nvoice])>(int32)p->gend) ?
227 (int32)p->gstart :
228 p->gskip[nvoice];
229 }
230
231 if (*p->ithd != 0) { /* Do thresholding.... */
232 tmplong2 = 0;
233 for (tmplong1=0; tmplong1< (int32_t) ftp->flen; tmplong1++)
234 if (fabs(ftp->ftable[tmplong1]) >= *p->ithd )
235 ftp->ftable[tmplong2++] = ftp->ftable[tmplong1];
236 ftp->flen = tmplong2;
237 }
238
239 if (UNLIKELY(p->gend > (int32_t) ftp->flen)) {
240 return csound->InitError(csound, Str("granule_set: Illegal combination "
241 "of igskip and ilength"));
242 }
243
244 nvoice = (int32_t)*p->ivoice;
245
246 if (UNLIKELY(*p->ilength < (20 * *p->kgsize)))
247 csound->Warning(csound, Str("granule_set: "
248 "WARNING * ilength may be too short *\n"
249 " ilength should be "
250 "greater than kgsize * max up\n"
251 " pitch shift. Also, igsize_os "
252 "and igskip_os should\n"
253 " be taken into consideration.\n"
254 "ilength is "
255 "%f Sec, kgsize is %f Sec\n"),
256 *p->ilength, *p->kgsize);
257
258 //p->clock = 0; /* init clock */
259 return OK;
260 } /* end grainsetv4(p) */
261
graingenv4(CSOUND * csound,GRAINV4 * p)262 static int32_t graingenv4(CSOUND *csound, GRAINV4 *p)
263 {
264 FUNC *ftp, *ftp_env;
265 MYFLT *ar, *ftbl, *ftbl_env=NULL;
266 uint32_t offset = p->h.insdshead->ksmps_offset;
267 uint32_t early = p->h.insdshead->ksmps_no_end;
268 uint32_t n, nsmps = CS_KSMPS;
269 int32_t nvoice;
270 int32 tmplong1, tmplong2, tmplong3, tmpfpnt, flen_env=0;
271 MYFLT fract, v1, tmpfloat1;
272 int32 att_len, dec_len, att_sus;
273 MYFLT envlop;
274
275 /* Optimisations */
276 int32 gstart = p->gstart;
277 int32 gend = p->gend;
278 int32 glength = p->glength;
279 MYFLT iratio = *p->iratio;
280
281 /* Recover parameters from previous call.... */
282 ftp = p->ftp;
283 if (UNLIKELY(p->ftp==NULL)) goto err1; /* RWD fix */
284 ftbl = ftp->ftable;
285
286 if (*p->ifnenv > 0) {
287 ftp_env = p->ftp_env;
288 flen_env = ftp_env->flen;
289 ftbl_env = ftp_env->ftable;
290 }
291
292 /* Recover audio output pointer... */
293 ar = p->ar;
294 if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
295 if (UNLIKELY(early)) {
296 nsmps -= early;
297 memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
298 }
299 /* *** Start the loop .... *** */
300 for (n=offset; n<nsmps; n++) {
301 /* Optimisations */
302 int32 *fpnt = p->fpnt, *cnt = p->cnt, *gskip = p->gskip;
303 int32 *gap = p->gap, *gsize = p->gsize;
304 int32 *stretch = p->stretch, *mode = p->mode;
305 MYFLT *pshift = p->pshift, *phs = p->phs;
306 ar[n] = FL(0.0);
307
308 for (nvoice = 0; nvoice < *p->ivoice ; nvoice++) {
309 if (*fpnt >= (*gsize -1)) {
310 ar[n] += 0; /* Is this necessary?? */
311 *cnt +=1L;
312 }
313 else {
314 fract = *phs - *fpnt;
315
316 if (*mode < 0) {
317 tmplong1 = *gskip - gstart;
318 if (*fpnt >= tmplong1) {
319 tmplong1= *fpnt - tmplong1;
320 tmplong2= tmplong1/glength;
321 tmplong1 -= tmplong2 * glength;
322 tmpfpnt = gend - tmplong1;
323 }
324 else
325 tmpfpnt = *gskip - *fpnt;
326 }
327 else {
328 tmplong1 = gend - *gskip;
329 if (*fpnt >= tmplong1) {
330 tmplong1= *fpnt - tmplong1;
331 tmplong2= tmplong1/glength;
332 tmplong1 -= tmplong2 * glength;
333 tmpfpnt = gstart + tmplong1;
334 }
335 else
336 tmpfpnt = *gskip + *fpnt;
337 }
338
339 att_len = (int32)(*gsize * *p->iatt * FL(0.01));
340 dec_len = (int32)(*gsize * *p->idec * FL(0.01));
341 att_sus = *gsize - dec_len;
342
343 if (*fpnt < att_sus) {
344 tmpfloat1 = (FL(1.0) * *fpnt) / att_len;
345 envlop = ((tmpfloat1 >=FL(1.0)) ? FL(1.0) : tmpfloat1);
346 }
347 else
348 envlop =
349 ((MYFLT)(dec_len - (MYFLT)(*fpnt - att_sus)))/((MYFLT)dec_len);
350
351 v1 = *(ftbl + tmpfpnt);
352
353 tmpfpnt = tmpfpnt + *mode;
354 if (tmpfpnt < gstart)
355 tmpfpnt = gend - (gstart - tmpfpnt) + 1;
356 if (tmpfpnt > gend)
357 tmpfpnt = gstart + (tmpfpnt - gend) - 1;
358
359 if (*p->ifnenv > 0) {
360 tmplong3 = (int32)(envlop * flen_env) -1L;
361 envlop = *(ftbl_env + tmplong3);
362 }
363
364 ar[n] +=(v1 + ( *(ftbl + tmpfpnt) - v1) * fract ) * envlop ;
365
366 *phs += *pshift;
367 *fpnt = (int32)*phs;
368 *cnt = (int32)*phs;
369 } /* end if (*fpnt >= (*gsize -1)) */
370
371 if (*cnt >= *stretch) {
372 *cnt = 0;
373 *fpnt= 0;
374 *phs = FL(0.0);
375
376 /* pick up new values... */
377
378 /* Use the old value of the pshift, gsize and gap */
379 /* to determine the time advanced */
380 /* *gskip+=
381 ((*gsize / *pshift) +
382 *gap) * iratio;
383 */
384 *gskip += (int32)((*gsize / *pshift) * iratio);
385
386 if (*p->igskip_os != 0)
387 *gskip += (int32)(p->gskip_os * grand(p));
388
389 if (*gskip >= gend) {
390 tmplong1 = *gskip - gend;
391 tmplong2 = tmplong1 /glength;
392 tmplong1 -= tmplong2 * glength;
393 *gskip = gstart + tmplong1;
394 }
395
396 if (*gskip < gstart) *gskip = gstart;
397
398 if (*p->imode == 0) {
399 *mode = (grand(p) < 0) ? -1 : 1;
400 }
401
402 if (*p->ipshift == 0) {
403 tmpfloat1 = grand(p);
404 *pshift = (tmpfloat1 < FL(0.0)) ?
405 (tmpfloat1*FL(0.5))+FL(1.0) : tmpfloat1+FL(1.0);
406 }
407
408 *gap = (int32)(*p->kgap * CS_ESR);
409 if (*p->igap_os != 0) {
410 *gap += (int32)((*gap * p->gap_os) * grand(p));
411 }
412
413 *gsize = (int32)(*p->kgsize * CS_ESR * *pshift);
414 if (*p->igsize_os != 0)
415 *gsize += (int32)((*gsize * p->gsize_os) * grand(p));
416
417 *stretch = *gsize + *gap;
418
419 }
420 fpnt++; cnt++; gskip++; gap++; gsize++;
421 stretch++; mode++; pshift++; phs++;
422 }
423 /* p->clock++; */
424 ar[n] *= *p->xamp; /* increment audio pointer and multiply the xamp */
425 }
426 return OK;
427 err1:
428 return csound->PerfError(csound, &(p->h),
429 Str("grain4: not initialised"));
430
431 } /* end graingenv4(p) */
432
433 /* Function return a float random number between -1 to +1 */
grand(GRAINV4 * p)434 static MYFLT grand( GRAINV4 *p)
435 {
436 p->grnd *= (int32_t
437 )RNDMUL;
438 p->grnd += 1;
439 return ((MYFLT) p->grnd * DV32768); /* IV - Jul 11 2002 */
440 } /* end grand(p) */
441
442 #define S(x) sizeof(x)
443
444
445
446
447
448
449 static OENTRY grain4_localops[] = {
450 { "granule", S(GRAINV4), TR, 3, "a", "xiiiiiiiiikikiiivppppo",
451 (SUBR)grainsetv4, (SUBR)graingenv4},
452 };
453
454 LINKAGE_BUILTIN(grain4_localops)
455