1 /*
2     pvadd.c:
3 
4     Copyright (C) 1998 Richard Karpen
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 /* The applications in this file were     */
26 /* designed and coded by Richard Karpen   */
27 /* University of Washington, Seattle 1998 */
28 /******************************************/
29 /*    PVADD.C        */
30 
31 #include "pvoc.h"
32 #include <math.h>
33 
34 static int32_t pvx_loadfile(CSOUND *csound, const char *fname, PVADD *p);
35 
36 /* This is used in pvadd instead of the Fetch() from dsputil.c */
FetchInForAdd(float * inp,MYFLT * buf,int32 fsize,MYFLT pos,int32_t binoffset,int32_t maxbin,int32_t binincr)37 void FetchInForAdd(float *inp, MYFLT *buf, int32 fsize,
38                    MYFLT pos, int32_t binoffset, int32_t maxbin, int32_t binincr)
39 {
40     int32    j;
41     float   *frame0, *frame1;
42     int32    base;
43     MYFLT   frac;
44 
45     base = (int32)pos;
46     frac = pos - (MYFLT)base;
47     /* & how close to get to next */
48     frame0 = inp + ((int32)fsize+2L)*base;
49     frame1 = frame0 + ((int32)fsize+2L);
50     if (frac != FL(0.0)) {
51       for (j = binoffset; j < maxbin; j+=binincr) {
52         buf[2L*j] = frame0[2L*j] + frac*(frame1[2L*j]-frame0[2L*j]);
53         buf[2L*j+1L] = frame0[2L*j+1L]
54           + frac*(frame1[2L*j+1L]-frame0[2L*j+1L]);
55       }
56     }
57     else {
58       for (j = binoffset; j < maxbin; j+=binincr) {
59         buf[2L*j] = frame0[2L*j];
60         buf[2L*j+1] = frame0[2L*j+1L];
61       }
62     }
63 }
64 
pvaddset_(CSOUND * csound,PVADD * p,int32_t stringname)65 int32_t pvaddset_(CSOUND *csound, PVADD *p, int32_t stringname)
66 {
67     int32_t      ibins;
68     char     pvfilnam[MAXNAME];
69     int32_t      size;
70     FUNC     *ftp = NULL, *AmpGateFunc = NULL;
71     int32     memsize;
72 
73     if (*p->ifn > FL(0.0))
74       if (UNLIKELY((ftp = csound->FTFind(csound, p->ifn)) == NULL))
75         return NOTOK;
76     p->ftp = ftp;
77 
78     if (*p->igatefun > FL(0.0))
79       if (UNLIKELY((AmpGateFunc = csound->FTnp2Finde(csound, p->igatefun)) == NULL))
80         return NOTOK;
81     p->AmpGateFunc = AmpGateFunc;
82 
83     if (stringname==0){
84       if (csound->ISSTRCOD(*p->ifilno))
85         strNcpy(pvfilnam,get_arg_string(csound, *p->ifilno), MAXNAME-1);
86       else csound->strarg2name(csound, pvfilnam, p->ifilno, "pvoc.",0);
87     }
88     else strNcpy(pvfilnam, ((STRINGDAT *)p->ifilno)->data, MAXNAME-1);
89 
90     if (UNLIKELY(pvx_loadfile(csound, pvfilnam, p) != OK))
91       return NOTOK;
92 
93     memsize = (int32) (MAXBINS + PVFFTSIZE + PVFFTSIZE);
94     if (*p->imode == 1 || *p->imode == 2) {
95       int32  n= (int32) ((p->frSiz + 2L) * (p->maxFr + 2L));
96 #ifdef USE_DOUBLE
97       n = (n + 1L) * (int32) sizeof(float) / (int32) sizeof(double);
98 #endif
99       memsize += n;
100     }
101 
102     if (p->auxch.auxp == NULL || memsize != p->mems) {
103       MYFLT *fltp;
104       csound->AuxAlloc(csound, (memsize * sizeof(MYFLT)), &p->auxch);
105       fltp = (MYFLT *) p->auxch.auxp;
106       p->oscphase = fltp;
107       fltp += MAXBINS;
108       p->buf = fltp;
109       if (*p->imode == 1 || *p->imode == 2) {
110         fltp += PVFFTSIZE * 2;
111         p->pvcopy = (float*) ((void*) fltp);
112       }
113     }
114     p->mems = memsize;
115 
116     size = pvfrsiz(p);
117     p->prFlg = 1;    /* true */
118 
119    if (*p->igatefun > 0)
120      p->PvMaxAmp = PvocMaxAmp(p->frPtr, size, p->maxFr);
121 
122    if (*p->imode == 1 || *p->imode == 2) {
123      SpectralExtract(p->frPtr, p->pvcopy, size, p->maxFr,
124                      (int32_t) *p->imode, *p->ifreqlim);
125      p->frPtr = (float*) p->pvcopy;
126    }
127 
128     memset(p->oscphase, 0, MAXBINS*sizeof(MYFLT));
129 
130     ibins = (*p->ibins <= FL(0.0) ? (size / 2) : (int32_t) *p->ibins);
131     p->maxbin = ibins + (int32_t) *p->ibinoffset;
132     p->maxbin = (p->maxbin > (size / 2) ? (size / 2) : p->maxbin);
133 
134     return OK;
135 }
136 
pvadd(CSOUND * csound,PVADD * p)137 int32_t pvadd(CSOUND *csound, PVADD *p)
138 {
139     MYFLT   *ar, *ftab;
140     MYFLT   frIndx;
141     int32_t     size = pvfrsiz(p);
142     int32_t i, binincr = (int32_t) *p->ibinincr;
143     uint32_t offset = p->h.insdshead->ksmps_offset;
144     uint32_t early  = p->h.insdshead->ksmps_no_end;
145     uint32_t n, nsmps = CS_KSMPS;
146     MYFLT   amp, frq, v1, fract, *oscphase;
147     int32    phase, incr;
148     FUNC    *ftp;
149     int32    lobits;
150 
151     if (UNLIKELY(p->auxch.auxp == NULL)) goto err1;
152     ftp = p->ftp;
153     if (UNLIKELY((frIndx = *p->ktimpnt * p->frPrtim) < 0)) goto err2;
154 
155     if (frIndx > p->maxFr) { /* not past last one */
156       frIndx = (MYFLT) p->maxFr;
157       if (p->prFlg) {
158         p->prFlg = 0;   /* false */
159         csound->Warning(csound, Str("PVADD ktimpnt truncated to last frame"));
160       }
161     }
162     FetchInForAdd(p->frPtr, p->buf, size, frIndx,
163                   (int32_t) *p->ibinoffset, p->maxbin, binincr);
164 
165     if (*p->igatefun > 0)
166       PvAmpGate(p->buf, p->maxbin*2, p->AmpGateFunc, p->PvMaxAmp);
167 
168     ar = p->rslt;
169     memset(ar, 0, nsmps*sizeof(MYFLT));
170     if (UNLIKELY(early)) nsmps -= early;
171     oscphase = p->oscphase;
172     for (i = (int32_t) *p->ibinoffset; i < p->maxbin; i += binincr) {
173       lobits = ftp->lobits;
174       phase = (int32) *oscphase;
175       frq = p->buf[i * 2 + 1] * *p->kfmod;
176       if (p->buf[i * 2 + 1] == FL(0.0) || frq >= CS_ESR * FL(0.5)) {
177         incr = 0;               /* Hope then does not matter */
178         amp = FL(0.0);
179       }
180       else {
181         MYFLT tmp = frq * csound->sicvt;
182         incr = (int32) MYFLT2LONG(tmp);
183         amp = p->buf[i * 2];
184       }
185       for (n=offset;n<nsmps;n++) {
186         fract = PFRAC(phase);
187         ftab = ftp->ftable + (phase >> lobits);
188         v1 = *ftab++;
189         ar[n] += (v1 + (*ftab - v1) * fract) * amp;
190         phase += incr;
191         phase &= PHMASK;
192       }
193       *oscphase = (MYFLT) phase;
194       oscphase++;
195     }
196     return OK;
197  err1:
198     return csound->PerfError(csound, &(p->h), Str("pvadd: not initialised"));
199  err2:
200     return csound->PerfError(csound, &(p->h), Str("PVADD timpnt < 0"));
201 }
202 
pvaddset(CSOUND * csound,PVADD * p)203 int32_t pvaddset(CSOUND *csound, PVADD *p){
204     return pvaddset_(csound, p, 0);
205 }
206 
pvaddset_S(CSOUND * csound,PVADD * p)207 int32_t pvaddset_S(CSOUND *csound, PVADD *p){
208     return pvaddset_(csound, p, 1);
209 }
210 
211 
pvx_loadfile(CSOUND * csound,const char * fname,PVADD * p)212 static int32_t pvx_loadfile(CSOUND *csound, const char *fname, PVADD *p)
213 {
214     PVOCEX_MEMFILE  pp;
215 
216     if (UNLIKELY(csound->PVOCEX_LoadFile(csound, fname, &pp) != 0)) {
217       return csound->InitError(csound, Str("PVADD cannot load %s"), fname);
218     }
219     /* fft size must be <= PVFRAMSIZE (=8192) for Csound */
220     if (UNLIKELY(pp.fftsize > PVFRAMSIZE)) {
221       return csound->InitError(csound, Str("pvoc-ex file %s: "
222                                            "FFT size %d too large for Csound"),
223                                fname, (int32_t
224                                        ) pp.fftsize);
225     }
226     if (UNLIKELY(pp.fftsize < 128)) {
227       return csound->InitError(csound, Str("PV frame %d seems too small in %s"),
228                                pp.fftsize, fname);
229     }
230     /* have to reject m/c files for now, until opcodes upgraded */
231     if (UNLIKELY(pp.chans > 1)) {
232       return csound->InitError(csound, Str("pvoc-ex file %s is not mono"), fname);
233     }
234     /* ignore the window spec until we can use it! */
235     p->frSiz    = pp.fftsize;
236     p->frPtr    = (float*) pp.data;
237     p->maxFr    = pp.nframes - 1;
238     p->asr      = pp.srate;
239     /* factor by which to mult expand phase diffs (ratio of samp spacings) */
240     p->frPrtim = CS_ESR / (MYFLT) pp.overlap;
241     return OK;
242 }
243 
244