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