1 /*
2 ugens8.c:
3
4 Copyright (C) 1991, 1998, 2000 Dan Ellis, Richard Karpen, Richard Dobson
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 "pvoc.h" /* UGENS8.C */
25 #include <math.h>
26
27 /* RWD 10:9:2000 read pvocex file format */
28 #include "pvfileio.h"
29 static int32_t pvx_loadfile(CSOUND *, const char *, PVOC *);
30
31 /********************************************/
32 /* Originated by Dan Ellis, MIT */
33 /* Spectral Extraction and Amplitude Gating */
34 /* added by Richard Karpen, University */
35 /* of Washington, Seattle 1998 */
36 /********************************************/
37
38 #define WLN 1 /* time window is WLN*2*ksmps long */
39 #define OPWLEN (2*WLN*CS_KSMPS) /* manifest used for final time wdw */
40
pvset_(CSOUND * csound,PVOC * p,int32_t stringname)41 int32_t pvset_(CSOUND *csound, PVOC *p, int32_t stringname)
42 {
43 uint32_t i;
44 int32 memsize;
45 char pvfilnam[MAXNAME];
46 int32_t size; /* THESE SHOULD BE SAVED IN PVOC STRUCT */
47 FUNC *AmpGateFunc = NULL;
48
49 p->pp = PVOC_GetGlobals(csound);
50
51 if (stringname==0){
52 if (csound->ISSTRCOD(*p->ifilno))
53 strNcpy(pvfilnam,get_arg_string(csound, *p->ifilno), MAXNAME-1);
54 else csound->strarg2name(csound, pvfilnam, p->ifilno, "pvoc.",0);
55 }
56 else strNcpy(pvfilnam, ((STRINGDAT *)p->ifilno)->data, MAXNAME-1);
57
58 if (UNLIKELY(pvx_loadfile(csound, pvfilnam, p) != OK))
59 return NOTOK;
60
61 memsize = (int32) (PVDATASIZE + PVFFTSIZE * 3 + PVWINLEN);
62 if (*p->imode == 1 || *p->imode == 2) {
63 int32 n = (int32) ((p->frSiz + 2L) * (p->maxFr + 2L));
64 #ifdef USE_DOUBLE
65 n = (n + 1L) * (int32) sizeof(float) / (int32) sizeof(double);
66 #endif
67 memsize += n;
68 }
69
70 if (p->auxch.auxp == NULL || memsize != p->mems) {
71 MYFLT *fltp;
72 csound->AuxAlloc(csound, (memsize * sizeof(MYFLT)), &p->auxch);
73 fltp = (MYFLT *) p->auxch.auxp;
74 p->lastPhase = fltp; fltp += PVDATASIZE; /* and insert addresses */
75 p->fftBuf = fltp; fltp += PVFFTSIZE;
76 p->dsBuf = fltp; fltp += PVFFTSIZE;
77 p->outBuf = fltp; fltp += PVFFTSIZE;
78 p->window = fltp;
79 if (*p->imode == 1 || *p->imode == 2) {
80 fltp += PVWINLEN;
81 p->pvcopy = (float*) ((void*) fltp);
82 }
83 }
84 p->mems = memsize;
85 p->frPktim = ((MYFLT)CS_KSMPS)/((MYFLT) p->frInc);
86 /* factor by which to mult expand phase diffs (ratio of samp spacings) */
87 p->frPrtim = CS_ESR/((MYFLT) p->frInc);
88 /* factor by which to mulitply 'real' time index to get frame index */
89 size = pvfrsiz(p); /* size used in def of OPWLEN ? */
90 /* 2*incr/OPWLEN scales down for win ovlp, windo'd 1ce (but 2ce?) */
91 /* 1/frSiz is the required scale down before (i)FFT */
92 p->prFlg = 1; /* true */
93 p->opBpos = 0;
94 p->lastPex = FL(1.0); /* needs to know last pitchexp to update phase */
95 /* Set up time window */
96 memset(p->lastPhase, 0, sizeof(MYFLT)*pvdasiz(p));
97 /* for (i=0; i < pvdasiz(p); ++i) { /\* or maybe pvdasiz(p) *\/ */
98 /* p->lastPhase[i] = FL(0.0); */
99 /* } */
100 if (UNLIKELY((OPWLEN/2 + 1)>PVWINLEN )) {
101 return csound->InitError(csound, Str("ksmps of %d needs wdw of %d, "
102 "max is %d for pv %s"),
103 CS_KSMPS, (OPWLEN/2 + 1), PVWINLEN,
104 pvfilnam);
105 }
106
107 if (*p->igatefun > 0)
108 if (UNLIKELY((AmpGateFunc = csound->FTnp2Find(csound, p->igatefun)) == NULL))
109 return NOTOK;
110 p->AmpGateFunc = AmpGateFunc;
111
112 if (*p->igatefun > 0)
113 p->PvMaxAmp = PvocMaxAmp(p->frPtr, size, p->maxFr);
114
115 if (*p->imode == 1 || *p->imode == 2) {
116 SpectralExtract(p->frPtr, p->pvcopy, size, p->maxFr,
117 (int32_t) *p->imode, *p->ifreqlim);
118 p->frPtr = p->pvcopy;
119 }
120
121 for (i=0; i < OPWLEN / 2 + 1; ++i) /* time window is OPWLEN long */
122 p->window[i] = (FL(0.5) - FL(0.5) * COS(TWOPI_F*(MYFLT)i/(MYFLT)OPWLEN));
123 /* NB: HANNING */
124 memset(p->outBuf, 0, sizeof(MYFLT)*pvfrsiz(p));
125 /* for (i=0; i< pvfrsiz(p); ++i) */
126 /* p->outBuf[i] = FL(0.0); */
127 MakeSinc(p->pp); /* sinctab is same for all instances */
128
129 if (p->memenv.auxp == NULL || p->memenv.size < pvdasiz(p)*sizeof(MYFLT))
130 csound->AuxAlloc(csound, pvdasiz(p) * sizeof(MYFLT), &p->memenv);
131
132 return OK;
133 }
134
pvset(CSOUND * csound,PVOC * p)135 int32_t pvset(CSOUND *csound, PVOC *p){
136 return pvset_(csound,p,0);
137 }
138
pvset_S(CSOUND * csound,PVOC * p)139 int32_t pvset_S(CSOUND *csound, PVOC *p){
140 return pvset_(csound,p,1);
141 }
142
143
pvoc(CSOUND * csound,PVOC * p)144 int32_t pvoc(CSOUND *csound, PVOC *p)
145 {
146 MYFLT *ar = p->rslt;
147 MYFLT frIndx;
148 MYFLT *buf = p->fftBuf;
149 MYFLT *buf2 = p->dsBuf;
150 int32_t asize = pvdasiz(p); /* new */
151 int32_t size = pvfrsiz(p);
152 int32_t buf2Size, outlen;
153 int32_t circBufSize = PVFFTSIZE;
154 int32_t specwp = (int32_t)*p->ispecwp; /* spectral warping flag */
155 MYFLT pex, scaleFac;
156 uint32_t offset = p->h.insdshead->ksmps_offset;
157 uint32_t early = p->h.insdshead->ksmps_no_end;
158 uint32_t i, nsmps = CS_KSMPS;
159
160 if (UNLIKELY(p->auxch.auxp == NULL)) goto err1;
161 pex = *p->kfmod;
162 outlen = (int32_t) (((MYFLT) size) / pex);
163 /* use outlen to check window/krate/transpose combinations */
164 if (UNLIKELY(outlen>PVFFTSIZE)) /* Maximum transposition down is one octave */
165 goto err2; /* ..so we won't run into buf2Size problems */
166 if (UNLIKELY(outlen<(int32_t)(2*nsmps))) /* minimum post-squeeze windowlength */
167 goto err3;
168 buf2Size = OPWLEN; /* always window to same length after DS */
169 if (UNLIKELY((frIndx = *p->ktimpnt * p->frPrtim) < 0)) goto err4;
170 if (frIndx > p->maxFr) { /* not past last one */
171 frIndx = (MYFLT)p->maxFr;
172 if (UNLIKELY(p->prFlg)) {
173 p->prFlg = 0; /* false */
174 csound->Warning(csound, Str("PVOC ktimpnt truncated to last frame"));
175 }
176 }
177 FetchIn(p->frPtr, buf, size, frIndx);
178
179 if (*p->igatefun > 0)
180 PvAmpGate(buf,size, p->AmpGateFunc, p->PvMaxAmp);
181
182 FrqToPhase(buf, asize, pex * (MYFLT) nsmps, p->asr,
183 FL(0.5) * ((pex / p->lastPex) - FL(1.0)));
184 /* accumulate phase and wrap to range -PI to PI */
185 RewrapPhase(buf, asize, p->lastPhase);
186
187 if (specwp > 0){
188 /* RWD: THIS CAUSED MASSIVE MEMORY ERROR, BUT DOESN'T WORK ANYWAY */
189 PreWarpSpec(buf, asize, pex, (MYFLT *)p->memenv.auxp);
190 }
191
192 Polar2Real_PVOC(csound, buf, size);
193
194 if (pex != FL(1.0))
195 UDSample(p->pp, buf, (FL(0.5) * ((MYFLT) size - pex * (MYFLT) buf2Size)),
196 buf2, size, buf2Size, pex);
197 else
198 memcpy(buf2, buf + (int32_t) ((size - buf2Size) >> 1),
199 sizeof(MYFLT) * buf2Size);
200 ApplyHalfWin(buf2, p->window, buf2Size);
201 addToCircBuf(buf2, p->outBuf, p->opBpos, nsmps, circBufSize);
202 writeClrFromCircBuf(p->outBuf, ar, p->opBpos, nsmps, circBufSize);
203 p->opBpos += nsmps;
204 if (UNLIKELY(p->opBpos > circBufSize))
205 p->opBpos -= circBufSize;
206 addToCircBuf(buf2 + nsmps, p->outBuf,
207 p->opBpos, buf2Size - nsmps, circBufSize);
208 p->lastPex = pex; /* needs to know last pitchexp to update phase */
209 /* scale output */
210 scaleFac = p->scale;
211 if (pex > FL(1.0))
212 scaleFac /= pex;
213 if (UNLIKELY(offset)) memset(p->rslt, '\0', offset*sizeof(MYFLT));
214 if (UNLIKELY(early)) {
215 nsmps -= early;
216 memset(&p->rslt[nsmps], '\0', early*sizeof(MYFLT));
217 }
218 for (i = offset; i < nsmps; i++)
219 p->rslt[i] *= scaleFac;
220
221 return OK;
222 err1:
223 return csound->PerfError(csound, &(p->h), Str("pvoc: not initialised"));
224 err2:
225 return csound->PerfError(csound, &(p->h),
226 Str("PVOC transpose too low"));
227 err3:
228 return csound->PerfError(csound, &(p->h),
229 Str("PVOC transpose too high"));
230 err4:
231 return csound->PerfError(csound, &(p->h),
232 Str("PVOC timpnt < 0"));
233 }
234
235 /* RWD 8:2001: custom version of ldmemfile();
236 enables pvfileio funcs to apply byte-reversal if needed.
237
238 this version applies scaling to match existing pvanal format
239 */
pvx_loadfile(CSOUND * csound,const char * fname,PVOC * p)240 static int32_t pvx_loadfile(CSOUND *csound, const char *fname, PVOC *p)
241 {
242 PVOCEX_MEMFILE pp;
243
244 if (UNLIKELY(csound->PVOCEX_LoadFile(csound, fname, &pp) != 0)) {
245 return csound->InitError(csound, Str("PVOC cannot load %s"), fname);
246 }
247 /* fft size must be <= PVFRAMSIZE (=8192) for Csound */
248 if (UNLIKELY(pp.fftsize > PVFRAMSIZE)) {
249 return csound->InitError(csound, Str("pvoc-ex file %s: "
250 "FFT size %d too large for Csound"),
251 fname, (int32_t) pp.fftsize);
252 }
253 /* have to reject m/c files for now, until opcodes upgraded */
254 if (UNLIKELY(pp.chans > 1)) {
255 return csound->InitError(csound, Str("pvoc-ex file %s is not mono"), fname);
256 }
257 /* ignore the window spec until we can use it! */
258 p->frSiz = pp.fftsize;
259 p->frPtr = (float*) pp.data;
260 p->baseFr = 0; /* point to first data frame */
261 /* highest possible frame index */
262 p->maxFr = pp.nframes - 1;
263 p->frInc = pp.overlap;
264 p->chans = pp.chans;
265 p->asr = pp.srate;
266 /* amplitude scale for PVOC */
267 /* p->scale = (MYFLT) pp.fftsize * ((MYFLT) pp.fftsize / (MYFLT) pp.winsize);
268 */
269 p->scale = (MYFLT) pp.fftsize * FL(0.5);
270 p->scale *= csound->GetInverseRealFFTScale(csound, pp.fftsize);
271
272 return OK;
273 }
274
275