1 /*
2     ugensa.c:
3 
4     Copyright (C) 1997 J. Michael Clarke, based on ideas from CHANT (IRCAM)
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 #include "stdopcod.h"                 /*                              UGENSA.C  */
25 #include "ugensa.h"
26 #include "ugens7.h"
27 #include <math.h>
28 
29 /* FOG generator */
30 
31 static int32_t newpulse(CSOUND *, FOGS *, OVERLAP *, MYFLT *, MYFLT *, MYFLT *);
32 
fogset(CSOUND * csound,FOGS * p)33 static int32_t fogset(CSOUND *csound, FOGS *p)
34 {
35     /* legato test, not sure if the last bit (auxch) is correct? */
36     int32_t skip = (*p->iskip != FL(0.0) && p->auxch.auxp != 0);
37     if (LIKELY((p->ftp1 = csound->FTFind(csound, p->ifna)) != NULL &&
38                (p->ftp2 = csound->FTFind(csound, p->ifnb)) != NULL)) {
39       OVERLAP *ovp, *nxtovp;
40       int32   olaps;
41       p->fogcvt = FMAXLEN/(p->ftp1)->flen; /*JMC for FOG*/
42       p->durtogo = (int32)(*p->itotdur * CS_ESR);
43       if (!skip) { /* legato: skip all memory management */
44         p->spdphs = 0L; /*JMC for FOG*/
45         if (*p->iphs == FL(0.0))                  /* if fundphs zero,  */
46           p->fundphs = MAXLEN;                    /*   trigger new FOF */
47         else p->fundphs = (int32)(*p->iphs * FMAXLEN) & PHMASK;
48         if (UNLIKELY((olaps = (int32)*p->iolaps) <= 0)) {
49           return csound->InitError(csound, Str("illegal value for iolaps"));
50         }
51         if (*p->iphs>=FL(0.0))
52           csound->AuxAlloc(csound, (size_t)olaps * sizeof(OVERLAP), &p->auxch);
53         ovp = &p->basovrlap;
54         nxtovp = (OVERLAP *) p->auxch.auxp;
55         do {
56           ovp->nxtact = NULL;
57           ovp->nxtfree = nxtovp;              /* link the ovlap spaces */
58           ovp = nxtovp++;
59         } while (--olaps);
60         ovp->nxtact  = NULL;
61         ovp->nxtfree = NULL;
62         p->fofcount  = -1;
63         p->prvband   = FL(0.0);
64         p->expamp    = FL(1.0);
65         p->prvsmps   = 0;
66         p->preamp    = FL(1.0);
67       }
68       p->ampcod   = IS_ASIG_ARG(p->xamp) ? 1 : 0;
69       p->fundcod  = IS_ASIG_ARG(p->xdens) ? 1 : 0;
70       p->formcod  = IS_ASIG_ARG(p->xtrans) ? 1 : 0;
71       p->xincod   = p->ampcod || p->fundcod || p->formcod;
72 /* p->speedcod  = (p->XINCODE & 0x8) ? 1 : 0; */ /*out for phs version of fog*/
73       p->fmtmod    = (*p->itmode == 0.0) ? 0 : 1;
74     }
75     else return NOTOK;
76     return OK;
77 }
78 
fog(CSOUND * csound,FOGS * p)79 static int32_t fog(CSOUND *csound, FOGS *p)
80 {
81     OVERLAP *ovp;
82     FUNC        *ftp1,  *ftp2;
83     MYFLT       *ar, *amp, *fund, *ptch, *speed;
84     MYFLT  v1, fract ,*ftab, fogcvt = p->fogcvt; /*JMC added for FOG*/
85     uint32_t offset = p->h.insdshead->ksmps_offset;
86     uint32_t early  = p->h.insdshead->ksmps_no_end;
87     uint32_t n, nsmps = CS_KSMPS;
88     int32   fund_inc, form_inc;
89     /* int64_t speed_inc; */ /*JMC added last--out for phs version*/
90 
91     ar = p->ar;
92     amp = p->xamp;
93     fund = p->xdens;
94     ptch = p->xtrans;
95     speed = p->xspd;
96     ftp1 = p->ftp1;
97     ftp2 = p->ftp2;
98     fund_inc = (int32)(*fund * csound->sicvt);
99     form_inc = (int32)(*ptch * fogcvt);  /*form_inc = *form * csound->sicvt;*/
100 /*      speed_inc = *speed * fogcvt; */   /*JMC for FOG--out for phs version*/
101     if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
102     if (UNLIKELY(early)) {
103       nsmps -= early;
104       memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
105     }
106     for (n=offset;n<nsmps;n++) {
107       if (p->fundphs & MAXLEN) {                       /* if phs has wrapped */
108         p->fundphs &= PHMASK;
109         if (UNLIKELY((ovp = p->basovrlap.nxtfree) == NULL)) goto err1;
110         if (newpulse(csound, p, ovp, amp, fund, ptch)) { /* init new fof */
111           ovp->nxtact = p->basovrlap.nxtact;           /* & link into  */
112           p->basovrlap.nxtact = ovp;                   /*   actlist    */
113           p->basovrlap.nxtfree = ovp->nxtfree;
114         }
115       }
116       ar[n] = FL(0.0);
117       ovp = &p->basovrlap;
118       while (ovp->nxtact != NULL) {         /* perform cur actlist:  */
119         MYFLT result;
120         OVERLAP *prvact = ovp;
121         ovp = ovp->nxtact;                     /*  formant waveform  */
122         fract = PFRAC1(ovp->formphs);                   /*JMC Fog*/
123         ftab = ftp1->ftable + (ovp->formphs >> ftp1->lobits);/*JMC Fog*/
124         v1 = *ftab++;                                   /*JMC Fog*/
125         result = v1 + (*ftab - v1) * fract;             /*JMC Fog*/
126 /*  result = *(ftp1->ftable + (ovp->formphs >> ftp1->lobits) ); FOF version*/
127         if (p->fmtmod)
128           ovp->formphs += form_inc;         /*   inc phs on mode  */
129         else ovp->formphs += ovp->forminc;
130         ovp->formphs &= PHMASK;
131         if (ovp->risphs < MAXLEN) {           /*  formant ris envlp */
132           result *= *(ftp2->ftable + (ovp->risphs >> ftp2->lobits) );
133           ovp->risphs += ovp->risinc;
134         }
135         if (ovp->timrem <= ovp->dectim) {     /*  formant dec envlp */
136           result *= *(ftp2->ftable + (ovp->decphs >> ftp2->lobits) );
137           if ((ovp->decphs -= ovp->decinc) < 0)
138             ovp->decphs = 0;
139         }
140         ar[n] += (result * ovp->curamp);        /*  add wavfrm to out */
141         if (--ovp->timrem)                    /*  if fof not expird */
142           ovp->curamp *= ovp->expamp;       /*   apply bw exp dec */
143         else {
144           prvact->nxtact = ovp->nxtact;     /*  else rm frm activ */
145           ovp->nxtfree = p->basovrlap.nxtfree;/*  & ret spc to free */
146           p->basovrlap.nxtfree = ovp;
147           ovp = prvact;
148         }
149       }
150       p->fundphs += fund_inc;
151 /*          p->spdphs += speed_inc; */ /*JMC for FOG*/
152       p->spdphs = (int32)(speed[n] * FMAXLEN); /*for phs version of FOG*/
153       p->spdphs &= PHMASK; /*JMC for FOG*/
154       if (p->xincod) {
155         if (p->ampcod)    amp++;
156         if (p->fundcod)   fund_inc = (int32)(*++fund * csound->sicvt);
157         if (p->formcod)   form_inc = (int32)(*++ptch * fogcvt);
158 /*form_inc = *++form * csound->sicvt;*/
159 /*      if (p->speedcod)  speed_inc = *++speed * fogcvt; */  /*JMC for FOG*/
160       }
161       p->durtogo--;
162     }
163     return OK;
164  err1:
165     return csound->PerfError(csound, &(p->h),
166                              Str("FOF needs more overlaps"));
167 }
168 
newpulse(CSOUND * csound,FOGS * p,OVERLAP * ovp,MYFLT * amp,MYFLT * fund,MYFLT * ptch)169 static int32_t newpulse(CSOUND *csound, FOGS *p, OVERLAP *ovp, MYFLT   *amp,
170                     MYFLT *fund, MYFLT *ptch)
171 {
172     MYFLT       octamp = *amp, oct;
173     MYFLT       form = *ptch / csound->sicvt, fogcvt = p->fogcvt;
174     int32   rismps, newexp = 0;
175     if ((ovp->timrem = (int32)(*p->kdur * CS_ESR)) > p->durtogo &&
176         (*p->iskip==FL(0.0)))  /* ringtime    */
177       return(0);
178     if ((oct = *p->koct) > 0.0) {                   /* octaviation */
179       int64_t cnst = -1L;
180       int32 ioct = (int32)oct, bitpat = ~(cnst << ioct);
181       if (bitpat & ++p->fofcount)
182         return(0);
183       if ((bitpat += 1) & p->fofcount)
184         octamp *= (FL(1.0) + ioct - oct);
185     }
186     if (*fund == 0.0)                               /* formant phs */
187       ovp->formphs = 0;
188 /*  else
189      ovp->formphs = (int32)((p->fundphs * form / *fund) + p->spdphs) & PHMASK; */
190     else ovp->formphs = (int32)(p->fundphs * form / *fund) & PHMASK;
191     ovp->forminc = (int32)(*ptch * fogcvt);/*JMC for FOG*/
192     /*ovp->forminc = *form * csound->sicvt;*/
193     if (*p->kband != p->prvband) {                    /* bw: exp dec */
194       p->prvband = *p->kband;
195       p->expamp = EXP(*p->kband * csound->mpidsr);
196       newexp = 1;
197     }
198     if (*p->kris >= csound->onedsr && form != 0.0) {  /* init fnb ris */
199       ovp->risphs = (uint32)(ovp->formphs / (fabs(form))
200                                     / *p->kris); /* JPff fix */
201       ovp->risinc = (int32)(csound->sicvt / *p->kris);
202       rismps = MAXLEN / ovp->risinc;
203     }
204     else {
205       ovp->risphs = MAXLEN;
206       rismps = 0;
207     }
208 
209     /* p->spdphs (soundfile ftable index) must be added to
210        ovp->formphs (sound ftable reading rate)
211        AFTER ovp-risphs is calculated */
212     ovp->formphs = (ovp->formphs + p->spdphs) & PHMASK;
213 
214     if (newexp || rismps != p->prvsmps) {            /* if new params */
215       if ((p->prvsmps = rismps))                     /*   redo preamp */
216         p->preamp = csound->intpow(p->expamp, -rismps);
217       else p->preamp = FL(1.0);
218     }
219     ovp->curamp = octamp * p->preamp;                /* set startamp  */
220     ovp->expamp = p->expamp;
221     if ((ovp->dectim = (int32)(*p->kdec * CS_ESR)) > 0) /*      fnb dec  */
222       ovp->decinc = (int32)(csound->sicvt / *p->kdec);
223     ovp->decphs = PHMASK;
224     return(1);
225 }
226 
227 /* JMC test additional UG */
228 #define S(x)    sizeof(x)
229 
230 static OENTRY localops[] = {
231   { "fog",  S(FOGS), TR, 3, "a","xxxakkkkkiiiiooo",(SUBR)fogset,(SUBR)fog}
232 };
233 
ugensa_init_(CSOUND * csound)234 int32_t ugensa_init_(CSOUND *csound)
235 {
236     return csound->AppendOpcodes(csound, &(localops[0]),
237                                  (int32_t) (sizeof(localops) / sizeof(OENTRY)));
238 }
239 
240