1 /*
2 pvinterp.c:
3
4 Copyright (C) 1996 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 /*********** PVINTERP, PVCROSS ***********/
26 /******** By Richard Karpen 1996 *********/
27 /*****************************************/
28
29 #include "pvoc.h"
30 #include <math.h>
31
32 #define WLN 1 /* time window is WLN*2*ksmps long */
33 #define OPWLEN (2*WLN*CS_KSMPS) /* manifest used for final time wdw */
34
35 /************************************************************/
36 /*************PVBUFREAD**************************************/
37 /************************************************************/
38
pvbufreadset_(CSOUND * csound,PVBUFREAD * p,int32_t stringname)39 int32_t pvbufreadset_(CSOUND *csound, PVBUFREAD *p, int32_t stringname)
40 {
41 char pvfilnam[MAXNAME];
42 PVOCEX_MEMFILE pp;
43 int32_t frInc, chans; /* THESE SHOULD BE SAVED IN PVOC STRUCT */
44
45 {
46 PVOC_GLOBALS *p_ = PVOC_GetGlobals(csound);
47 p_->pvbufreadaddr = p;
48 }
49
50 if (p->auxch.auxp == NULL) { /* if no buffers yet, alloc now */
51 /* Assumes PVDATASIZE, PVFFTSIZE, PVWINLEN constant */
52 MYFLT *fltp;
53 csound->AuxAlloc(csound,
54 (PVDATASIZE + PVFFTSIZE * 3 + PVWINLEN) * sizeof(MYFLT),
55 &p->auxch);
56 fltp = (MYFLT *) p->auxch.auxp;
57 p->lastPhase = fltp; fltp += PVDATASIZE; /* and insert addresses */
58 p->fftBuf = fltp; /* fltp += PVFFTSIZE; */ /* Not needed */
59 }
60
61 if (stringname==0){
62 if (csound->ISSTRCOD(*p->ifilno))
63 strNcpy(pvfilnam,get_arg_string(csound, *p->ifilno), MAXNAME-1);
64 else csound->strarg2name(csound, pvfilnam, p->ifilno, "pvoc.",0);
65 }
66 else strNcpy(pvfilnam, ((STRINGDAT *)p->ifilno)->data, MAXNAME-1);
67
68 if (UNLIKELY(csound->PVOCEX_LoadFile(csound, pvfilnam, &pp) != 0))
69 return csound->InitError(csound, Str("PVBUFREAD cannot load %s"),
70 pvfilnam);
71
72 p->frSiz = pp.fftsize;
73 frInc = pp.overlap;
74 chans = pp.chans;
75 p->asr = pp.srate;
76 if (UNLIKELY(p->asr != CS_ESR)) { /* & chk the data */
77 csound->Warning(csound, Str("%s's srate = %8.0f, orch's srate = %8.0f"),
78 pvfilnam, p->asr, CS_ESR);
79 }
80 if (UNLIKELY(p->frSiz > PVFRAMSIZE)) {
81 return csound->InitError(csound,
82 Str("PVOC frame %ld bigger than %ld in %s"),
83 (long) p->frSiz, (long) PVFRAMSIZE, pvfilnam);
84 }
85 if (UNLIKELY(p->frSiz < 128)) {
86 return csound->InitError(csound,
87 Str("PVOC frame %ld seems too small in %s"),
88 (long) p->frSiz, pvfilnam);
89 }
90 if (UNLIKELY(chans != 1)) {
91 return csound->InitError(csound, Str("%d chans (not 1) in PVOC file %s"),
92 (int32_t) chans, pvfilnam);
93 }
94 p->frPtr = (float*) pp.data;
95 p->maxFr = pp.nframes - 1;
96 p->frPktim = (MYFLT) CS_KSMPS / (MYFLT) frInc;
97 p->frPrtim = CS_ESR / (MYFLT) frInc;
98 p->prFlg = 1; /* true */
99 /* amplitude scale for PVOC */
100 /* p->scale = (MYFLT) pp.fftsize * ((MYFLT) pp.fftsize / (MYFLT) pp.winsize);
101 */
102 p->scale = (MYFLT) pp.fftsize * FL(0.5);
103 p->scale *= csound->GetInverseRealFFTScale(csound, pp.fftsize);
104
105 if (UNLIKELY((OPWLEN / 2 + 1) > PVWINLEN )) {
106 return csound->InitError(csound, Str("ksmps of %d needs wdw of %d, "
107 "max is %d for pv %s"),
108 CS_KSMPS, (int32_t) (OPWLEN / 2 + 1),
109 (int32_t) PVWINLEN, pvfilnam);
110 }
111
112 return OK;
113 }
114
pvbufreadset(CSOUND * csound,PVBUFREAD * p)115 int32_t pvbufreadset(CSOUND *csound, PVBUFREAD *p){
116 return pvbufreadset_(csound,p,0);
117 }
118
pvbufreadset_S(CSOUND * csound,PVBUFREAD * p)119 int32_t pvbufreadset_S(CSOUND *csound, PVBUFREAD *p){
120 return pvbufreadset_(csound,p,1);
121 }
122
pvbufread(CSOUND * csound,PVBUFREAD * p)123 int32_t pvbufread(CSOUND *csound, PVBUFREAD *p)
124 {
125 MYFLT frIndx;
126 MYFLT *buf = p->fftBuf;
127 int32_t size = pvfrsiz(p);
128
129 if (UNLIKELY(p->auxch.auxp == NULL)) goto err1; /* RWD fix */
130 if (UNLIKELY((frIndx = *p->ktimpnt * p->frPrtim) < 0)) goto err2;
131 if (frIndx > (MYFLT) p->maxFr) { /* not past last one */
132 frIndx = (MYFLT) p->maxFr;
133 if (UNLIKELY(p->prFlg)) {
134 p->prFlg = 0; /* false */
135 csound->Warning(csound, Str("PVOC ktimpnt truncated to last frame"));
136 }
137 }
138 FetchIn(p->frPtr, buf, size, frIndx);
139 p->buf = buf;
140
141 return OK;
142 err1:
143 return csound->PerfError(csound, &(p->h),
144 Str("pvbufread: not initialised"));
145 err2:
146 return csound->PerfError(csound, &(p->h), Str("PVOC timpnt < 0"));
147 }
148
149 /************************************************************/
150 /*************PVINTERP**************************************/
151 /************************************************************/
pvinterpset_(CSOUND * csound,PVINTERP * p,int32_t stringname)152 int32_t pvinterpset_(CSOUND *csound, PVINTERP *p, int32_t stringname)
153 {
154 uint32_t i;
155 char pvfilnam[MAXNAME];
156 PVOCEX_MEMFILE pp;
157 int32_t frInc, chans; /* THESE SHOULD BE SAVED IN PVOC STRUCT */
158
159 p->pp = PVOC_GetGlobals(csound);
160 p->pvbufread = p->pp->pvbufreadaddr;
161 if (UNLIKELY(p->pvbufread == NULL))
162 return csound->InitError(csound,
163 Str("pvinterp: associated pvbufread not found"));
164
165 if (p->auxch.auxp == NULL) { /* if no buffers yet, alloc now */
166 MYFLT *fltp;
167 csound->AuxAlloc(csound,
168 (PVDATASIZE + PVFFTSIZE * 3 + PVWINLEN) * sizeof(MYFLT),
169 &p->auxch);
170 fltp = (MYFLT *) p->auxch.auxp;
171 p->lastPhase = fltp; fltp += PVDATASIZE; /* and insert addresses */
172 p->fftBuf = fltp; fltp += PVFFTSIZE;
173 p->dsBuf = fltp; fltp += PVFFTSIZE;
174 p->outBuf = fltp; fltp += PVFFTSIZE;
175 p->window = fltp;
176 }
177
178 if (stringname==0){
179 if (csound->ISSTRCOD(*p->ifilno))
180 strNcpy(pvfilnam,get_arg_string(csound, *p->ifilno), MAXNAME-1);
181 else csound->strarg2name(csound, pvfilnam, p->ifilno, "pvoc.",0);
182 }
183 else strNcpy(pvfilnam, ((STRINGDAT *)p->ifilno)->data, MAXNAME-1);;
184 if (UNLIKELY(csound->PVOCEX_LoadFile(csound, pvfilnam, &pp) != 0))
185 return csound->InitError(csound, Str("PVINTERP cannot load %s"),
186 pvfilnam);
187
188 p->frSiz = pp.fftsize;
189 frInc = pp.overlap;
190 chans = pp.chans;
191 p->asr = pp.srate;
192 if (UNLIKELY(p->asr != CS_ESR)) { /* & chk the data */
193 csound->Warning(csound, Str("%s's srate = %8.0f, orch's srate = %8.0f"),
194 pvfilnam, p->asr, CS_ESR);
195 }
196 if (UNLIKELY(p->frSiz != p->pvbufread->frSiz)) {
197 return csound->InitError(csound,
198 Str("pvinterp: %s: frame size %d does not "
199 "match pvbufread frame size %d\n"), pvfilnam,
200 (int32_t) p->frSiz, (int32_t) p->pvbufread->frSiz);
201 }
202 if (UNLIKELY(chans != 1)) {
203 return csound->InitError(csound, Str("%d chans (not 1) in PVOC file %s"),
204 (int32_t) chans, pvfilnam);
205 }
206 /* Check that pv->frSiz is a power of two too ? */
207 p->frPtr = (float*) pp.data;
208 p->baseFr = 0; /* point to first data frame */
209 p->maxFr = pp.nframes - 1;
210 /* highest possible frame index */
211 p->frPktim = (MYFLT) CS_KSMPS / (MYFLT) frInc;
212 /* factor by which to mult expand phase diffs (ratio of samp spacings) */
213 p->frPrtim = CS_ESR / (MYFLT) frInc;
214 /* factor by which to mulitply 'real' time index to get frame index */
215 /* amplitude scale for PVOC */
216 /* p->scale = (MYFLT) pp.fftsize * ((MYFLT) pp.fftsize / (MYFLT) pp.winsize);
217 */
218 p->scale = (MYFLT) pp.fftsize * FL(0.5);
219 p->scale *= csound->GetInverseRealFFTScale(csound, pp.fftsize);
220 /* 2*incr/OPWLEN scales down for win ovlp, windo'd 1ce (but 2ce?) */
221 /* 1/frSiz is the required scale down before (i)FFT */
222 p->prFlg = 1; /* true */
223 p->opBpos = 0;
224 p->lastPex = FL(1.0); /* needs to know last pitchexp to update phase */
225 /* Set up time window */
226 memset(p->lastPhase,'\0', pvdasiz(p)*sizeof(MYFLT));
227 /* for (i = 0; i < pvdasiz(p); ++i) { /\* or maybe pvdasiz(p) *\/ */
228 /* p->lastPhase[i] = FL(0.0); */
229 /* } */
230 if (UNLIKELY((OPWLEN / 2 + 1) > PVWINLEN)) {
231 return csound->InitError(csound, Str("ksmps of %d needs wdw of %d, "
232 "max is %d for pv %s"),
233 CS_KSMPS, (OPWLEN / 2 + 1),
234 PVWINLEN, pvfilnam);
235 }
236 for (i = 0; i < OPWLEN / 2 + 1; ++i) /* time window is OPWLEN long */
237 p->window[i] = (MYFLT) (0.5 - 0.5 * cos(TWOPI*(double)i/(double)OPWLEN));
238 /* NB: HANNING */
239 memset(p->outBuf, 0, pvfrsiz(p)*sizeof(MYFLT));
240 /* for (i = 0; i< pvfrsiz(p); ++i) */
241 /* p->outBuf[i] = FL(0.0); */
242 MakeSinc(p->pp); /* sinctab is same for all instances */
243
244 return OK;
245 }
246
pvinterpset(CSOUND * csound,PVINTERP * p)247 int32_t pvinterpset(CSOUND *csound, PVINTERP *p){
248 return pvinterpset_(csound,p,0);
249 }
250
pvinterpset_S(CSOUND * csound,PVINTERP * p)251 int32_t pvinterpset_S(CSOUND *csound, PVINTERP *p){
252 return pvinterpset_(csound,p,1);
253 }
254
255
pvinterp(CSOUND * csound,PVINTERP * p)256 int32_t pvinterp(CSOUND *csound, PVINTERP *p)
257 {
258 MYFLT *ar = p->rslt;
259 MYFLT frIndx;
260 MYFLT *buf = p->fftBuf;
261 MYFLT *buf2 = p->dsBuf;
262 int32_t asize = pvdasiz(p); /* fix */
263 int32_t size = pvfrsiz(p);
264 int32_t buf2Size, outlen;
265 int32_t circBufSize = PVFFTSIZE;
266 MYFLT pex, scaleFac = p->scale;
267 PVBUFREAD *q = p->pvbufread;
268 int32 i, j;
269
270 if (UNLIKELY(p->auxch.auxp == NULL)) goto err1; /* RWD Fix */
271 pex = *p->kfmod;
272 outlen = (int32_t) (((MYFLT) size) / pex);
273 /* use outlen to check window/krate/transpose combinations */
274 if (UNLIKELY(outlen>PVFFTSIZE)) /* Maximum transposition down is one octave */
275 /* ..so we won't run into buf2Size problems */
276 goto err2;
277 if (UNLIKELY(outlen<(int32_t)(2*CS_KSMPS)))
278 goto err3; /* minimum post-squeeze windowlength */
279 buf2Size = OPWLEN; /* always window to same length after DS */
280 if (UNLIKELY((frIndx = *p->ktimpnt * p->frPrtim) < 0)) goto err4;
281 if (frIndx > (MYFLT)p->maxFr) { /* not past last one */
282 frIndx = (MYFLT)p->maxFr;
283 if (UNLIKELY(p->prFlg)) {
284 p->prFlg = 0; /* false */
285 csound->Warning(csound, Str("PVOC ktimpnt truncated to last frame"));
286 }
287 }
288 FetchIn(p->frPtr, buf, size, frIndx);
289
290 /* Here's where the interpolation happens ***********************/
291 if (pex > FL(1.0))
292 scaleFac /= pex;
293 for (i = 0, j = 1; i <= size; i += 2, j += 2) {
294 buf[i] = buf[i] * *p->kampscale2;
295 q->buf[i] = q->buf[i] * *p->kampscale1;
296 buf[j] = buf[j] * *p->kfreqscale2;
297 q->buf[j] = q->buf[j] * *p->kfreqscale1;
298 buf[i] = (buf[i] + ((q->buf[i] - buf[i]) * *p->kampinterp)) * scaleFac;
299 buf[j] = (buf[j] + ((q->buf[j] - buf[j]) * *p->kfreqinterp));
300 }
301 /*******************************************************************/
302 FrqToPhase(buf, asize, pex * (MYFLT) CS_KSMPS, p->asr,
303 (MYFLT) (0.5 * ((pex / p->lastPex) - 1)));
304 /* accumulate phase and wrap to range -PI to PI */
305 RewrapPhase(buf, asize, p->lastPhase);
306
307 Polar2Real_PVOC(csound, buf, (int32_t) size);
308
309 if (pex != FL(1.0))
310 UDSample(p->pp, buf,
311 (FL(0.5) * ((MYFLT) size - pex * (MYFLT) buf2Size)), buf2,
312 size, buf2Size, pex);
313 else
314 memcpy(buf2, buf + (int32_t) ((size - buf2Size) >> 1),
315 sizeof(MYFLT) * buf2Size);
316 ApplyHalfWin(buf2, p->window, buf2Size);
317
318 addToCircBuf(buf2, p->outBuf, p->opBpos, CS_KSMPS, circBufSize);
319 writeClrFromCircBuf(p->outBuf, ar, p->opBpos, CS_KSMPS, circBufSize);
320 p->opBpos += CS_KSMPS;
321 if (UNLIKELY(p->opBpos > circBufSize))
322 p->opBpos -= circBufSize;
323 addToCircBuf(buf2 + CS_KSMPS, p->outBuf, p->opBpos,
324 buf2Size - CS_KSMPS, circBufSize);
325 p->lastPex = pex; /* needs to know last pitchexp to update phase */
326
327 return OK;
328 err1:
329 return csound->PerfError(csound, &(p->h),
330 Str("pvinterp: not initialised"));
331 err2:
332 return csound->PerfError(csound, &(p->h),
333 Str("PVOC transpose too low"));
334 err3:
335 return csound->PerfError(csound, &(p->h),
336 Str("PVOC transpose too high"));
337 err4:
338 return csound->PerfError(csound, &(p->h), Str("PVOC timpnt < 0"));
339 }
340
341 /************************************************************/
342 /************* PVCROSS **************************************/
343 /************************************************************/
pvcrossset_(CSOUND * csound,PVCROSS * p,int32_t stringname)344 int32_t pvcrossset_(CSOUND *csound, PVCROSS *p, int32_t stringname)
345 {
346 uint32_t i;
347 char pvfilnam[MAXNAME];
348 PVOCEX_MEMFILE pp;
349 int32_t frInc, chans; /* THESE SHOULD BE SAVED IN PVOC STRUCT */
350
351 p->pp = PVOC_GetGlobals(csound);
352 p->pvbufread = p->pp->pvbufreadaddr;
353 if (UNLIKELY(p->pvbufread == NULL))
354 return csound->InitError(csound,
355 Str("pvcross: associated pvbufread not found"));
356
357 if (p->auxch.auxp == NULL) { /* if no buffers yet, alloc now */
358 MYFLT *fltp;
359 csound->AuxAlloc(csound,
360 (PVDATASIZE + PVFFTSIZE * 3 + PVWINLEN) * sizeof(MYFLT),
361 &p->auxch);
362 fltp = (MYFLT *) p->auxch.auxp;
363 p->lastPhase = fltp; fltp += PVDATASIZE; /* and insert addresses */
364 p->fftBuf = fltp; fltp += PVFFTSIZE;
365 p->dsBuf = fltp; fltp += PVFFTSIZE;
366 p->outBuf = fltp; fltp += PVFFTSIZE;
367 p->window = fltp;
368 }
369 if (stringname==0){
370 if (csound->ISSTRCOD(*p->ifilno))
371 strNcpy(pvfilnam,get_arg_string(csound, *p->ifilno), MAXNAME-1);
372 else csound->strarg2name(csound, pvfilnam, p->ifilno, "pvoc.",0);
373 }
374 else strNcpy(pvfilnam, ((STRINGDAT *)p->ifilno)->data, MAXNAME-1);
375
376 if (UNLIKELY(csound->PVOCEX_LoadFile(csound, pvfilnam, &pp) != 0))
377 return csound->InitError(csound, Str("PVCROSS cannot load %s"), pvfilnam);
378
379 p->frSiz = pp.fftsize;
380 frInc = pp.overlap;
381 chans = pp.chans;
382 p->asr = pp.srate;
383 if (UNLIKELY(p->asr != CS_ESR)) { /* & chk the data */
384 csound->Warning(csound, Str("%s's srate = %8.0f, orch's srate = %8.0f"),
385 pvfilnam, p->asr, CS_ESR);
386 }
387 if (UNLIKELY(p->frSiz != p->pvbufread->frSiz)) {
388 return csound->InitError(csound,
389 Str("pvcross: %s: frame size %d does not "
390 "match pvbufread frame size %d\n"), pvfilnam,
391 (int32_t) p->frSiz, (int32_t) p->pvbufread->frSiz);
392 }
393 if (UNLIKELY(chans != 1)) {
394 return csound->InitError(csound, Str("%d chans (not 1) in PVOC file %s"),
395 (int32_t) chans, pvfilnam);
396 }
397 /* Check that pv->frSiz is a power of two too ? */
398 p->frPtr = (float*) pp.data;
399 p->baseFr = 0; /* point to first data frame */
400 p->maxFr = pp.nframes - 1;
401 /* highest possible frame index */
402 p->frPktim = (MYFLT) CS_KSMPS / (MYFLT) frInc;
403 /* factor by which to mult expand phase diffs (ratio of samp spacings) */
404 p->frPrtim = CS_ESR / (MYFLT) frInc;
405 /* factor by which to mulitply 'real' time index to get frame index */
406 /* amplitude scale for PVOC */
407 /* p->scale = (MYFLT) pp.fftsize * ((MYFLT) pp.fftsize / (MYFLT) pp.winsize);
408 */
409 p->scale = (MYFLT) pp.fftsize * FL(0.5);
410 p->scale *= csound->GetInverseRealFFTScale(csound, pp.fftsize);
411 p->prFlg = 1; /* true */
412 p->opBpos = 0;
413 p->lastPex = FL(1.0); /* needs to know last pitchexp to update phase */
414 /* Set up time window */
415 memset(p->lastPhase, '\0', pvdasiz(p)*sizeof(MYFLT));
416 /* for (i = 0; i < pvdasiz(p); ++i) { /\* or maybe pvdasiz(p) *\/ */
417 /* p->lastPhase[i] = FL(0.0); */
418 /* } */
419 if (UNLIKELY((OPWLEN / 2 + 1) > PVWINLEN )) {
420 return csound->InitError(csound, Str("ksmps of %d needs wdw of %d, "
421 "max is %d for pv %s"),
422 CS_KSMPS, (OPWLEN / 2 + 1),
423 PVWINLEN, pvfilnam);
424 }
425 for (i = 0; i < OPWLEN / 2 + 1; ++i) /* time window is OPWLEN long */
426 p->window[i] = (MYFLT) (0.5 - 0.5 * cos(TWOPI*(double)i/(double)OPWLEN));
427 /* NB: HANNING */
428 memset(p->outBuf, 0, pvfrsiz(p)*sizeof(MYFLT));
429 /* for (i = 0; i < pvfrsiz(p); ++i) */
430 /* p->outBuf[i] = FL(0.0); */
431 MakeSinc(p->pp); /* sinctab is same for all instances */
432 if (p->memenv.auxp == NULL || p->memenv.size < pvdasiz(p)*sizeof(MYFLT))
433 csound->AuxAlloc(csound, pvdasiz(p) * sizeof(MYFLT), &p->memenv);
434 return OK;
435 }
436
pvcrossset(CSOUND * csound,PVCROSS * p)437 int32_t pvcrossset(CSOUND *csound, PVCROSS *p){
438 return pvcrossset_(csound,p,0);
439 }
440
pvcrossset_S(CSOUND * csound,PVCROSS * p)441 int32_t pvcrossset_S(CSOUND *csound, PVCROSS *p) {
442 return pvcrossset_(csound,p,1);
443 }
444
pvcross(CSOUND * csound,PVCROSS * p)445 int32_t pvcross(CSOUND *csound, PVCROSS *p)
446 {
447 MYFLT *ar = p->rslt;
448 MYFLT frIndx;
449 MYFLT *buf = p->fftBuf;
450 MYFLT *buf2 = p->dsBuf;
451 int32_t asize = pvdasiz(p); /* fix */
452 int32_t size = pvfrsiz(p);
453 int32_t buf2Size, outlen;
454 int32_t circBufSize = PVFFTSIZE;
455 int32_t specwp = (int32_t) *p->ispecwp; /* spectral warping flag */
456 MYFLT pex, scaleFac = p->scale;
457 PVBUFREAD *q = p->pvbufread;
458 int32 i, j;
459 MYFLT ampscale1 = *p->kampscale1;
460 MYFLT ampscale2 = *p->kampscale2;
461
462 if (UNLIKELY(p->auxch.auxp == NULL)) goto err1; /* RWD Fix */
463 pex = *p->kfmod;
464 outlen = (int32_t) (((MYFLT) size) / pex);
465 /* use outlen to check window/krate/transpose combinations */
466 if (UNLIKELY(outlen>PVFFTSIZE)) /* Maximum transposition down is one octave */
467 /* ..so we won't run into buf2Size problems */
468 goto err2;
469 if (UNLIKELY(outlen<(int32_t)(2*CS_KSMPS)))
470 goto err3; /* minimum post-squeeze windowlength */
471 buf2Size = OPWLEN; /* always window to same length after DS */
472 if (UNLIKELY((frIndx = *p->ktimpnt * p->frPrtim) < 0)) goto err4;
473 if (frIndx > (MYFLT) p->maxFr) { /* not past last one */
474 frIndx = (MYFLT) p->maxFr;
475 if (p->prFlg) {
476 p->prFlg = 0; /* false */
477 csound->Warning(csound, Str("PVOC ktimpnt truncated to last frame"));
478 }
479 }
480
481 FetchIn(p->frPtr, buf, size, frIndx);
482
483 /**** Apply amplitudes from pvbufread ********/
484 if (pex > FL(1.0))
485 scaleFac /= pex;
486 for (i = 0, j = 0; i <= size; i += 2, j++)
487 buf[i] = ((buf[i] * ampscale2) + (q->buf[i] * ampscale1)) * scaleFac;
488 /***************************************************/
489
490 FrqToPhase(buf, asize, pex * (MYFLT) CS_KSMPS, p->asr,
491 (MYFLT) (0.5 * ((pex / p->lastPex) - 1)));
492 /* accumulate phase and wrap to range -PI to PI */
493 RewrapPhase(buf, asize, p->lastPhase);
494
495 if (specwp == 0 || (p->prFlg)++ == -(int32_t) specwp) {
496 /* ?screws up when prFlg used */
497 /* specwp=0 => normal; specwp = -n => just nth frame */
498 #ifdef BETA
499 if (specwp < 0)
500 csound->Message(csound, Str("PVOC debug: one frame gets through\n"));
501 #endif
502 if (specwp > 0)
503 PreWarpSpec(buf, asize, pex, (MYFLT *)p->memenv.auxp);
504
505 Polar2Real_PVOC(csound, buf, (int32_t) size);
506
507 if (pex != FL(1.0))
508 UDSample(p->pp, buf,
509 (FL(0.5) * ((MYFLT) size - pex * (MYFLT) buf2Size)), buf2,
510 size, buf2Size, pex);
511 else
512 memcpy(buf2, buf + (int32_t) ((size - buf2Size) >> 1),
513 sizeof(MYFLT) * buf2Size);
514 if (specwp >= 0)
515 ApplyHalfWin(buf2, p->window, buf2Size);
516 }
517 else {
518 memset(buf2, 0, buf2Size*sizeof(MYFLT));
519 }
520
521 addToCircBuf(buf2, p->outBuf, p->opBpos, CS_KSMPS, circBufSize);
522 writeClrFromCircBuf(p->outBuf, ar, p->opBpos, CS_KSMPS, circBufSize);
523 p->opBpos += CS_KSMPS;
524 if (UNLIKELY(p->opBpos > circBufSize))
525 p->opBpos -= circBufSize;
526 addToCircBuf(buf2 + CS_KSMPS, p->outBuf, p->opBpos,
527 buf2Size - CS_KSMPS, circBufSize);
528 p->lastPex = pex; /* needs to know last pitchexp to update phase */
529
530 return OK;
531 err1:
532 return csound->PerfError(csound, &(p->h),
533 Str("pvcross: not initialised"));
534 err2:
535 return csound->PerfError(csound, &(p->h),
536 Str("PVOC transpose too low"));
537 err3:
538 return csound->PerfError(csound, &(p->h),
539 Str("PVOC transpose too high"));
540 err4:
541 return csound->PerfError(csound, &(p->h),
542 Str("PVOC timpnt < 0"));
543 }
544