1 /*
2 diskin2.c:
3
4 Copyright (C) 2005 Istvan Varga
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 "csoundCore.h"
25 #include "soundio.h"
26 #include "diskin2.h"
27 #include <math.h>
28 #include <inttypes.h>
29
30 typedef struct DISKIN_INST_ {
31 CSOUND *csound;
32 DISKIN2 *diskin;
33 struct DISKIN_INST_ *nxt;
34 } DISKIN_INST;
35
36
diskin2_read_buffer(CSOUND * csound,DISKIN2 * p,int32_t bufReadPos)37 static CS_NOINLINE void diskin2_read_buffer(CSOUND *csound,
38 DISKIN2 *p, int32_t bufReadPos)
39 {
40 MYFLT *tmp;
41 int32_t nsmps;
42 int32_t i;
43 IGN(csound);
44 /* swap buffer pointers */
45 tmp = p->buf;
46 p->buf = p->prvBuf;
47 p->prvBuf = tmp;
48 /* check if requested data can be found in previously used buffer */
49 i = (int32_t)((int32_t) bufReadPos + (p->bufStartPos - p->prvBufStartPos));
50 if ((uint32_t) i < (uint32_t) p->bufSize) {
51 int32_t tmp2;
52 /* yes, only need to swap buffers and return */
53 tmp2 = p->bufStartPos;
54 p->bufStartPos = p->prvBufStartPos;
55 p->prvBufStartPos = tmp2;
56 return;
57 }
58 /* save buffer position */
59 p->prvBufStartPos = p->bufStartPos;
60 /* calculate new buffer frame start position */
61 p->bufStartPos = p->bufStartPos + (int32_t) bufReadPos;
62 p->bufStartPos &= (~((int32_t) (p->bufSize - 1)));
63 i = 0;
64 if (p->bufStartPos >= 0L) {
65 /* number of sample frames to read */
66 nsmps = p->fileLength - p->bufStartPos;
67 if (nsmps > 0L) { /* if there is anything to read: */
68 if (nsmps > (int32_t) p->bufSize)
69 nsmps = (int32_t) p->bufSize;
70 nsmps *= (int32_t) p->nChannels;
71 sf_seek(p->sf, (sf_count_t) p->bufStartPos, SEEK_SET);
72 /* convert sample count to mono samples and read file */
73 i = (int32_t)sf_read_MYFLT(p->sf, p->buf, (sf_count_t) nsmps);
74 if (UNLIKELY(i < 0)) /* error ? */
75 i = 0; /* clear entire buffer to zero */
76 }
77 }
78 /* fill rest of buffer with zero samples */
79 memset(&p->buf[i], 0, sizeof(MYFLT)*(p->bufSize * p->nChannels-i));
80 /* while (i < (p->bufSize * p->nChannels)) */
81 /* p->buf[i++] = FL(0.0); */
82 }
83
84 /* Mix one sample frame from input file at location 'pos' to outputs */
85 /* of opcode 'p', at sample index 'n' (0 <= n < ksmps), with amplitude */
86 /* scale 'scl'. */
87
diskin2_get_sample(CSOUND * csound,DISKIN2 * p,int32_t fPos,int32_t n,MYFLT scl)88 static inline void diskin2_get_sample(CSOUND *csound,
89 DISKIN2 *p, int32_t fPos, int32_t n,
90 MYFLT scl)
91 {
92 int32_t bufPos, i;
93
94 if (p->wrapMode) {
95 if (UNLIKELY(fPos >= p->fileLength)){
96 fPos -= p->fileLength;
97 }
98 else if (UNLIKELY(fPos < 0L)){
99 fPos += p->fileLength;
100 }
101 }
102 bufPos = (int32_t)(fPos - p->bufStartPos);
103 if (UNLIKELY((uint32_t) bufPos >= (uint32_t) p->bufSize)) {
104 /* not in current buffer frame, need to read file */
105 diskin2_read_buffer(csound, p, bufPos);
106 /* recalculate buffer position */
107 bufPos = (int32_t)(fPos - p->bufStartPos);
108 }
109
110 if (p->aOut_buf == NULL){
111 MYFLT **aOut = p->aOut;
112 /* copy all channels from buffer */
113 if (p->nChannels == 1) {
114 aOut[0][n] += scl * p->buf[bufPos];
115 }
116 else if (p->nChannels == 2) {
117 bufPos += bufPos;
118 aOut[0][n] += scl * p->buf[bufPos];
119 aOut[1][n] += scl * p->buf[bufPos + 1];
120 }
121 else {
122 bufPos *= p->nChannels;
123 i = 0;
124 /* p->aOut[i++][n] += scl * p->buf[bufPos++]; */
125 /* p->aOut[i++][n] += scl * p->buf[bufPos++]; */
126 do {
127 aOut[i++][n] += scl * p->buf[bufPos++];
128 } while (i < p->nChannels);
129 }
130 } else{
131 MYFLT *aOut = p->aOut_buf;
132 int32_t chans = p->nChannels;
133 /* copy all channels from buffer */
134 if (chans == 1) {
135 aOut[n] += scl * p->buf[bufPos];
136 }
137 else if (chans == 2) {
138 bufPos += bufPos;
139 aOut[n*2] += scl * p->buf[bufPos];
140 aOut[n*2+1] += scl * p->buf[bufPos+1];
141 }
142 else {
143 bufPos *= chans;//p->nChannels;
144 i = 0;
145 do {
146 aOut[n*chans+i] += scl * p->buf[bufPos++];
147 } while (++i < chans);
148 }
149
150 }
151 }
152
153 /* ------------- set up fast sine generator ------------- */
154 /* Input args: */
155 /* a: amplitude */
156 /* f: frequency (-PI - PI) */
157 /* p: initial phase (0 - PI/2) */
158 /* c: 2.0 * cos(f) - 2.0 */
159 /* Output args: */
160 /* *x: first output sample */
161 /* *v: coefficients for calculating next sample as */
162 /* shown below: */
163 /* v = v + c * x */
164 /* x = x + v */
165 /* These values are calculated as follows: */
166 /* x = y[0] */
167 /* v = y[1] - (c + 1.0) * y[0] */
168 /* where y[0], and y[1] are the first, and */
169 /* second sample of the sine wave to be */
170 /* generated, respectively. */
171 /* -------- written by Istvan Varga, Jan 28 2002 -------- */
172
init_sine_gen(double a,double f,double p,double c,double * x,double * v)173 static inline void init_sine_gen(double a, double f, double p, double c,
174 double *x, double *v)
175 {
176 double y0, y1; /* these should be doubles */
177
178 y0 = sin(p);
179 y1 = sin(p + f);
180 *x = y0;
181 *v = y1 - (c * y0) - y0;
182 /* amp. scale */
183 *x *= a; *v *= a;
184 }
185
186 /* calculate buffer size in sample frames */
187
diskin2_calc_buffer_size(DISKIN2 * p,int32_t n_monoSamps)188 static int32_t diskin2_calc_buffer_size(DISKIN2 *p, int32_t n_monoSamps)
189 {
190 int32_t i, nFrames;
191
192 /* default to 4096 mono samples if zero or negative */
193 if (n_monoSamps <= 0)
194 n_monoSamps = 4096;
195 /* convert mono samples -> sample frames */
196 i = n_monoSamps / p->nChannels;
197 /* limit to sane range */
198 if (i < p->winSize)
199 i = p->winSize;
200 else if (i > 1048576)
201 i = 1048576;
202 /* buffer size must be an integer power of two, so round up */
203 nFrames = 64; /* will be at least 128 sample frames */
204 do {
205 nFrames <<= 1;
206 } while (nFrames < i);
207
208 return nFrames;
209 }
210
211 static const int32_t diskin2_format_table[11] = {
212 0,
213 SF_FORMAT_RAW | SF_FORMAT_PCM_16,
214 SF_FORMAT_RAW | SF_FORMAT_PCM_S8,
215 SF_FORMAT_RAW | SF_FORMAT_ALAW,
216 SF_FORMAT_RAW | SF_FORMAT_ULAW,
217 SF_FORMAT_RAW | SF_FORMAT_PCM_16,
218 SF_FORMAT_RAW | SF_FORMAT_PCM_32,
219 SF_FORMAT_RAW | SF_FORMAT_FLOAT,
220 SF_FORMAT_RAW | SF_FORMAT_PCM_U8,
221 SF_FORMAT_RAW | SF_FORMAT_PCM_24,
222 SF_FORMAT_RAW | SF_FORMAT_DOUBLE
223 };
224
225 static int32_t diskin2_init_(CSOUND *csound, DISKIN2 *p, int32_t stringname);
226
diskin2_init(CSOUND * csound,DISKIN2 * p)227 int32_t diskin2_init(CSOUND *csound, DISKIN2 *p) {
228 p->SkipInit = *p->iSkipInit;
229 p->WinSize = *p->iWinSize;
230 p->BufSize = *p->iBufSize;
231 p->fforceSync = *p->forceSync;
232 return diskin2_init_(csound,p,0);
233 }
234
diskin2_init_S(CSOUND * csound,DISKIN2 * p)235 int32_t diskin2_init_S(CSOUND *csound, DISKIN2 *p) {
236 p->SkipInit = *p->iSkipInit;
237 p->WinSize = *p->iWinSize;
238 p->BufSize = *p->iBufSize;
239 p->fforceSync = *p->forceSync;
240 return diskin2_init_(csound,p,1);
241 }
242
243 /* VL 11-01-13 diskin_init - calls diskin2_init */
244
diskin_init(CSOUND * csound,DISKIN2 * p)245 int32_t diskin_init(CSOUND *csound, DISKIN2 *p){
246 p->SkipInit = *p->iWinSize;
247 p->WinSize = 2;
248 p->BufSize = 0;
249 p->fforceSync = 0;
250 return diskin2_init_(csound,p,0);
251 }
252
diskin_init_S(CSOUND * csound,DISKIN2 * p)253 int32_t diskin_init_S(CSOUND *csound, DISKIN2 *p){
254 p->SkipInit = *p->iWinSize;
255 p->WinSize = 2;
256 p->BufSize = 0;
257 p->fforceSync = 0;
258 return diskin2_init_(csound,p,1);
259 }
260
261 /*
262 * soundin now uses diskin2 VL 24-12-16
263 */
sndinset(CSOUND * csound,DISKIN2 * p)264 int32_t sndinset(CSOUND *csound, DISKIN2 *p) {
265 int32_t ret;
266 p->SkipInit = *p->iWrapMode;
267 p->iSampleFormat = p->iSkipTime;
268 p->iSkipTime = p->kTranspose;
269 p->WinSize = 2;
270 p->BufSize = 0;
271 p->fforceSync = 0;
272 ret = diskin2_init_(csound,p,0);
273 return ret;
274 }
275
sndinset_S(CSOUND * csound,DISKIN2 * p)276 int32_t sndinset_S(CSOUND *csound, DISKIN2 *p){
277 int32_t ret;
278 p->SkipInit = *p->iWrapMode;
279 p->iSampleFormat = p->iSkipTime;
280 p->iSkipTime = p->kTranspose;
281 p->WinSize = 2;
282 p->BufSize = 0;
283 p->fforceSync = 0;
284 ret = diskin2_init_(csound,p,1);
285 return ret;
286 }
287
soundin(CSOUND * csound,DISKIN2 * p)288 int32_t soundin(CSOUND *csound, DISKIN2 *p){
289 MYFLT tmp = *p->kTranspose;
290 int32_t ret;
291 *p->kTranspose = 1.;
292 ret = diskin2_perf(csound, p);
293 *p->kTranspose = tmp;
294 return ret;
295 }
296
297 int32_t diskin2_async_deinit(CSOUND *csound, void *p);
298
diskin2_init_(CSOUND * csound,DISKIN2 * p,int32_t stringname)299 static int32_t diskin2_init_(CSOUND *csound, DISKIN2 *p, int32_t stringname)
300 {
301 double pos;
302 char name[1024];
303 void *fd;
304 SF_INFO sfinfo;
305 int32_t n;
306
307 /* check number of channels */
308 p->nChannels = (int32_t)(p->OUTOCOUNT);
309 if (UNLIKELY(p->nChannels < 1 || p->nChannels > DISKIN2_MAXCHN)) {
310 return csound->InitError(csound,
311 Str("diskin2: invalid number of channels"));
312 }
313 /* if already open, close old file first */
314 if (p->fdch.fd != NULL) {
315 /* skip initialisation if requested */
316 if (p->SkipInit != FL(0.0))
317 return OK;
318 csound_fd_close(csound, &(p->fdch));
319 }
320 /* set default format parameters */
321 memset(&sfinfo, 0, sizeof(SF_INFO));
322 sfinfo.samplerate = MYFLT2LONG(csound->esr);
323 sfinfo.channels = p->nChannels;
324 /* check for user specified sample format */
325 n = MYFLT2LONG(*p->iSampleFormat);
326 if (n<0) {
327 n = -n;
328 if (UNLIKELY(n < 0 || n > 10))
329 return csound->InitError(csound, Str("diskin2: unknown sample format"));
330 sfinfo.format = diskin2_format_table[n];
331 }
332 /* open file */
333 /* FIXME: name can overflow with very long string */
334 if (stringname==0){
335 if (csound->ISSTRCOD(*p->iFileCode))
336 strNcpy(name,get_arg_string(csound, *p->iFileCode), 1023);
337 else csound->strarg2name(csound, name, p->iFileCode, "soundin.",0);
338 }
339 else strNcpy(name, ((STRINGDAT *)p->iFileCode)->data, 1023);
340
341 fd = csound->FileOpen2(csound, &(p->sf), CSFILE_SND_R, name, &sfinfo,
342 "SFDIR;SSDIR", CSFTYPE_UNKNOWN_AUDIO, 0);
343 if (UNLIKELY(fd == NULL)) {
344 return csound->InitError(csound,
345 Str("diskin2: %s: failed to open file (%s)"),
346 name, Str(sf_strerror(NULL)));
347 }
348 /* record file handle so that it will be closed at note-off */
349 memset(&(p->fdch), 0, sizeof(FDCH));
350 p->fdch.fd = fd;
351 fdrecord(csound, &(p->fdch));
352
353 /* check number of channels in file (must equal the number of outargs) */
354 if (UNLIKELY(sfinfo.channels != p->nChannels)) {
355 return csound->InitError(csound,
356 Str("diskin2: number of output args "
357 "inconsistent with number of file channels"));
358 }
359 /* skip initialisation if requested */
360 if (p->initDone && p->SkipInit != FL(0.0))
361 return OK;
362
363
364 /* interpolation window size: valid settings are 1 (no interpolation), */
365 /* 2 (linear interpolation), 4 (cubic interpolation), and integer */
366 /* multiples of 4 in the range 8 to 1024 (sinc interpolation) */
367 p->winSize = MYFLT2LONG(p->WinSize);
368 if (p->winSize < 1)
369 p->winSize = 4; /* use cubic interpolation by default */
370 else if (p->winSize > 2) {
371 /* cubic/sinc: round to nearest integer multiple of 4 */
372 p->winSize = (p->winSize + 2) & (~3L);
373 if ((uint32) p->winSize > 1024UL)
374 p->winSize = 1024;
375 /* constant for window calculation */
376 p->winFact = (FL(1.0) - POWER(p->winSize * FL(0.85172), -FL(0.89624)))
377 / ((MYFLT)((p->winSize * p->winSize) >> 2));
378 }
379 /* set file parameters from header info */
380 p->fileLength = (int32_t) sfinfo.frames;
381 p->warpScale = 1.0;
382 if (MYFLT2LONG(csound->esr) != sfinfo.samplerate) {
383 if (LIKELY(p->winSize != 1)) {
384 /* will automatically convert sample rate if interpolation is enabled */
385 p->warpScale = (double)sfinfo.samplerate / (double)csound->esr;
386 }
387 else {
388 csound->Warning(csound, Str("diskin2: warning: file sample rate (%d) "
389 "!= orchestra sr (%d)\n"),
390 sfinfo.samplerate, MYFLT2LONG(csound->esr));
391 }
392 }
393 /* wrap mode */
394 p->wrapMode = (*(p->iWrapMode) == FL(0.0) ? 0 : 1);
395 if (UNLIKELY(p->fileLength < 1L))
396 p->wrapMode = 0;
397 /* initialise read position */
398 pos = (double)*(p->iSkipTime) * (double)csound->esr * p->warpScale;
399 pos *= (double)POS_FRAC_SCALE;
400 p->pos_frac = (int64_t)(pos >= 0.0 ? (pos + 0.5) : (pos - 0.5));
401 if (p->wrapMode) {
402 p->pos_frac %= ((int64_t)p->fileLength << POS_FRAC_SHIFT);
403 if (UNLIKELY(p->pos_frac < (int64_t)0))
404 p->pos_frac += ((int64_t)p->fileLength << POS_FRAC_SHIFT);
405 }
406 p->pos_frac_inc = (int64_t)0;
407 p->prv_kTranspose = FL(0.0);
408 /* allocate and initialise buffers */
409 p->bufSize = diskin2_calc_buffer_size(p, MYFLT2LONG(p->BufSize));
410 n = 2 * p->bufSize * p->nChannels * (int32_t)sizeof(MYFLT);
411 if (n != (int32_t)p->auxData.size)
412 csound->AuxAlloc(csound, (int32_t) n, &(p->auxData));
413 p->bufStartPos = p->prvBufStartPos = -((int32_t)p->bufSize);
414 n = p->bufSize * p->nChannels;
415 p->buf = (MYFLT*) (p->auxData.auxp);
416 p->prvBuf = (MYFLT*) p->buf + (int32_t)n;
417
418 memset(p->buf, 0, n*sizeof(MYFLT));
419
420 // create circular buffer, on fail set mode to synchronous
421 if (csound->oparms->realtime==1 && p->fforceSync==0 &&
422 (p->cb = csound->CreateCircularBuffer(csound,
423 p->bufSize*p->nChannels*2,
424 sizeof(MYFLT))) != NULL){
425 DISKIN_INST **top, *current;
426 #ifndef __EMSCRIPTEN__
427 int32_t *start;
428 #endif
429 // allocate buffer
430 p->aOut_bufsize = ((unsigned int)p->bufSize) < CS_KSMPS ?
431 ((MYFLT)CS_KSMPS) : ((MYFLT)p->bufSize);
432 n = p->aOut_bufsize*sizeof(MYFLT)*p->nChannels;
433 if (n != (int32_t)p->auxData2.size)
434 csound->AuxAlloc(csound, (int32_t) n, &(p->auxData2));
435 p->aOut_buf = (MYFLT *) (p->auxData2.auxp);
436 memset(p->aOut_buf, 0, n);
437 top = (DISKIN_INST **)csound->QueryGlobalVariable(csound, "DISKIN_INST");
438 #ifndef __EMSCRIPTEN__
439 if (top == NULL){
440 csound->CreateGlobalVariable(csound, "DISKIN_INST", sizeof(DISKIN_INST *));
441 top = (DISKIN_INST **) csound->QueryGlobalVariable(csound, "DISKIN_INST");
442 *top = (DISKIN_INST *) csound->Calloc(csound, sizeof(DISKIN_INST));
443 csound->CreateGlobalVariable(csound, "DISKIN_PTHREAD", sizeof(void**));
444 csound->CreateGlobalVariable(csound,
445 "DISKIN_THREAD_START", sizeof(int32_t));
446 current = *top;
447 }
448 else
449 #endif
450 {
451 current = *top;
452 while(current->nxt != NULL) { /* find next empty slot in chain */
453 current = current->nxt;
454 }
455 current->nxt = (DISKIN_INST *) csound->Calloc(csound,
456 sizeof(DISKIN_INST));
457 current = current->nxt;
458 }
459 current->csound = csound;
460 current->diskin = p;
461 current->nxt = NULL;
462
463 #ifndef __EMSCRIPTEN__
464 if ( *(start = csound->QueryGlobalVariable(csound,
465 "DISKIN_THREAD_START")) == 0) {
466 uintptr_t diskin_io_thread(void *p);
467 void **thread = csound->QueryGlobalVariable(csound, "DISKIN_PTHREAD");
468 *thread = csound->CreateThread(diskin_io_thread, *top);
469 *start = 1;
470 }
471 #endif
472 csound->RegisterDeinitCallback(csound, p, diskin2_async_deinit);
473 p->async = 1;
474
475 /* print file information */
476 if (UNLIKELY((csound->oparms_.msglevel & 7) == 7)) {
477 csound->Message(csound, "%s '%s'\n"
478 " %d Hz, %d %s, %" PRId64 " %s",
479 Str("diskin2: opened (asynchronously)"),
480 csound->GetFileName(fd),
481 sfinfo.samplerate, sfinfo.channels,
482 Str("channel(s)"),
483 (int64_t)sfinfo.frames,
484 Str("sample frames\n"));
485 }
486 }
487 else {
488 p->aOut_buf = NULL;
489 p->aOut_bufsize = 0;
490 p->async = 0;
491 /* print file information */
492 if (UNLIKELY((csound->oparms_.msglevel & 7) == 7)) {
493 csound->Message(csound, "%s '%s':\n"
494 " %d Hz, %d %s, %" PRId64 " %s\n",
495 Str("diskin2: opened"),
496 csound->GetFileName(fd),
497 sfinfo.samplerate, sfinfo.channels,
498 Str("channel(s)"),
499 (int64_t)sfinfo.frames,
500 Str("sample frames\n"));
501 }
502 }
503
504 /* done initialisation */
505 p->initDone = 1;
506 return OK;
507 }
508
diskin2_async_deinit(CSOUND * csound,void * p)509 int32_t diskin2_async_deinit(CSOUND *csound, void *p){
510
511 DISKIN_INST **top, *current, *prv;
512
513 if ((top = (DISKIN_INST **)
514 csound->QueryGlobalVariable(csound, "DISKIN_INST")) == NULL) return NOTOK;
515 current = *top;
516 prv = NULL;
517 while(current->diskin != (DISKIN2 *)p) {
518 prv = current;
519 current = current->nxt;
520 }
521 if (prv == NULL) *top = current->nxt;
522 else prv->nxt = current->nxt;
523
524 #ifndef __EMSCRIPTEN__
525 if (*top == NULL) {
526 int32_t *start; void **pt;
527
528 start = (int32_t *) csound->QueryGlobalVariable(csound,"DISKIN_THREAD_START");
529 *start = 0;
530 pt = csound->QueryGlobalVariable(csound,"DISKIN_PTHREAD");
531 //csound->Message(csound, "dealloc %p %d\n", start, *start);
532 csound->JoinThread(*pt);
533 csound->DestroyGlobalVariable(csound, "DISKIN_PTHREAD");
534 csound->DestroyGlobalVariable(csound, "DISKIN_THREAD_START");
535 csound->DestroyGlobalVariable(csound, "DISKIN_INST");
536 }
537 #endif
538 csound->Free(csound, current);
539 csound->DestroyCircularBuffer(csound, ((DISKIN2 *)p)->cb);
540
541 return OK;
542 }
543
diskin2_file_pos_inc(DISKIN2 * p,int32_t * ndx)544 static inline void diskin2_file_pos_inc(DISKIN2 *p, int32_t *ndx)
545 {
546 p->pos_frac += p->pos_frac_inc;
547 *ndx = (int32_t) (p->pos_frac >> POS_FRAC_SHIFT);
548 if (p->wrapMode) {
549 if (*ndx >= p->fileLength) {
550 *ndx -= p->fileLength;
551 p->pos_frac -= ((int64_t)p->fileLength << POS_FRAC_SHIFT);
552 }
553 else if (*ndx < 0L) {
554 *ndx += p->fileLength;
555 p->pos_frac += ((int64_t)p->fileLength << POS_FRAC_SHIFT);
556 }
557 }
558 }
559
560
diskin2_perf_synchronous(CSOUND * csound,DISKIN2 * p)561 int32_t diskin2_perf_synchronous(CSOUND *csound, DISKIN2 *p)
562 {
563 uint32_t offset = p->h.insdshead->ksmps_offset;
564 uint32_t early = p->h.insdshead->ksmps_no_end;
565 int nsmps = CS_KSMPS;
566 int chn, i, nn;
567 double d, frac_d, x, c, v, pidwarp_d;
568 MYFLT frac, a0, a1, a2, a3, onedwarp, winFact;
569 int32_t ndx;
570 int32_t wsized2, warp;
571
572
573 if (UNLIKELY(p->fdch.fd == NULL) ) goto file_error;
574 if (!p->initDone && !p->SkipInit){
575 return csound->PerfError(csound, &(p->h),
576 Str("diskin2: not initialised"));
577 }
578 if (*(p->kTranspose) != p->prv_kTranspose) {
579 double f;
580 p->prv_kTranspose = *(p->kTranspose);
581 f = (double)p->prv_kTranspose * p->warpScale * (double)POS_FRAC_SCALE;
582 #ifdef HAVE_C99
583 p->pos_frac_inc = (int64_t)llrint(f);
584 #else
585 p->pos_frac_inc = (int64_t)(f + (f < 0.0 ? -0.5 : 0.5));
586 #endif
587 }
588 /* clear outputs to zero first */
589 for (chn = 0; chn < p->nChannels; chn++)
590 for (nn = 0; nn < nsmps; nn++)
591 p->aOut[chn][nn] = FL(0.0);
592 /* file read position */
593 if (UNLIKELY(early)) nsmps -= early;
594 ndx = (int32_t) (p->pos_frac >> POS_FRAC_SHIFT);
595 switch (p->winSize) {
596 case 1: /* ---- no interpolation ---- */
597 for (nn = offset; nn < nsmps; nn++) {
598 if (p->pos_frac & ((int64_t)POS_FRAC_SCALE >> 1))
599 ndx++; /* round to nearest sample */
600 diskin2_get_sample(csound, p, ndx, nn, FL(1.0));
601 /* update file position */
602 diskin2_file_pos_inc(p, &ndx);
603 }
604 break;
605 case 2: /* ---- linear interpolation ---- */
606 for (nn = offset; nn < nsmps; nn++) {
607 a1 = (MYFLT)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
608 * (FL(1.0) / (MYFLT)POS_FRAC_SCALE);
609 a0 = FL(1.0) - a1;
610 diskin2_get_sample(csound, p, ndx, nn, a0);
611 ndx++;
612 diskin2_get_sample(csound, p, ndx, nn, a1);
613 /* update file position */
614 diskin2_file_pos_inc(p, &ndx);
615 }
616 break;
617 case 4: /* ---- cubic interpolation ---- */
618 for (nn = offset; nn < nsmps; nn++) {
619 frac = (MYFLT)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
620 * (FL(1.0) / (MYFLT)POS_FRAC_SCALE);
621 a3 = frac * frac; a3 -= FL(1.0); a3 *= (FL(1.0) / FL(6.0));
622 a2 = frac; a2 += FL(1.0); a0 = (a2 *= FL(0.5)); a0 -= FL(1.0);
623 a1 = FL(3.0) * a3; a2 -= a1; a0 -= a3; a1 -= frac;
624 a0 *= frac; a1 *= frac; a2 *= frac; a3 *= frac; a1 += FL(1.0);
625 ndx--; /* sample -1 */
626 diskin2_get_sample(csound, p, ndx, nn, a0);
627 ndx++; /* sample 0 */
628 diskin2_get_sample(csound, p, ndx, nn, a1);
629 ndx++; /* sample +1 */
630 diskin2_get_sample(csound, p, ndx, nn, a2);
631 ndx++; /* sample +2 */
632 diskin2_get_sample(csound, p, ndx, nn, a3);
633 /* update file position */
634 diskin2_file_pos_inc(p, &ndx);
635 }
636 break;
637 default: /* ---- sinc interpolation ---- */
638 wsized2 = p->winSize >> 1;
639 nn = POS_FRAC_SCALE + (POS_FRAC_SCALE >> 12);
640 if (p->pos_frac_inc > (int64_t) nn ||
641 p->pos_frac_inc < (int64_t) (-nn)) {
642 warp = 1; /* enable warp */
643 onedwarp = (p->pos_frac_inc >= (int64_t) 0 ?
644 ((MYFLT)nn / (MYFLT)p->pos_frac_inc)
645 : ((MYFLT)(-nn) / (MYFLT)p->pos_frac_inc));
646 pidwarp_d = PI * (double)onedwarp;
647 c = 2.0 * cos(pidwarp_d) - 2.0;
648 /* correct window for kwarp */
649 x = v = (double)wsized2; x *= x; x = 1.0 / x;
650 v *= (double)onedwarp; v -= (double)((int32_t)v) + 0.5; v *= 4.0 * v;
651 winFact = (MYFLT)(((double)p->winFact - x) * v + x);
652 }
653 else {
654 warp = 0;
655 onedwarp = FL(0.0);
656 pidwarp_d = c = 0.0;
657 winFact = p->winFact;
658 }
659 for (nn = offset; nn < nsmps; nn++) {
660 frac_d = (double)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
661 * (1.0 / (double)POS_FRAC_SCALE);
662 ndx += (int32_t)(1 - wsized2);
663 d = (double)(1 - wsized2) - frac_d;
664 if (warp) { /* ---- warp enabled ---- */
665 init_sine_gen((1.0 / PI), pidwarp_d, (pidwarp_d * d), c, &x, &v);
666 /* samples -(window size / 2 - 1) to -1 */
667 i = wsized2 - 1;
668 do {
669 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
670 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
671 diskin2_get_sample(csound, p, ndx, nn, a1);
672 ndx++;
673 d += 1.0; v += c * x; x += v;
674 } while (--i);
675 /* sample 0 */
676 /* avoid division by zero */
677 if (UNLIKELY(frac_d < 0.00003)) {
678 a1 = onedwarp;
679 }
680 else {
681 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
682 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
683 }
684 diskin2_get_sample(csound, p, ndx, nn, a1);
685 ndx++;
686 d += 1.0; v += c * x; x += v;
687 /* sample 1 */
688 /* avoid division by zero */
689 if (UNLIKELY(frac_d > 0.99997)) {
690 a1 = onedwarp;
691 }
692 else {
693 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
694 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
695 }
696 diskin2_get_sample(csound, p, ndx, nn, a1);
697 ndx++;
698 d += 1.0; v += c * x; x += v;
699 /* samples 2 to (window size / 2) */
700 i = wsized2 - 1;
701 do {
702 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
703 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
704 diskin2_get_sample(csound, p, ndx, nn, a1);
705 ndx++;
706 d += 1.0; v += c * x; x += v;
707 } while (--i);
708 }
709 else { /* ---- warp disabled ---- */
710 /* avoid division by zero */
711 if (frac_d < 0.00001 || frac_d > 0.99999) {
712 ndx += (int32_t) (wsized2 - (frac_d < 0.5 ? 1 : 0));
713 diskin2_get_sample(csound, p, ndx, nn, FL(1.0));
714 }
715 else {
716 a0 = (MYFLT)(sin(PI * frac_d) / PI);
717 i = wsized2;
718 do {
719 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
720 a1 = a1 * a1 / (MYFLT)d;
721 diskin2_get_sample(csound, p, ndx, nn, a1*a0);
722 d += 1.0;
723 ndx++;
724 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
725 a1 = -(a1 * a1 / (MYFLT)d);
726 diskin2_get_sample(csound, p, ndx, nn, a1*a0);
727 d += 1.0;
728 ndx++;
729 } while (--i);
730 }
731 }
732 /* update file position */
733 diskin2_file_pos_inc(p, &ndx);
734 }
735 }
736 /* apply 0dBFS scale */
737 for (chn = 0; chn < p->nChannels; chn++)
738 for (nn = offset; nn < nsmps; nn++)
739 p->aOut[chn][nn] *= csound->e0dbfs;
740 return OK;
741 file_error:
742 csound->ErrorMsg(csound, Str("diskin2: file descriptor closed or invalid\n"));
743 return NOTOK;
744 }
745
746
diskin_file_read(CSOUND * csound,DISKIN2 * p)747 int32_t diskin_file_read(CSOUND *csound, DISKIN2 *p)
748 {
749 /* nsmps is bufsize in frames */
750 int32_t nsmps = p->aOut_bufsize;// - p->h.insdshead->ksmps_offset;
751 int32_t i, nn;
752 int32_t chn, chans = p->nChannels;
753 double d, frac_d, x, c, v, pidwarp_d;
754 MYFLT frac, a0, a1, a2, a3, onedwarp, winFact;
755 int32_t ndx;
756 int32_t wsized2, warp;
757 MYFLT *aOut = (MYFLT *)p->aOut_buf; /* needs to be allocated */
758
759 if (UNLIKELY(p->fdch.fd == NULL) ) goto file_error;
760 if (!p->initDone && !p->SkipInit) {
761 return csound->PerfError(csound, &(p->h),
762 Str("diskin2: not initialised"));
763 }
764 if (*(p->kTranspose) != p->prv_kTranspose) {
765 double f;
766 p->prv_kTranspose = *(p->kTranspose);
767 f = (double)p->prv_kTranspose * p->warpScale * (double)POS_FRAC_SCALE;
768 #ifdef HAVE_C99
769 p->pos_frac_inc = (int64_t)llrint(f);
770 #else
771 p->pos_frac_inc = (int64_t)(f + (f < 0.0 ? -0.5 : 0.5));
772 #endif
773 }
774 /* clear outputs to zero first */
775 for (chn = 0; chn < chans; chn++)
776 for (nn = 0; nn < nsmps; nn++)
777 aOut[chn + nn*chans] = FL(0.0);
778 /* file read position */
779 ndx = (int32_t) (p->pos_frac >> POS_FRAC_SHIFT);
780 switch (p->winSize) {
781 case 1: /* ---- no interpolation ---- */
782 for (nn = 0; nn < nsmps; nn++) {
783 if (p->pos_frac & ((int64_t)POS_FRAC_SCALE >> 1))
784 ndx++; /* round to nearest sample */
785 diskin2_get_sample(csound, p, ndx, nn, FL(1.0));
786 /* update file position */
787 diskin2_file_pos_inc(p, &ndx);
788 }
789 break;
790 case 2: /* ---- linear interpolation ---- */
791 for (nn = 0; nn < nsmps; nn++) {
792 a1 = (MYFLT)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
793 * (FL(1.0) / (MYFLT)POS_FRAC_SCALE);
794 a0 = FL(1.0) - a1;
795 diskin2_get_sample(csound, p, ndx, nn, a0);
796 ndx++;
797 diskin2_get_sample(csound, p, ndx, nn, a1);
798 /* update file position */
799 diskin2_file_pos_inc(p, &ndx);
800 }
801 break;
802 case 4: /* ---- cubic interpolation ---- */
803 for (nn = 0; nn < nsmps; nn++) {
804 frac = (MYFLT)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
805 * (FL(1.0) / (MYFLT)POS_FRAC_SCALE);
806 a3 = frac * frac; a3 -= FL(1.0); a3 *= (FL(1.0) / FL(6.0));
807 a2 = frac; a2 += FL(1.0); a0 = (a2 *= FL(0.5)); a0 -= FL(1.0);
808 a1 = FL(3.0) * a3; a2 -= a1; a0 -= a3; a1 -= frac;
809 a0 *= frac; a1 *= frac; a2 *= frac; a3 *= frac; a1 += FL(1.0);
810 ndx--; /* sample -1 */
811 diskin2_get_sample(csound, p, ndx, nn, a0);
812 ndx++; /* sample 0 */
813 diskin2_get_sample(csound, p, ndx, nn, a1);
814 ndx++; /* sample +1 */
815 diskin2_get_sample(csound, p, ndx, nn, a2);
816 ndx++; /* sample +2 */
817 diskin2_get_sample(csound, p, ndx, nn, a3);
818 /* update file position */
819 diskin2_file_pos_inc(p, &ndx);
820 }
821 break;
822 default: /* ---- sinc interpolation ---- */
823 wsized2 = p->winSize >> 1;
824 nn = POS_FRAC_SCALE + (POS_FRAC_SCALE >> 12);
825 if (p->pos_frac_inc > (int64_t) nn ||
826 p->pos_frac_inc < (int64_t) (-nn)) {
827 warp = 1; /* enable warp */
828 onedwarp = (p->pos_frac_inc >= (int64_t) 0 ?
829 ((MYFLT)nn / (MYFLT)p->pos_frac_inc)
830 : ((MYFLT)(-nn) / (MYFLT)p->pos_frac_inc));
831 pidwarp_d = PI * (double)onedwarp;
832 c = 2.0 * cos(pidwarp_d) - 2.0;
833 /* correct window for kwarp */
834 x = v = (double)wsized2; x *= x; x = 1.0 / x;
835 v *= (double)onedwarp; v -= (double)((int32_t)v) + 0.5; v *= 4.0 * v;
836 winFact = (MYFLT)(((double)p->winFact - x) * v + x);
837 }
838 else {
839 warp = 0;
840 onedwarp = FL(0.0);
841 pidwarp_d = c = 0.0;
842 winFact = p->winFact;
843 }
844 for (nn = 0; nn < nsmps; nn++) {
845 frac_d = (double)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
846 * (1.0 / (double)POS_FRAC_SCALE);
847 ndx += (int32_t)(1 - wsized2);
848 d = (double)(1 - wsized2) - frac_d;
849 if (warp) { /* ---- warp enabled ---- */
850 init_sine_gen((1.0 / PI), pidwarp_d, (pidwarp_d * d), c, &x, &v);
851 /* samples -(window size / 2 - 1) to -1 */
852 i = wsized2 - 1;
853 do {
854 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
855 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
856 diskin2_get_sample(csound, p, ndx, nn, a1);
857 ndx++;
858 d += 1.0; v += c * x; x += v;
859 } while (--i);
860 /* sample 0 */
861 /* avoid division by zero */
862 if (UNLIKELY(frac_d < 0.00003)) {
863 a1 = onedwarp;
864 }
865 else {
866 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
867 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
868 }
869 diskin2_get_sample(csound, p, ndx, nn, a1);
870 ndx++;
871 d += 1.0; v += c * x; x += v;
872 /* sample 1 */
873 /* avoid division by zero */
874 if (UNLIKELY(frac_d > 0.99997)) {
875 a1 = onedwarp;
876 }
877 else {
878 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
879 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
880 }
881 diskin2_get_sample(csound, p, ndx, nn, a1);
882 ndx++;
883 d += 1.0; v += c * x; x += v;
884 /* samples 2 to (window size / 2) */
885 i = wsized2 - 1;
886 do {
887 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
888 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
889 diskin2_get_sample(csound, p, ndx, nn, a1);
890 ndx++;
891 d += 1.0; v += c * x; x += v;
892 } while (--i);
893 }
894 else { /* ---- warp disabled ---- */
895 /* avoid division by zero */
896 if (frac_d < 0.00001 || frac_d > 0.99999) {
897 ndx += (int32_t) (wsized2 - (frac_d < 0.5 ? 1 : 0));
898 diskin2_get_sample(csound, p, ndx, nn, FL(1.0));
899 }
900 else {
901 a0 = (MYFLT)(sin(PI * frac_d) / PI);
902 i = wsized2;
903 do {
904 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
905 a1 = a0 * a1 * a1 / (MYFLT)d;
906 diskin2_get_sample(csound, p, ndx, nn, a1);
907 d += 1.0;
908 ndx++;
909 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
910 a1 = -(a0 * a1 * a1 / (MYFLT)d);
911 diskin2_get_sample(csound, p, ndx, nn, a1);
912 d += 1.0;
913 ndx++;
914 } while (--i);
915 }
916 }
917 /* update file position */
918 diskin2_file_pos_inc(p, &ndx);
919 }
920 }
921 {
922 /* write to circular buffer */
923 int32_t lc, mc=0, nc=nsmps*p->nChannels;
924 int32_t *start = csound->QueryGlobalVariable(csound,"DISKIN_THREAD_START");
925 do{
926 lc = csound->WriteCircularBuffer(csound, p->cb, &aOut[mc], nc);
927 nc -= lc;
928 mc += lc;
929 } while(nc && *start);
930 }
931 return OK;
932 file_error:
933 csound->ErrorMsg(csound, Str("diskin2: file descriptor closed or invalid\n"));
934 return NOTOK;
935 }
936
937
diskin2_perf_asynchronous(CSOUND * csound,DISKIN2 * p)938 int32_t diskin2_perf_asynchronous(CSOUND *csound, DISKIN2 *p)
939 {
940 uint32_t offset = p->h.insdshead->ksmps_offset;
941 uint32_t early = p->h.insdshead->ksmps_no_end;
942 uint32_t nn, nsmps = CS_KSMPS;
943 MYFLT samp;
944 int32_t chn;
945 void *cb = p->cb;
946 int32_t chans = p->nChannels;
947
948 if (offset || early) {
949 for (chn = 0; chn < chans; chn++)
950 for (nn = 0; nn < nsmps; nn++)
951 p->aOut[chn][nn] = FL(0.0);
952 if (UNLIKELY(early)) nsmps -= early;
953 }
954
955 if (UNLIKELY(p->fdch.fd == NULL)) return NOTOK;
956 if (!p->initDone && !p->SkipInit){
957 return csound->PerfError(csound, &(p->h),
958 Str("diskin2: not initialised"));
959 }
960 for (nn = offset; nn < nsmps; nn++){
961
962 for (chn = 0; chn < chans; chn++) {
963 //int32_t i =0;
964 //do {
965 // i =
966 csound->ReadCircularBuffer(csound, cb, &samp, 1);
967 //} while(i==0);
968 p->aOut[chn][nn] = csound->e0dbfs*samp;
969 }
970 }
971 return OK;
972 }
973
974
diskin_io_thread(void * p)975 uintptr_t diskin_io_thread(void *p){
976 DISKIN_INST *current = (DISKIN_INST *) p;
977 int32_t wakeup = 1000*current->csound->ksmps/current->csound->esr;
978 int32_t *start =
979 current->csound->QueryGlobalVariable(current->csound,"DISKIN_THREAD_START");
980 _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
981 while(*start){
982 current = (DISKIN_INST *) p;
983 csoundSleep(wakeup > 0 ? wakeup : 1);
984 while(current != NULL){
985 diskin_file_read(current->csound, current->diskin);
986 current = current->nxt;
987 }
988 }
989 return 0;
990 }
991
992
diskin2_perf(CSOUND * csound,DISKIN2 * p)993 int32_t diskin2_perf(CSOUND *csound, DISKIN2 *p) {
994 if (!p->async) return diskin2_perf_synchronous(csound, p);
995 else return diskin2_perf_asynchronous(csound, p);
996 }
997
998
999
soundout_deinit(CSOUND * csound,void * pp)1000 static int32_t soundout_deinit(CSOUND *csound, void *pp)
1001 {
1002 char *opname = csound->GetOpcodeName(pp);
1003 SNDCOM *q;
1004
1005 if (strcmp(opname, "soundouts") == 0)
1006 q = &(((SNDOUTS*) pp)->c);
1007 else
1008 q = &(((SNDOUT*) pp)->c);
1009
1010 if (q->fd != NULL) {
1011 /* flush buffer */
1012 MYFLT *p0 = (MYFLT*) &(q->outbuf[0]);
1013 MYFLT *p1 = (MYFLT*) q->outbufp;
1014 if (p1 > p0) {
1015 sf_write_MYFLT(q->sf, p0, (sf_count_t) ((MYFLT*) p1 - (MYFLT*) p0));
1016 q->outbufp = (MYFLT*) &(q->outbuf[0]);
1017 }
1018 /* close file */
1019 csound->FileClose(csound, q->fd);
1020 q->sf = (SNDFILE*) NULL;
1021 q->fd = NULL;
1022 }
1023
1024 return OK;
1025 }
1026
1027 /* RWD:DBFS: NB: thse funcs all supposed to write to a 'raw' file, so
1028 what will people want for 0dbfs handling? really need to update
1029 opcode with more options. */
1030
1031 /* init routine for instr soundout */
1032
sndo1set_(CSOUND * csound,void * pp,int32_t stringname)1033 static int32_t sndo1set_(CSOUND *csound, void *pp, int32_t stringname)
1034 {
1035 char *sfname, *opname, name[1024];
1036 SNDCOM *q;
1037 MYFLT *ifilcod, *iformat;
1038 int32_t filetyp = TYP_RAW, format = csound->oparms_.outformat, nchns = 1;
1039 SF_INFO sfinfo;
1040 //SNDOUTS *p = (SNDOUTS*) pp;
1041
1042 opname = csound->GetOpcodeName(pp);
1043 csound->Warning(csound, Str("%s is deprecated; use fout instead\n"),
1044 opname);
1045 if (strcmp(opname, "soundouts") == 0 || strcmp(opname, "soundouts.i") == 0) {
1046 q = &(((SNDOUTS*) pp)->c);
1047 ifilcod = ((SNDOUTS*) pp)->ifilcod;
1048 iformat = ((SNDOUTS*) pp)->iformat;
1049 nchns++;
1050 }
1051 else {
1052 q = &(((SNDOUT*) pp)->c);
1053 ifilcod = ((SNDOUT*) pp)->ifilcod;
1054 iformat = ((SNDOUT*) pp)->iformat;
1055 }
1056
1057 if (q->fd != NULL) /* if file already open, */
1058 return OK; /* return now */
1059
1060 csound->RegisterDeinitCallback(csound, pp, soundout_deinit);
1061
1062 if (stringname==0){
1063 if (csound->ISSTRCOD(*ifilcod))
1064 strNcpy(name,get_arg_string(csound, *ifilcod), 1023);
1065 else csound->strarg2name(csound, name, ifilcod, "soundout.",0);
1066 }
1067 else strNcpy(name, ((STRINGDAT *)ifilcod)->data, 1023);
1068
1069 sfname = name;
1070 memset(&sfinfo, 0, sizeof(SF_INFO));
1071 //sfinfo.frames = 0;
1072 sfinfo.samplerate = MYFLT2LONG(csound->esr);
1073 sfinfo.channels = nchns;
1074 switch (MYFLT2LONG(*iformat)) {
1075 case 1: format = AE_CHAR; break;
1076 case 4: format = AE_SHORT; break;
1077 case 5: format = AE_LONG; break;
1078 case 6: format = AE_FLOAT;
1079 case 0: break;
1080 default:
1081 return csound->InitError(csound, Str("%s: invalid sample format: %d"),
1082 opname, MYFLT2LONG(*iformat));
1083 }
1084 sfinfo.format = TYPE2SF(filetyp) | FORMAT2SF(format);
1085 if (q->fd == NULL) {
1086 return csound->InitError(csound, Str("%s cannot open %s"), opname, sfname);
1087 }
1088 sfname = csound->GetFileName(q->fd);
1089 if (format != AE_FLOAT)
1090 sf_command(q->sf, SFC_SET_CLIPPING, NULL, SF_TRUE);
1091 else
1092 sf_command(q->sf, SFC_SET_CLIPPING, NULL, SF_FALSE);
1093 #ifdef USE_DOUBLE
1094 sf_command(q->sf, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE);
1095 #else
1096 sf_command(q->sf, SFC_SET_NORM_FLOAT, NULL, SF_FALSE);
1097 #endif
1098 csound->Warning(csound, Str("%s: opening RAW outfile %s\n"),
1099 opname, sfname);
1100 q->outbufp = q->outbuf; /* fix - isro 20-11-96 */
1101 q->bufend = q->outbuf + SNDOUTSMPS; /* fix - isro 20-11-96 */
1102
1103 return OK;
1104 }
1105
sndoutset(CSOUND * csound,SNDOUT * p)1106 int32_t sndoutset(CSOUND *csound, SNDOUT *p){
1107 return sndo1set_(csound,p,0);
1108 }
1109
sndoutset_S(CSOUND * csound,SNDOUT * p)1110 int32_t sndoutset_S(CSOUND *csound, SNDOUT *p){
1111 return sndo1set_(csound,p,1);
1112 }
1113
1114
soundout(CSOUND * csound,SNDOUT * p)1115 int32_t soundout(CSOUND *csound, SNDOUT *p)
1116 {
1117 uint32_t offset = p->h.insdshead->ksmps_offset;
1118 uint32_t early = p->h.insdshead->ksmps_no_end;
1119 uint32_t nn, nsmps = CS_KSMPS;
1120
1121 if (UNLIKELY(p->c.sf == NULL))
1122 return csound->PerfError(csound, &(p->h),
1123 Str("soundout: not initialised"));
1124 if (UNLIKELY(early)) nsmps -= early;
1125 for (nn = offset; nn < nsmps; nn++) {
1126 if (UNLIKELY(p->c.outbufp >= p->c.bufend)) {
1127
1128 sf_write_MYFLT(p->c.sf, p->c.outbuf, p->c.bufend - p->c.outbuf);
1129 p->c.outbufp = p->c.outbuf;
1130 }
1131 *(p->c.outbufp++) = p->asig[nn];
1132 }
1133
1134 return OK;
1135 }
1136
soundouts(CSOUND * csound,SNDOUTS * p)1137 int32_t soundouts(CSOUND *csound, SNDOUTS *p)
1138 {
1139 uint32_t offset = p->h.insdshead->ksmps_offset;
1140 uint32_t early = p->h.insdshead->ksmps_no_end;
1141 uint32_t nn, nsmps = CS_KSMPS;
1142
1143 if (UNLIKELY(p->c.sf == NULL))
1144 return csound->PerfError(csound, &(p->h),
1145 Str("soundouts: not initialised"));
1146 if (UNLIKELY(early)) nsmps -= early;
1147 for (nn = offset; nn < nsmps; nn++) {
1148 if (UNLIKELY(p->c.outbufp >= p->c.bufend)) {
1149 sf_write_MYFLT(p->c.sf, p->c.outbuf, p->c.bufend - p->c.outbuf);
1150 p->c.outbufp = p->c.outbuf;
1151 }
1152 *(p->c.outbufp++) = p->asig1[nn];
1153 *(p->c.outbufp++) = p->asig2[nn];
1154 }
1155
1156 return OK;
1157 }
1158
diskin2_read_buffer_array(CSOUND * csound,DISKIN2_ARRAY * p,int32_t bufReadPos)1159 static CS_NOINLINE void diskin2_read_buffer_array(CSOUND *csound,
1160 DISKIN2_ARRAY *p,
1161 int32_t bufReadPos)
1162 {
1163 MYFLT *tmp;
1164 int32_t nsmps;
1165 int32_t i;
1166 IGN(csound);
1167 /* swap buffer pointers */
1168 tmp = p->buf;
1169 p->buf = p->prvBuf;
1170 p->prvBuf = tmp;
1171 /* check if requested data can be found in previously used buffer */
1172 i = (int32_t)((int32_t) bufReadPos + (p->bufStartPos - p->prvBufStartPos));
1173 if ((uint32_t) i < (uint32_t) p->bufSize) {
1174 int32_t tmp2;
1175 /* yes, only need to swap buffers and return */
1176 tmp2 = p->bufStartPos;
1177 p->bufStartPos = p->prvBufStartPos;
1178 p->prvBufStartPos = tmp2;
1179 return;
1180 }
1181 /* save buffer position */
1182 p->prvBufStartPos = p->bufStartPos;
1183 /* calculate new buffer frame start position */
1184 p->bufStartPos = p->bufStartPos + (int32_t) bufReadPos;
1185 p->bufStartPos &= (~((int32_t) (p->bufSize - 1)));
1186 i = 0;
1187 if (p->bufStartPos >= 0L) {
1188 /* number of sample frames to read */
1189 nsmps = p->fileLength - p->bufStartPos;
1190 if (nsmps > 0L) { /* if there is anything to read: */
1191 if (nsmps > (int32_t) p->bufSize)
1192 nsmps = (int32_t) p->bufSize;
1193 nsmps *= (int32_t) p->nChannels;
1194 sf_seek(p->sf, (sf_count_t) p->bufStartPos, SEEK_SET);
1195 /* convert sample count to mono samples and read file */
1196 i = (int32_t)sf_read_MYFLT(p->sf, p->buf, (sf_count_t) nsmps);
1197 if (UNLIKELY(i < 0)) /* error ? */
1198 i = 0; /* clear entire buffer to zero */
1199 }
1200 }
1201 /* fill rest of buffer with zero samples */
1202 memset(&p->buf[i], 0, sizeof(MYFLT)*(p->bufSize * p->nChannels-i));
1203 /* while (i < (p->bufSize * p->nChannels)) */
1204 /* p->buf[i++] = FL(0.0); */
1205 }
1206
1207
diskin2_calc_buffer_size_array(DISKIN2_ARRAY * p,int32_t n_monoSamps)1208 static int32_t diskin2_calc_buffer_size_array(DISKIN2_ARRAY *p, int32_t n_monoSamps)
1209 {
1210 int32_t i, nFrames;
1211
1212 /* default to 4096 mono samples if zero or negative */
1213 if (n_monoSamps <= 0)
1214 n_monoSamps = 4096;
1215 /* convert mono samples -> sample frames */
1216 i = n_monoSamps / p->nChannels;
1217 /* limit to sane range */
1218 if (i < p->winSize)
1219 i = p->winSize;
1220 else if (i > 1048576)
1221 i = 1048576;
1222 /* buffer size must be an integer power of two, so round up */
1223 nFrames = 64; /* will be at least 128 sample frames */
1224 do {
1225 nFrames <<= 1;
1226 } while (nFrames < i);
1227
1228 return nFrames;
1229 }
1230
diskin2_file_pos_inc_array(DISKIN2_ARRAY * p,int32_t * ndx)1231 static inline void diskin2_file_pos_inc_array(DISKIN2_ARRAY *p, int32_t *ndx)
1232 {
1233 p->pos_frac += p->pos_frac_inc;
1234 *ndx = (int32_t) (p->pos_frac >> POS_FRAC_SHIFT);
1235 if (p->wrapMode) {
1236 if (*ndx >= p->fileLength) {
1237 *ndx -= p->fileLength;
1238 p->pos_frac -= ((int64_t)p->fileLength << POS_FRAC_SHIFT);
1239 }
1240 else if (*ndx < 0L) {
1241 *ndx += p->fileLength;
1242 p->pos_frac += ((int64_t)p->fileLength << POS_FRAC_SHIFT);
1243 }
1244 }
1245 }
1246
diskin2_get_sample_array(CSOUND * csound,DISKIN2_ARRAY * p,int32_t fPos,int32_t n,MYFLT scl)1247 static inline void diskin2_get_sample_array(CSOUND *csound,
1248 DISKIN2_ARRAY *p, int32_t fPos,
1249 int32_t n, MYFLT scl)
1250 {
1251 int32_t bufPos, i;
1252 int32_t ksmps = CS_KSMPS;
1253 MYFLT *aOut = (MYFLT *) p->aOut->data;
1254
1255 if (p->wrapMode) {
1256 if (UNLIKELY(fPos >= p->fileLength)){
1257 fPos -= p->fileLength;
1258 }
1259 else if (UNLIKELY(fPos < 0L)){
1260 fPos += p->fileLength;
1261 }
1262 }
1263 bufPos = (int32_t)(fPos - p->bufStartPos);
1264 if (UNLIKELY((uint32_t) bufPos >= (uint32_t) p->bufSize)) {
1265 /* not in current buffer frame, need to read file */
1266 diskin2_read_buffer_array(csound, p, bufPos);
1267 /* recalculate buffer position */
1268 bufPos = (int32_t)(fPos - p->bufStartPos);
1269 }
1270
1271 /* copy all channels from buffer */
1272 if (p->aOut_buf == NULL){
1273 if (p->nChannels == 1) {
1274 aOut[n] += scl * p->buf[bufPos];
1275 }
1276 else if (p->nChannels == 2) {
1277 bufPos += bufPos;
1278 aOut[n] += scl * p->buf[bufPos];
1279 aOut[n+ksmps] += scl * p->buf[bufPos + 1];
1280 }
1281 else {
1282 bufPos *= p->nChannels;
1283 i = 0;
1284 do {
1285 aOut[i*ksmps+n] += scl * p->buf[bufPos++];
1286 } while (++i < p->nChannels);
1287 }
1288 } else{
1289 MYFLT *aOut = p->aOut_buf;
1290 int32_t chans = p->nChannels;
1291 /* copy all channels from buffer */
1292 if (chans == 1) {
1293 aOut[n] += scl * p->buf[bufPos];
1294 }
1295 else if (chans == 2) {
1296 bufPos += bufPos;
1297 aOut[n*2] += scl * p->buf[bufPos];
1298 aOut[n*2+1] += scl * p->buf[bufPos+1];
1299 }
1300 else {
1301 bufPos *= chans;//p->nChannels;
1302 i = 0;
1303 do {
1304 aOut[n*chans+i] += scl * p->buf[bufPos++];
1305 } while (++i < chans);
1306 }
1307
1308 }
1309 }
1310
diskin2_async_deinit_array(CSOUND * csound,void * p)1311 int32_t diskin2_async_deinit_array(CSOUND *csound, void *p){
1312
1313 DISKIN_INST **top, *current, *prv;
1314
1315 if ((top = (DISKIN_INST **)
1316 csound->QueryGlobalVariable(csound, "DISKIN_INST_ARRAY")) == NULL)
1317 return NOTOK;
1318 current = *top;
1319 prv = NULL;
1320 while(current->diskin != (DISKIN2 *)p) {
1321 prv = current;
1322 current = current->nxt;
1323 }
1324 if (prv == NULL) *top = current->nxt;
1325 else prv->nxt = current->nxt;
1326
1327 #ifndef __EMSCRIPTEN__
1328 if (*top == NULL) {
1329 int32_t *start; void **pt;
1330 start = (int32_t *) csound->QueryGlobalVariable(csound,
1331 "DISKIN_THREAD_START_ARRAY");
1332 *start = 0;
1333 pt = csound->QueryGlobalVariable(csound,"DISKIN_PTHREAD_ARRAY");
1334 //csound->Message(csound, "dealloc %p %d\n", start, *start);
1335 csound->JoinThread(*pt);
1336 csound->DestroyGlobalVariable(csound, "DISKIN_PTHREAD_ARRAY");
1337 csound->DestroyGlobalVariable(csound, "DISKIN_THREAD_START_ARRAY");
1338 csound->DestroyGlobalVariable(csound, "DISKIN_INST_ARRAY");
1339 }
1340 #endif
1341
1342 csound->Free(csound, current);
1343 csound->DestroyCircularBuffer(csound, ((DISKIN2_ARRAY *)p)->cb);
1344
1345 return OK;
1346 }
1347
1348
diskin_file_read_array(CSOUND * csound,DISKIN2_ARRAY * p)1349 int32_t diskin_file_read_array(CSOUND *csound, DISKIN2_ARRAY *p)
1350 {
1351 /* nsmps is bufsize in frames */
1352 int32_t nsmps = p->aOut_bufsize;// - p->h.insdshead->ksmps_offset;
1353 int32_t i, nn;
1354 int32_t chn, chans = p->nChannels;
1355 double d, frac_d, x, c, v, pidwarp_d;
1356 MYFLT frac, a0, a1, a2, a3, onedwarp, winFact;
1357 int32_t ndx;
1358 int32_t wsized2, warp;
1359 MYFLT *aOut = (MYFLT *)p->aOut_buf; /* needs to be allocated */
1360
1361 if (UNLIKELY(p->fdch.fd == NULL) ) goto file_error;
1362 if (!p->initDone && !p->SkipInit) {
1363 return csound->PerfError(csound, &(p->h),
1364 Str("diskin2: not initialised"));
1365 }
1366 if (*(p->kTranspose) != p->prv_kTranspose) {
1367 double f;
1368 p->prv_kTranspose = *(p->kTranspose);
1369 f = (double)p->prv_kTranspose * p->warpScale * (double)POS_FRAC_SCALE;
1370 #ifdef HAVE_C99
1371 p->pos_frac_inc = (int64_t)llrint(f);
1372 #else
1373 p->pos_frac_inc = (int64_t)(f + (f < 0.0 ? -0.5 : 0.5));
1374 #endif
1375 }
1376 /* clear outputs to zero first */
1377 for (chn = 0; chn < chans; chn++)
1378 for (nn = 0; nn < nsmps; nn++)
1379 aOut[chn + nn*chans] = FL(0.0);
1380 /* file read position */
1381 ndx = (int32_t) (p->pos_frac >> POS_FRAC_SHIFT);
1382 switch (p->winSize) {
1383 case 1: /* ---- no interpolation ---- */
1384 for (nn = 0; nn < nsmps; nn++) {
1385 if (p->pos_frac & ((int64_t)POS_FRAC_SCALE >> 1))
1386 ndx++; /* round to nearest sample */
1387 diskin2_get_sample_array(csound, p, ndx, nn, FL(1.0));
1388 /* update file position */
1389 diskin2_file_pos_inc_array(p, &ndx);
1390 }
1391 break;
1392 case 2: /* ---- linear interpolation ---- */
1393 for (nn = 0; nn < nsmps; nn++) {
1394 a1 = (MYFLT)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
1395 * (FL(1.0) / (MYFLT)POS_FRAC_SCALE);
1396 a0 = FL(1.0) - a1;
1397 diskin2_get_sample_array(csound, p, ndx, nn, a0);
1398 ndx++;
1399 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1400 /* update file position */
1401 diskin2_file_pos_inc_array(p, &ndx);
1402 }
1403 break;
1404 case 4: /* ---- cubic interpolation ---- */
1405 for (nn = 0; nn < nsmps; nn++) {
1406 frac = (MYFLT)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
1407 * (FL(1.0) / (MYFLT)POS_FRAC_SCALE);
1408 a3 = frac * frac; a3 -= FL(1.0); a3 *= (FL(1.0) / FL(6.0));
1409 a2 = frac; a2 += FL(1.0); a0 = (a2 *= FL(0.5)); a0 -= FL(1.0);
1410 a1 = FL(3.0) * a3; a2 -= a1; a0 -= a3; a1 -= frac;
1411 a0 *= frac; a1 *= frac; a2 *= frac; a3 *= frac; a1 += FL(1.0);
1412 ndx--; /* sample -1 */
1413 diskin2_get_sample_array(csound, p, ndx, nn, a0);
1414 ndx++; /* sample 0 */
1415 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1416 ndx++; /* sample +1 */
1417 diskin2_get_sample_array(csound, p, ndx, nn, a2);
1418 ndx++; /* sample +2 */
1419 diskin2_get_sample_array(csound, p, ndx, nn, a3);
1420 /* update file position */
1421 diskin2_file_pos_inc_array(p, &ndx);
1422 }
1423 break;
1424 default: /* ---- sinc interpolation ---- */
1425 wsized2 = p->winSize >> 1;
1426 nn = POS_FRAC_SCALE + (POS_FRAC_SCALE >> 12);
1427 if (p->pos_frac_inc > (int64_t) nn ||
1428 p->pos_frac_inc < (int64_t) (-nn)) {
1429 warp = 1; /* enable warp */
1430 onedwarp = (p->pos_frac_inc >= (int64_t) 0 ?
1431 ((MYFLT)nn / (MYFLT)p->pos_frac_inc)
1432 : ((MYFLT)(-nn) / (MYFLT)p->pos_frac_inc));
1433 pidwarp_d = PI * (double)onedwarp;
1434 c = 2.0 * cos(pidwarp_d) - 2.0;
1435 /* correct window for kwarp */
1436 x = v = (double)wsized2; x *= x; x = 1.0 / x;
1437 v *= (double)onedwarp; v -= (double)((int32_t)v) + 0.5; v *= 4.0 * v;
1438 winFact = (MYFLT)(((double)p->winFact - x) * v + x);
1439 }
1440 else {
1441 warp = 0;
1442 onedwarp = FL(0.0);
1443 pidwarp_d = c = 0.0;
1444 winFact = p->winFact;
1445 }
1446 for (nn = 0; nn < nsmps; nn++) {
1447 frac_d = (double)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
1448 * (1.0 / (double)POS_FRAC_SCALE);
1449 ndx += (int32_t)(1 - wsized2);
1450 d = (double)(1 - wsized2) - frac_d;
1451 if (warp) { /* ---- warp enabled ---- */
1452 init_sine_gen((1.0 / PI), pidwarp_d, (pidwarp_d * d), c, &x, &v);
1453 /* samples -(window size / 2 - 1) to -1 */
1454 i = wsized2 - 1;
1455 do {
1456 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1457 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
1458 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1459 ndx++;
1460 d += 1.0; v += c * x; x += v;
1461 } while (--i);
1462 /* sample 0 */
1463 /* avoid division by zero */
1464 if (UNLIKELY(frac_d < 0.00003)) {
1465 a1 = onedwarp;
1466 }
1467 else {
1468 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1469 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
1470 }
1471 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1472 ndx++;
1473 d += 1.0; v += c * x; x += v;
1474 /* sample 1 */
1475 /* avoid division by zero */
1476 if (UNLIKELY(frac_d > 0.99997)) {
1477 a1 = onedwarp;
1478 }
1479 else {
1480 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1481 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
1482 }
1483 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1484 ndx++;
1485 d += 1.0; v += c * x; x += v;
1486 /* samples 2 to (window size / 2) */
1487 i = wsized2 - 1;
1488 do {
1489 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1490 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
1491 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1492 ndx++;
1493 d += 1.0; v += c * x; x += v;
1494 } while (--i);
1495 }
1496 else { /* ---- warp disabled ---- */
1497 /* avoid division by zero */
1498 if (frac_d < 0.00001 || frac_d > 0.99999) {
1499 ndx += (int32_t) (wsized2 - (frac_d < 0.5 ? 1 : 0));
1500 diskin2_get_sample_array(csound, p, ndx, nn, FL(1.0));
1501 }
1502 else {
1503 a0 = (MYFLT)(sin(PI * frac_d) / PI);
1504 i = wsized2;
1505 do {
1506 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1507 a1 = a0 * a1 * a1 / (MYFLT)d;
1508 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1509 d += 1.0;
1510 ndx++;
1511 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1512 a1 = -(a0 * a1 * a1 / (MYFLT)d);
1513 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1514 d += 1.0;
1515 ndx++;
1516 } while (--i);
1517 }
1518 }
1519 /* update file position */
1520 diskin2_file_pos_inc_array(p, &ndx);
1521 }
1522 }
1523 {
1524 /* write to circular buffer */
1525 int32_t lc, mc=0, nc=nsmps*p->nChannels;
1526 int32_t *start = csound->QueryGlobalVariable(csound,"DISKIN_THREAD_START");
1527 do{
1528 lc = csound->WriteCircularBuffer(csound, p->cb, &aOut[mc], nc);
1529 nc -= lc;
1530 mc += lc;
1531 } while(nc && *start);
1532 }
1533 return OK;
1534 file_error:
1535 csound->ErrorMsg(csound, Str("diskin2: file descriptor closed or invalid\n"));
1536 return NOTOK;
1537 }
1538
diskin_io_thread_array(void * p)1539 uintptr_t diskin_io_thread_array(void *p){
1540 DISKIN_INST *current = (DISKIN_INST *) p;
1541 int32_t wakeup = 1000*current->csound->ksmps/current->csound->esr;
1542 int32_t *start =
1543 current->csound->QueryGlobalVariable(current->csound,
1544 "DISKIN_THREAD_START_ARRAY");
1545 _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
1546 while(*start){
1547 current = (DISKIN_INST *) p;
1548 csoundSleep(wakeup > 0 ? wakeup : 1);
1549 while(current != NULL){
1550 diskin_file_read_array(current->csound, (DISKIN2_ARRAY *)current->diskin);
1551 current = current->nxt;
1552 }
1553 }
1554 return 0;
1555 }
1556
1557
diskin2_init_array(CSOUND * csound,DISKIN2_ARRAY * p,int32_t stringname)1558 static int32_t diskin2_init_array(CSOUND *csound, DISKIN2_ARRAY *p,
1559 int32_t stringname)
1560 {
1561 double pos;
1562 char name[1024];
1563 void *fd;
1564 SF_INFO sfinfo;
1565 int32_t n;
1566 ARRAYDAT *t = p->aOut;
1567
1568 /* if already open, close old file first */
1569 if (p->fdch.fd != NULL) {
1570 /* skip initialisation if requested */
1571 if (p->SkipInit != FL(0.0))
1572 return OK;
1573 csound_fd_close(csound, &(p->fdch));
1574 }
1575 // to handle raw files number of channels
1576 if (t->data) p->nChannels = t->sizes[0];
1577 /* set default format parameters */
1578 memset(&sfinfo, 0, sizeof(SF_INFO));
1579 sfinfo.samplerate = MYFLT2LONG(csound->esr);
1580 sfinfo.channels = p->nChannels;
1581 /* check for user specified sample format */
1582 n = MYFLT2LONG(*p->iSampleFormat);
1583 if (n<0) {
1584 n = -n;
1585 if (UNLIKELY(n > 10))
1586 return csound->InitError(csound, Str("diskin2: unknown sample format"));
1587 sfinfo.format = diskin2_format_table[n];
1588 }
1589 /* open file */
1590 /* FIXME: name can overflow with very long string */
1591 if (stringname==0){
1592 if (csound->ISSTRCOD(*p->iFileCode))
1593 strNcpy(name,get_arg_string(csound, *p->iFileCode), 1023);
1594 else csound->strarg2name(csound, name, p->iFileCode, "soundin.",0);
1595 }
1596 else strNcpy(name, ((STRINGDAT *)p->iFileCode)->data, 1023);
1597
1598 fd = csound->FileOpen2(csound, &(p->sf), CSFILE_SND_R, name, &sfinfo,
1599 "SFDIR;SSDIR", CSFTYPE_UNKNOWN_AUDIO, 0);
1600 if (UNLIKELY(fd == NULL)) {
1601 return csound->InitError(csound,
1602 Str("diskin2: %s: failed to open file: %s"),
1603 name, Str(sf_strerror(NULL)));
1604 }
1605 /* record file handle so that it will be closed at note-off */
1606 memset(&(p->fdch), 0, sizeof(FDCH));
1607 p->fdch.fd = fd;
1608 fdrecord(csound, &(p->fdch));
1609
1610 /* get number of channels in file */
1611 p->nChannels = sfinfo.channels;
1612
1613 if (UNLIKELY(t->data == NULL) || t->sizes[0] < p->nChannels ) {
1614 /* create array */
1615 CS_VARIABLE* var;
1616 int32_t memSize;
1617 if (t->data) {
1618 csound->Free(csound, t->data);
1619 csound->Free(csound, t->sizes);
1620 }
1621 t->dimensions = 1;
1622 t->sizes = csound->Calloc(csound, sizeof(int32_t));
1623 t->sizes[0] = p->nChannels;
1624 var = t->arrayType->createVariable(csound, NULL);
1625 t->arrayMemberSize = var->memBlockSize;
1626 memSize = var->memBlockSize*(t->sizes[0]);
1627 t->data = csound->Calloc(csound, memSize);
1628 }
1629 /* else { */
1630 /* /\* check dim 1 to see if it matches channels*\/ */
1631 /* if (t->sizes[0] < p->nChannels) */
1632 /* return csound->InitError(csound, */
1633 /* Str("diskin2: output array too small")); */
1634 /* } */
1635
1636 /* skip initialisation if requested */
1637 if (p->initDone && (p->SkipInit) != FL(0.0))
1638 return OK;
1639
1640 /* interpolation window size: valid settings are 1 (no interpolation), */
1641 /* 2 (linear interpolation), 4 (cubic interpolation), and integer */
1642 /* multiples of 4 in the range 8 to 1024 (sinc interpolation) */
1643 p->winSize = MYFLT2LONG(p->WinSize);
1644 if (p->winSize < 1)
1645 p->winSize = 4; /* use cubic interpolation by default */
1646 else if (p->winSize > 2) {
1647 /* cubic/sinc: round to nearest integer multiple of 4 */
1648 p->winSize = (p->winSize + 2) & (~3L);
1649 if ((uint32) p->winSize > 1024UL)
1650 p->winSize = 1024;
1651 /* constant for window calculation */
1652 p->winFact = (FL(1.0) - POWER(p->winSize * FL(0.85172), -FL(0.89624)))
1653 / ((MYFLT)((p->winSize * p->winSize) >> 2));
1654 }
1655 /* set file parameters from header info */
1656 p->fileLength = (int32_t) sfinfo.frames;
1657 p->warpScale = 1.0;
1658 if (MYFLT2LONG(csound->esr) != sfinfo.samplerate) {
1659 if (LIKELY(p->winSize != 1)) {
1660 /* will automatically convert sample rate if interpolation is enabled */
1661 p->warpScale = (double)sfinfo.samplerate / (double)csound->esr;
1662 }
1663 else {
1664 csound->Warning(csound, Str("diskin2: warning: file sample rate (%d) "
1665 "!= orchestra sr (%d)\n"),
1666 sfinfo.samplerate, MYFLT2LONG(csound->esr));
1667 }
1668 }
1669 /* wrap mode */
1670 p->wrapMode = (*(p->iWrapMode) == FL(0.0) ? 0 : 1);
1671 if (UNLIKELY(p->fileLength < 1L))
1672 p->wrapMode = 0;
1673 /* initialise read position */
1674 pos = (double)*(p->iSkipTime) * (double)csound->esr * p->warpScale;
1675 pos *= (double)POS_FRAC_SCALE;
1676 p->pos_frac = (int64_t)(pos >= 0.0 ? (pos + 0.5) : (pos - 0.5));
1677 if (p->wrapMode) {
1678 p->pos_frac %= ((int64_t)p->fileLength << POS_FRAC_SHIFT);
1679 if (UNLIKELY(p->pos_frac < (int64_t)0))
1680 p->pos_frac += ((int64_t)p->fileLength << POS_FRAC_SHIFT);
1681 }
1682 p->pos_frac_inc = (int64_t)0;
1683 p->prv_kTranspose = FL(0.0);
1684 /* allocate and initialise buffers */
1685 p->bufSize = diskin2_calc_buffer_size_array(p, MYFLT2LONG(p->BufSize));
1686 n = 2 * p->bufSize * p->nChannels * (int32_t)sizeof(MYFLT);
1687 if (n != (int32_t)p->auxData.size)
1688 csound->AuxAlloc(csound, (int32_t) n, &(p->auxData));
1689 p->bufStartPos = p->prvBufStartPos = -((int32_t)p->bufSize);
1690 n = p->bufSize * p->nChannels;
1691 p->buf = (MYFLT*) (p->auxData.auxp);
1692 p->prvBuf = (MYFLT*) p->buf + (int32_t)n;
1693
1694 memset(p->buf, 0, n*sizeof(MYFLT));
1695
1696 // create circular buffer, on fail set mode to synchronous
1697 if (csound->oparms->realtime==1 && p->fforceSync==0 &&
1698 (p->cb = csound->CreateCircularBuffer(csound,
1699 p->bufSize*p->nChannels*2,
1700 sizeof(MYFLT))) != NULL){
1701 DISKIN_INST **top, *current;
1702 #ifndef __EMSCRIPTEN__
1703 int32_t *start;
1704 #endif
1705 // allocate buffer
1706 p->aOut_bufsize =
1707 ((unsigned int)p->bufSize) < CS_KSMPS ?
1708 ((MYFLT)CS_KSMPS) : ((MYFLT)p->bufSize);
1709 n = p->aOut_bufsize*sizeof(MYFLT)*p->nChannels;
1710 if (n != (int32_t)p->auxData2.size)
1711 csound->AuxAlloc(csound, (int32_t) n, &(p->auxData2));
1712 p->aOut_buf = (MYFLT *) (p->auxData2.auxp);
1713 memset(p->aOut_buf, 0, n);
1714 top =
1715 (DISKIN_INST **)csound->QueryGlobalVariable(csound, "DISKIN_INST_ARRAY");
1716 #ifndef __EMSCRIPTEN__
1717 if (top == NULL){
1718 csound->CreateGlobalVariable(csound,
1719 "DISKIN_INST_ARRAY", sizeof(DISKIN_INST *));
1720 top = (DISKIN_INST **) csound->QueryGlobalVariable(csound,
1721 "DISKIN_INST_ARRAY");
1722 *top = (DISKIN_INST *) csound->Calloc(csound, sizeof(DISKIN_INST));
1723 csound->CreateGlobalVariable(csound,
1724 "DISKIN_PTHREAD_ARRAY", sizeof(void**));
1725 csound->CreateGlobalVariable(csound,
1726 "DISKIN_THREAD_START_ARRAY", sizeof(int32_t));
1727 current = *top;
1728 }
1729 else
1730 #endif
1731 {
1732 current = *top;
1733 while(current->nxt != NULL) { /* find next empty slot in chain */
1734 current = current->nxt;
1735 }
1736 current->nxt =
1737 (DISKIN_INST *) csound->Calloc(csound, sizeof(DISKIN_INST));
1738 current = current->nxt;
1739 }
1740 current->csound = csound;
1741 current->diskin = (DISKIN2 *) p;
1742 current->nxt = NULL;
1743
1744 #ifndef __EMSCRIPTEN__
1745 if (*(start =
1746 csound->QueryGlobalVariable(csound,
1747 "DISKIN_THREAD_START_ARRAY")) == 0) {
1748 uintptr_t diskin_io_thread_array(void *p);
1749 // TOFIX: this variable (thread) is not referenced
1750 #if 0
1751 void **thread = csound->QueryGlobalVariable(csound,
1752 "DISKIN_PTHREAD_ARRAY");
1753 #endif
1754 *start = 1;
1755 csound->CreateThread(diskin_io_thread_array, *top);
1756 }
1757 #endif
1758 csound->RegisterDeinitCallback(csound, (DISKIN2 *) p,
1759 diskin2_async_deinit_array);
1760 p->async = 1;
1761
1762 /* print file information */
1763 if (UNLIKELY((csound->oparms_.msglevel & 7) == 7)) {
1764 csound->Message(csound, "%s '%s':\n"
1765 " %d Hz, %d %schannel(s), %" PRId64 " %s",
1766 Str("diskin2: opened (asynchronously)"),
1767 csound->GetFileName(fd),
1768 sfinfo.samplerate, sfinfo.channels,
1769 Str("channel(s)"),
1770 (int64_t)sfinfo.frames,
1771 Str("sample frames\n"));
1772 }
1773 }
1774 else {
1775 p->aOut_buf = NULL;
1776 p->aOut_bufsize = 0;
1777 p->async = 0;
1778 /* print file information */
1779 if (UNLIKELY((csound->oparms_.msglevel & 7) == 7)) {
1780 csound->Message(csound, "%s '%s':\n"
1781 " %d Hz, %d %s, %" PRId64 " %s",
1782 Str("diskin2: opened"),
1783 csound->GetFileName(fd),
1784 sfinfo.samplerate, sfinfo.channels,
1785 Str("channel(s)"),
1786 (int64_t)sfinfo.frames,
1787 Str("sample frames\n"));
1788 }
1789 }
1790
1791 /* done initialisation */
1792 p->initDone = 1;
1793 return OK;
1794 }
1795
1796
1797
diskin2_perf_synchronous_array(CSOUND * csound,DISKIN2_ARRAY * p)1798 int32_t diskin2_perf_synchronous_array(CSOUND *csound, DISKIN2_ARRAY *p)
1799 {
1800 uint32_t offset = p->h.insdshead->ksmps_offset;
1801 uint32_t early = p->h.insdshead->ksmps_no_end;
1802 int32_t nsmps = CS_KSMPS, ksmps = CS_KSMPS;
1803 int32_t chn, i, nn;
1804 double d, frac_d, x, c, v, pidwarp_d;
1805 MYFLT frac, a0, a1, a2, a3, onedwarp, winFact;
1806 int32_t ndx;
1807 int32_t wsized2, warp;
1808 MYFLT *aOut = (MYFLT *) p->aOut->data;
1809
1810
1811 if (UNLIKELY(p->fdch.fd == NULL) ) goto file_error;
1812 if (!p->initDone && !p->SkipInit){
1813 return csound->PerfError(csound, &(p->h),
1814 Str("diskin2: not initialised"));
1815 }
1816 if (*(p->kTranspose) != p->prv_kTranspose) {
1817 double f;
1818 p->prv_kTranspose = *(p->kTranspose);
1819 f = (double)p->prv_kTranspose * p->warpScale * (double)POS_FRAC_SCALE;
1820 #ifdef HAVE_C99
1821 p->pos_frac_inc = (int64_t)llrint(f);
1822 #else
1823 p->pos_frac_inc = (int64_t)(f + (f < 0.0 ? -0.5 : 0.5));
1824 #endif
1825 }
1826 /* clear outputs to zero first */
1827 for (chn = 0; chn < p->nChannels; chn++)
1828 for (nn = 0; nn < nsmps; nn++)
1829 aOut[chn*ksmps+nn] = FL(0.0);
1830 /* file read position */
1831 if (UNLIKELY(early)) nsmps -= early;
1832 ndx = (int32_t) (p->pos_frac >> POS_FRAC_SHIFT);
1833 switch (p->winSize) {
1834 case 1: /* ---- no interpolation ---- */
1835 for (nn = offset; nn < nsmps; nn++) {
1836 if (p->pos_frac & ((int64_t)POS_FRAC_SCALE >> 1))
1837 ndx++; /* round to nearest sample */
1838 diskin2_get_sample_array(csound, p, ndx, nn, FL(1.0));
1839 /* update file position */
1840 diskin2_file_pos_inc_array(p, &ndx);
1841 }
1842 break;
1843 case 2: /* ---- linear interpolation ---- */
1844 for (nn = offset; nn < nsmps; nn++) {
1845 a1 = (MYFLT)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
1846 * (FL(1.0) / (MYFLT)POS_FRAC_SCALE);
1847 a0 = FL(1.0) - a1;
1848 diskin2_get_sample_array(csound, p, ndx, nn, a0);
1849 ndx++;
1850 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1851 /* update file position */
1852 diskin2_file_pos_inc_array(p, &ndx);
1853 }
1854 break;
1855 case 4: /* ---- cubic interpolation ---- */
1856 for (nn = offset; nn < nsmps; nn++) {
1857 frac = (MYFLT)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
1858 * (FL(1.0) / (MYFLT)POS_FRAC_SCALE);
1859 a3 = frac * frac; a3 -= FL(1.0); a3 *= (FL(1.0) / FL(6.0));
1860 a2 = frac; a2 += FL(1.0); a0 = (a2 *= FL(0.5)); a0 -= FL(1.0);
1861 a1 = FL(3.0) * a3; a2 -= a1; a0 -= a3; a1 -= frac;
1862 a0 *= frac; a1 *= frac; a2 *= frac; a3 *= frac; a1 += FL(1.0);
1863 ndx--; /* sample -1 */
1864 diskin2_get_sample_array(csound, p, ndx, nn, a0);
1865 ndx++; /* sample 0 */
1866 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1867 ndx++; /* sample +1 */
1868 diskin2_get_sample_array(csound, p, ndx, nn, a2);
1869 ndx++; /* sample +2 */
1870 diskin2_get_sample_array(csound, p, ndx, nn, a3);
1871 /* update file position */
1872 diskin2_file_pos_inc_array(p, &ndx);
1873 }
1874 break;
1875 default: /* ---- sinc interpolation ---- */
1876 wsized2 = p->winSize >> 1;
1877 nn = POS_FRAC_SCALE + (POS_FRAC_SCALE >> 12);
1878 if (p->pos_frac_inc > (int64_t) nn ||
1879 p->pos_frac_inc < (int64_t) (-nn)) {
1880 warp = 1; /* enable warp */
1881 onedwarp = (p->pos_frac_inc >= (int64_t) 0 ?
1882 ((MYFLT)nn / (MYFLT)p->pos_frac_inc)
1883 : ((MYFLT)(-nn) / (MYFLT)p->pos_frac_inc));
1884 pidwarp_d = PI * (double)onedwarp;
1885 c = 2.0 * cos(pidwarp_d) - 2.0;
1886 /* correct window for kwarp */
1887 x = v = (double)wsized2; x *= x; x = 1.0 / x;
1888 v *= (double)onedwarp; v -= (double)((int32_t)v) + 0.5; v *= 4.0 * v;
1889 winFact = (MYFLT)(((double)p->winFact - x) * v + x);
1890 }
1891 else {
1892 warp = 0;
1893 onedwarp = FL(0.0);
1894 pidwarp_d = c = 0.0;
1895 winFact = p->winFact;
1896 }
1897 for (nn = offset; nn < nsmps; nn++) {
1898 frac_d = (double)((int32_t)(p->pos_frac & (int64_t)POS_FRAC_MASK))
1899 * (1.0 / (double)POS_FRAC_SCALE);
1900 ndx += (int32_t)(1 - wsized2);
1901 d = (double)(1 - wsized2) - frac_d;
1902 if (warp) { /* ---- warp enabled ---- */
1903 init_sine_gen((1.0 / PI), pidwarp_d, (pidwarp_d * d), c, &x, &v);
1904 /* samples -(window size / 2 - 1) to -1 */
1905 i = wsized2 - 1;
1906 do {
1907 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1908 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
1909 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1910 ndx++;
1911 d += 1.0; v += c * x; x += v;
1912 } while (--i);
1913 /* sample 0 */
1914 /* avoid division by zero */
1915 if (UNLIKELY(frac_d < 0.00003)) {
1916 a1 = onedwarp;
1917 }
1918 else {
1919 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1920 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
1921 }
1922 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1923 ndx++;
1924 d += 1.0; v += c * x; x += v;
1925 /* sample 1 */
1926 /* avoid division by zero */
1927 if (UNLIKELY(frac_d > 0.99997)) {
1928 a1 = onedwarp;
1929 }
1930 else {
1931 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1932 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
1933 }
1934 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1935 ndx++;
1936 d += 1.0; v += c * x; x += v;
1937 /* samples 2 to (window size / 2) */
1938 i = wsized2 - 1;
1939 do {
1940 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1941 a1 = (MYFLT)x * a1 * a1 / (MYFLT)d;
1942 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1943 ndx++;
1944 d += 1.0; v += c * x; x += v;
1945 } while (--i);
1946 }
1947 else { /* ---- warp disabled ---- */
1948 /* avoid division by zero */
1949 if (frac_d < 0.00001 || frac_d > 0.99999) {
1950 ndx += (int32_t) (wsized2 - (frac_d < 0.5 ? 1 : 0));
1951 diskin2_get_sample_array(csound, p, ndx, nn, FL(1.0));
1952 }
1953 else {
1954 a0 = (MYFLT)(sin(PI * frac_d) / PI);
1955 i = wsized2;
1956 do {
1957 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1958 a1 = a0 * a1 * a1 / (MYFLT)d;
1959 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1960 d += 1.0;
1961 ndx++;
1962 a1 = (MYFLT)d; a1 = FL(1.0) - a1 * a1 * winFact;
1963 a1 = -(a0 * a1 * a1 / (MYFLT)d);
1964 diskin2_get_sample_array(csound, p, ndx, nn, a1);
1965 d += 1.0;
1966 ndx++;
1967 } while (--i);
1968 }
1969 }
1970 /* update file position */
1971 diskin2_file_pos_inc_array(p, &ndx);
1972 }
1973 }
1974 /* apply 0dBFS scale */
1975 for (chn = 0; chn < p->nChannels; chn++)
1976 for (nn = offset; nn < nsmps; nn++)
1977 aOut[chn*ksmps+nn] *= csound->e0dbfs;
1978 return OK;
1979 file_error:
1980 csound->ErrorMsg(csound, Str("diskin2: file descriptor closed or invalid\n"));
1981 return NOTOK;
1982 }
1983
1984
1985
diskin2_perf_asynchronous_array(CSOUND * csound,DISKIN2_ARRAY * p)1986 int32_t diskin2_perf_asynchronous_array(CSOUND *csound, DISKIN2_ARRAY *p)
1987 {
1988 uint32_t offset = p->h.insdshead->ksmps_offset;
1989 uint32_t early = p->h.insdshead->ksmps_no_end;
1990 uint32_t nn, nsmps = CS_KSMPS, ksmps = CS_KSMPS;
1991 MYFLT samp;
1992 int32_t chn;
1993 void *cb = p->cb;
1994 int32_t chans = p->nChannels;
1995 MYFLT *aOut = (MYFLT *) p->aOut->data;
1996
1997 if (offset || early) {
1998 for (chn = 0; chn < chans; chn++)
1999 for (nn = 0; nn < nsmps; nn++)
2000 aOut[chn*ksmps+nn] = FL(0.0);
2001 if (UNLIKELY(early)) nsmps -= early;
2002 }
2003
2004 if (UNLIKELY(p->fdch.fd == NULL)) return NOTOK;
2005 if (!p->initDone && !p->SkipInit){
2006 return csound->PerfError(csound, &(p->h),
2007 Str("diskin2: not initialised"));
2008 }
2009 for (nn = offset; nn < nsmps; nn++){
2010
2011 for (chn = 0; chn < chans; chn++) {
2012 //int32_t i =0;
2013 //do {
2014 // i =
2015 csound->ReadCircularBuffer(csound, cb, &samp, 1);
2016 //} while(i==0);
2017 aOut[chn*ksmps+nn] = csound->e0dbfs*samp;
2018 }
2019 }
2020 return OK;
2021 }
2022
diskin2_init_array_I(CSOUND * csound,DISKIN2_ARRAY * p)2023 int32_t diskin2_init_array_I(CSOUND *csound, DISKIN2_ARRAY *p) {
2024 p->SkipInit = *p->iSkipInit;
2025 p->WinSize = *p->iWinSize;
2026 p->BufSize = *p->iBufSize;
2027 p->fforceSync = *p->forceSync;
2028 return diskin2_init_array(csound,p,0);
2029 }
2030
diskin2_init_array_S(CSOUND * csound,DISKIN2_ARRAY * p)2031 int32_t diskin2_init_array_S(CSOUND *csound, DISKIN2_ARRAY *p) {
2032 p->SkipInit = *p->iSkipInit;
2033 p->WinSize = *p->iWinSize;
2034 p->BufSize = *p->iBufSize;
2035 p->fforceSync = *p->forceSync;
2036 return diskin2_init_array(csound,p,1);
2037 }
2038
2039 /* diskin_init_array - calls diskin2_init_array */
2040
diskin_init_array_I(CSOUND * csound,DISKIN2_ARRAY * p)2041 int32_t diskin_init_array_I(CSOUND *csound, DISKIN2_ARRAY *p){
2042 p->SkipInit = *p->iWinSize;
2043 p->WinSize = 2;
2044 p->BufSize = 0;
2045 p->fforceSync = 0;
2046 return diskin2_init_array(csound,p,0);
2047 }
2048
diskin_init_array_S(CSOUND * csound,DISKIN2_ARRAY * p)2049 int32_t diskin_init_array_S(CSOUND *csound, DISKIN2_ARRAY *p){
2050 p->SkipInit = *p->iWinSize;
2051 p->WinSize = 2;
2052 p->BufSize = 0;
2053 p->fforceSync = 0;
2054 return diskin2_init_array(csound,p,1);
2055 }
2056
diskin2_perf_array(CSOUND * csound,DISKIN2_ARRAY * p)2057 int32_t diskin2_perf_array(CSOUND *csound, DISKIN2_ARRAY *p) {
2058 if (!p->async) return diskin2_perf_synchronous_array(csound, p);
2059 else return diskin2_perf_asynchronous_array(csound, p);
2060 }
2061
2062 #if 0 // OLD SOUNDIN code VL 24-12-2016
2063 /* -------- soundin opcode: simplified version of diskin2 -------- */
2064
2065 static void soundin_read_buffer(CSOUND *csound, SOUNDIN_ *p, int32_t bufReadPos)
2066 {
2067 int32_t i = 0;
2068
2069 /* calculate new buffer frame start position */
2070 p->bufStartPos = p->bufStartPos + (int_least64_t) bufReadPos;
2071 p->bufStartPos &= (~((int_least64_t) (p->bufSize - 1)));
2072 if (p->bufStartPos >= (int_least64_t) 0) {
2073 int_least64_t lsmps;
2074 int32_t nsmps;
2075 /* number of sample frames to read */
2076 lsmps = p->fileLength - p->bufStartPos;
2077 if (lsmps > (int_least64_t) 0) { /* if there is anything to read: */
2078 nsmps = (lsmps < (int_least64_t) p->bufSize ? (int) lsmps : p->bufSize);
2079 /* convert sample count to mono samples and read file */
2080 nsmps *= (int32_t) p->nChannels;
2081 if (csound->oparms->realtime==0){
2082 sf_seek(p->sf, (sf_count_t) p->bufStartPos, SEEK_SET);
2083 i = (int32_t) sf_read_MYFLT(p->sf, p->buf, (sf_count_t) nsmps);
2084 }
2085 else
2086 i = (int32_t) csound->ReadAsync(csound, p->fdch.fd, p->buf,
2087 (sf_count_t) nsmps);
2088 if (UNLIKELY(i < 0)) /* error ? */
2089 i = 0; /* clear entire buffer to zero */
2090 }
2091 }
2092 /* fill rest of buffer with zero samples */
2093 for ( ; i < (p->bufSize * p->nChannels); i++)
2094 p->buf[i] = FL(0.0);
2095 }
2096
2097 /* calculate buffer size in sample frames */
2098
2099 static int32_t soundin_calc_buffer_size(SOUNDIN_ *p, int32_t n_monoSamps)
2100 {
2101 int32_t i, nFrames;
2102
2103 /* default to 2048 mono samples if zero or negative */
2104 if (n_monoSamps <= 0)
2105 n_monoSamps = 2048;
2106 /* convert mono samples -> sample frames */
2107 i = n_monoSamps / p->nChannels;
2108 /* limit to sane range */
2109 if (i > 1048576)
2110 i = 1048576;
2111 /* buffer size must be an integer power of two, so round up */
2112 nFrames = 32; /* will be at least 64 sample frames */
2113 do {
2114 nFrames <<= 1;
2115 } while (nFrames < i);
2116
2117 return nFrames;
2118 }
2119
2120 static int32_t sndinset_(CSOUND *csound, SOUNDIN_ *p, int32_t stringname)
2121 {
2122 double pos;
2123 char name[1024];
2124 void *fd;
2125 SF_INFO sfinfo;
2126 int32_t n, fmt, typ;
2127
2128 /* check number of channels */
2129 p->nChannels = (int32_t) (p->OUTOCOUNT);
2130 if (UNLIKELY(p->nChannels < 1 || p->nChannels > DISKIN2_MAXCHN)) {
2131 return csound->InitError(csound,
2132 Str("soundin: invalid number of channels"));
2133 }
2134 p->bufSize = soundin_calc_buffer_size(p, MYFLT2LONG(*p->iBufSize));
2135 /* if already open, close old file first */
2136 if (p->fdch.fd != NULL) {
2137 /* skip initialisation if requested */
2138 if (*(p->iSkipInit) != FL(0.0))
2139 return OK;
2140 csound_fd_close(csound, &(p->fdch));
2141 }
2142 /* set default format parameters */
2143 memset(&sfinfo, 0, sizeof(SF_INFO));
2144 sfinfo.samplerate = MYFLT2LONG(csound->esr);
2145 sfinfo.channels = p->nChannels;
2146 /* check for user specified sample format */
2147 n = MYFLT2LONG(*p->iSampleFormat);
2148 if (n == 1) {
2149 sfinfo.format = SF_FORMAT_RAW
2150 | (int32_t) FORMAT2SF(csound->oparms_.outformat);
2151 }
2152 else {
2153 if (n<0) {
2154 n = -n;
2155 if (UNLIKELY(n > 10))
2156 return csound->InitError(csound, Str("soundin: unknown sample format"));
2157 sfinfo.format = diskin2_format_table[n];
2158 }
2159 }
2160 /* open file */
2161 /* FIXME: name can overflow with very long string */
2162 if (stringname==0){
2163 if (csound->ISSTRCOD(*p->iFileCode))
2164 strNcpy(name,get_arg_string(csound, *p->iFileCode), 1023);
2165 else csound->strarg2name(csound, name, p->iFileCode, "soundin.",0);
2166 }
2167 else strNcpy(name, ((STRINGDAT *)p->iFileCode)->data, 1023);
2168
2169 if (csound->oparms->realtime==0)
2170 fd = csound->FileOpen2(csound, &(p->sf), CSFILE_SND_R, name, &sfinfo,
2171 "SFDIR;SSDIR", CSFTYPE_UNKNOWN_AUDIO, 0);
2172 else
2173 fd = csound->FileOpenAsync(csound, &(p->sf), CSFILE_SND_R, name, &sfinfo,
2174 "SFDIR;SSDIR", CSFTYPE_UNKNOWN_AUDIO,
2175 p->bufSize*p->nChannels, 0);
2176 if (UNLIKELY(fd == NULL)) {
2177 if (csound->oparms->realtime==0)
2178 return csound->InitError(csound,
2179 Str("soundin: %s: failed to open file: %s"),
2180 name, Str(sf_strerror(NULL)));
2181 else
2182 return csound->InitError(csound,
2183 Str("soundin: %s: failed to open file"), name);
2184 }
2185 /* record file handle so that it will be closed at note-off */
2186 memset(&(p->fdch), 0, sizeof(FDCH));
2187 p->fdch.fd = fd;
2188 fdrecord(csound, &(p->fdch));
2189 /* print file information */
2190 if (UNLIKELY((csound->oparms_.msglevel & 7) == 7)) {
2191 csound->Message(csound, Str("soundin: opened '%s':\n"
2192 " %d Hz, %d channel(s), "
2193 "%ld sample frames\n"),
2194 csound->GetFileName(fd),
2195 (int32_t) sfinfo.samplerate, (int32_t) sfinfo.channels,
2196 (int32_t) sfinfo.frames);
2197 }
2198 /* check number of channels in file (must equal the number of outargs) */
2199 if (UNLIKELY(sfinfo.channels != p->nChannels)) {
2200 return csound->InitError(csound,
2201 Str("soundin: number of output args "
2202 "inconsistent with number of file channels"));
2203 }
2204 /* skip initialisation if requested */
2205 if (p->auxData.auxp != NULL && *(p->iSkipInit) != FL(0.0))
2206 return OK;
2207 /* set file parameters from header info */
2208 p->fileLength = (int_least64_t) sfinfo.frames;
2209 if (MYFLT2LONG(csound->esr) != sfinfo.samplerate)
2210 csound->Warning(csound, Str("soundin: file sample rate (%d) "
2211 "!= orchestra sr (%d)\n"),
2212 sfinfo.samplerate, MYFLT2LONG(csound->esr));
2213 fmt = sfinfo.format & SF_FORMAT_SUBMASK;
2214 typ = sfinfo.format & SF_FORMAT_TYPEMASK;
2215 if ((fmt != SF_FORMAT_FLOAT && fmt != SF_FORMAT_DOUBLE) ||
2216 (typ == SF_FORMAT_WAV || typ == SF_FORMAT_W64 || typ == SF_FORMAT_AIFF))
2217 p->scaleFac = csound->e0dbfs;
2218 else
2219 p->scaleFac = FL(1.0); /* do not scale "raw" float files */
2220 /* initialise read position */
2221 pos = (double)*(p->iSkipTime) * (double)sfinfo.samplerate;
2222 p->read_pos = (int_least64_t)(pos + (pos >= 0.0 ? 0.5 : -0.5));
2223 /* allocate and initialise buffer */
2224 n = p->bufSize * p->nChannels;
2225 if (n != (int32_t) p->auxData.size)
2226 csound->AuxAlloc(csound, (int32_t)(n * (int32_t)sizeof(MYFLT)),
2227 &(p->auxData));
2228 p->buf = (MYFLT*) (p->auxData.auxp);
2229 /* make sure that read position is not in buffer, to force read */
2230 if (p->read_pos < (int_least64_t) 0)
2231 p->bufStartPos = (int_least64_t) p->bufSize;
2232 else
2233 p->bufStartPos = -((int_least64_t) p->bufSize);
2234 /* done initialisation */
2235 if (csound->oparms->realtime) {
2236 csound->FSeekAsync(csound,p->fdch.fd, p->read_pos, SEEK_SET);
2237 // csound->Message(csound, "using async code \n");
2238 }
2239 return OK;
2240 }
2241
2242
2243 int32_t sndinset(CSOUND *csound, SOUNDIN_ *p){
2244 return sndinset_(csound,p,0);
2245 }
2246
2247 int32_t sndinset_S(CSOUND *csound, SOUNDIN_ *p){
2248 return sndinset_(csound,p,1);
2249 }
2250
2251
2252 int32_t soundin(CSOUND *csound, SOUNDIN_ *p)
2253 {
2254 uint32_t offset = p->h.insdshead->ksmps_offset;
2255 uint32_t early = p->h.insdshead->ksmps_no_end;
2256 uint32_t nn, nsmps=CS_KSMPS, bufPos;
2257 int32_t i;
2258
2259 if (UNLIKELY(p->fdch.fd == NULL)) {
2260 return csound->PerfError(csound, &(p->h),
2261 Str("soundin: not initialised"));
2262 }
2263 if (UNLIKELY(offset)) for (i=0; i<p->nChannels; i++)
2264 memset(p->aOut[i], '\0', offset*sizeof(MYFLT));
2265 if (UNLIKELY(early)) {
2266 nsmps -= early;
2267 for (i=0; i<p->nChannels; i++)
2268 memset(&(p->aOut[i][nsmps]), '\0', early*sizeof(MYFLT));
2269 }
2270 for (nn = offset; nn < nsmps; nn++) {
2271 bufPos = (int32_t) (p->read_pos - p->bufStartPos);
2272 if ((uint32_t) bufPos >= (uint32_t) p->bufSize) {
2273 /* not in current buffer frame, need to read file */
2274 soundin_read_buffer(csound, p, bufPos);
2275 /* recalculate buffer position */
2276 bufPos = (int32_t) (p->read_pos - p->bufStartPos);
2277 }
2278 /* copy all channels from buffer */
2279 if (p->nChannels == 1) {
2280 p->aOut[0][nn] = p->scaleFac * (MYFLT) p->buf[bufPos];
2281 }
2282 else if (p->nChannels == 2) {
2283 bufPos += bufPos;
2284 p->aOut[0][nn] = p->scaleFac * p->buf[bufPos];
2285 p->aOut[1][nn] = p->scaleFac * p->buf[bufPos + 1];
2286 }
2287 else {
2288 bufPos *= p->nChannels;
2289 i = 0;
2290 do {
2291 p->aOut[i++][nn] = p->scaleFac * p->buf[bufPos++];
2292 } while (i < p->nChannels);
2293 }
2294 p->read_pos++;
2295 }
2296 return OK;
2297 }
2298 #endif
2299