1 /*
2     fout.c:
3 
4     Copyright (C) 1999 Gabriel Maldonado, John ffitch, Matt Ingalls
5         (C) 2005, 2006 Istvan Varga
6 
7     This file is part of Csound.
8 
9     The Csound Library is free software; you can redistribute it
10     and/or modify it under the terms of the GNU Lesser General Public
11     License as published by the Free Software Foundation; either
12     version 2.1 of the License, or (at your option) any later version.
13 
14     Csound is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU Lesser General Public License for more details.
18 
19     You should have received a copy of the GNU Lesser General Public
20     License along with Csound; if not, write to the Free Software
21     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22     02110-1301 USA
23 */
24 
25 /* Opcodes By Gabriel Maldonado, 1999 */
26 /* Code modified by JPff to remove fixed size arrays, allow
27    AIFF and WAV, and close files neatly.  Also bugs fixed */
28 
29 #include "stdopcod.h"
30 #include <sndfile.h>
31 #include "fout.h"
32 #include "soundio.h"
33 #include <ctype.h>
34 
35 /* remove a file reference, optionally closing the file */
36 
fout_deinit_callback(CSOUND * csound,void * p_)37 static CS_NOINLINE int32_t fout_deinit_callback(CSOUND *csound, void *p_)
38 {
39     FOUT_FILE         *p = (FOUT_FILE*) p_;
40     struct fileinTag  *pp;
41     p->sf = (SNDFILE*) NULL;
42     p->f = (FILE*) NULL;
43     if (p->idx) {
44       pp = &(((STDOPCOD_GLOBALS*) csound->stdOp_Env)->file_opened[p->idx - 1]);
45       p->idx = 0;
46       if (pp->refCount) {
47         pp->refCount--;
48         /* VL 29/08/07: files were not being closed properly,
49            changed check to 0 */
50         if (pp->refCount == 0/*0x80000000U*/) {
51           pp->file = (SNDFILE*) NULL;
52           pp->raw = (FILE*) NULL;
53           csound->Free(csound, pp->name);
54           pp->name = (char*) NULL;
55           pp->do_scale = 0;
56           pp->refCount = 0U;
57 
58           if (pp->fd != NULL) {
59             if ((csound->oparms->msglevel & 7) == 7)
60               csound->Message(csound, Str("Closing file '%s'...\n"),
61                                       csound->GetFileName(pp->fd));
62             csound->FileClose(csound, pp->fd);
63             pp->fd = NULL;
64           }
65         }
66       }
67     }
68 
69     return OK;
70 }
71 
fout_open_file(CSOUND * csound,FOUT_FILE * p,void * fp,int32_t fileType,MYFLT * iFile,int32_t isString,void * fileParams,int32_t forceSync)72 static CS_NOINLINE int32_t fout_open_file(CSOUND *csound, FOUT_FILE *p, void *fp,
73                                           int32_t fileType, MYFLT *iFile,
74                                           int32_t isString,
75                                           void *fileParams, int32_t forceSync)
76 {
77     STDOPCOD_GLOBALS  *pp = (STDOPCOD_GLOBALS*) csound->stdOp_Env;
78     char              *name;
79     int32_t               idx, csFileType, need_deinit = 0;
80 
81     if (p != (FOUT_FILE*) NULL) p->async = 0;
82     if (fp != NULL) {
83       if (fileType == CSFILE_STD)
84         *((FILE**) fp) = (FILE*) NULL;
85       else
86         *((SNDFILE**) fp) = (SNDFILE*) NULL;
87     }
88     /* if the opcode already uses a file, remove old reference first */
89     if (p != (FOUT_FILE*) NULL) {
90       if (p->idx)
91         fout_deinit_callback(csound, (void*) p);
92       else
93         need_deinit = 1;
94     }
95     /* get file name, */
96     if (isString) name = cs_strdup(csound, ((STRINGDAT *)iFile)->data);
97     else if (csound->ISSTRCOD(*iFile))
98       name = cs_strdup(csound, get_arg_string(csound, *iFile));
99     /* else csound->strarg2name(csound, NULL, iFile, "fout.", 0);*/
100     else {
101       /* or handle to previously opened file */
102       idx = (int32_t) MYFLT2LRND(*iFile);
103       if (UNLIKELY(idx < 0 || idx > pp->file_num ||
104                    (fileType == CSFILE_STD && pp->file_opened[idx].raw == NULL) ||
105                    (fileType != CSFILE_STD && pp->file_opened[idx].file == NULL))) {
106         return csound->InitError(csound, Str("invalid file handle"));
107       }
108       goto returnHandle;
109     }
110     /* check for a valid name */
111     if (UNLIKELY(name == NULL || name[0] == '\0')) {
112       csound->Free(csound, name);
113       return csound->InitError(csound, Str("invalid file name"));
114     }
115     /* is this file already open ? */
116     if (fileType == CSFILE_STD) {
117       for (idx = 0; idx <= pp->file_num; idx++) {
118         if (pp->file_opened[idx].raw != (FILE*) NULL &&
119             strcmp(pp->file_opened[idx].name, name) == 0)
120           goto returnHandle;
121       }
122     }
123     else {
124       for (idx = 0; idx <= pp->file_num; idx++) {
125         if (pp->file_opened[idx].file != (SNDFILE*) NULL &&
126             strcmp(pp->file_opened[idx].name, name) == 0)
127           goto returnHandle;
128       }
129     }
130     /* allocate new file handle, or use an already existing unused one */
131     for (idx = 0; idx <= pp->file_num; idx++) {
132       if (pp->file_opened[idx].fd == NULL)
133         break;
134     }
135     if (idx > pp->file_num) {
136       if (idx >= pp->file_max) {
137         struct fileinTag  *tmp;
138         /* Expand by 4 each time */
139         pp->file_max = (idx | 3) + 1;
140         tmp = (struct fileinTag *)
141             csound->ReAlloc(csound, pp->file_opened,
142                                     sizeof(struct fileinTag) * pp->file_max);
143         pp->file_opened = tmp;
144         memset(&(tmp[pp->file_num + 1]), 0,
145                sizeof(struct fileinTag) * (pp->file_max - (pp->file_num + 1)));
146       }
147       pp->file_num = idx;
148     }
149     memset(&pp->file_opened[idx], 0, sizeof(struct fileinTag));
150     /* pp->file_opened[idx].file = (SNDFILE*) NULL; */
151     /* pp->file_opened[idx].raw = (FILE*) NULL; */
152     /* pp->file_opened[idx].fd = NULL; */
153     /* pp->file_opened[idx].name = (char*) NULL; */
154     /* pp->file_opened[idx].do_scale = 0; */
155     /* pp->file_opened[idx].refCount = 0U; */
156     /* attempt to open file */
157     if (fileType == CSFILE_STD) {
158       FILE    *f;
159       void    *fd;
160       char    *filemode = (char*)fileParams;
161 
162       /* akozar: csFileType cannot be as specific as I'd like since it is not
163          possible to know the real file type until this handle is used */
164       if ((strcmp(filemode, "rb") == 0 || (strcmp(filemode, "wb") == 0)))
165             csFileType = CSFTYPE_OTHER_BINARY;
166       else  csFileType = CSFTYPE_OTHER_TEXT;
167       fd = csound->FileOpen2(csound, &f, fileType, name, fileParams, "",
168                                csFileType, 0);
169       if (UNLIKELY(fd == NULL)) {
170         csound->InitError(csound, Str("error opening file '%s'"), name);
171         csound->Free(csound, name);
172         return NOTOK;
173       }
174       /* setvbuf(f, (char *) NULL, _IOLBF, 0); */ /* Ensure line buffering */
175       pp->file_opened[idx].raw = f;
176       pp->file_opened[idx].fd = fd;
177     }
178     else {
179       SNDFILE *sf;
180       void    *fd;
181       //int32_t     buf_reqd;
182       int32_t     do_scale = 0;
183 
184       if (fileType == CSFILE_SND_W) {
185         do_scale = ((SF_INFO*) fileParams)->format;
186         csFileType = csound->sftype2csfiletype(do_scale);
187         if (csound->oparms->realtime == 0 || forceSync == 1) {
188           fd = csound->FileOpen2(csound, &sf, fileType, name, fileParams,
189                                 "SFDIR", csFileType, 0);
190           p->async = 0;
191         }
192         else {
193           p->fd = fd = csound->FileOpenAsync(csound, &sf, fileType,
194                                              name, fileParams,
195                                              "SFDIR;SSDIR", CSFTYPE_UNKNOWN_AUDIO,
196                                              p->bufsize,  0);
197           p->async = 1;
198         }
199         p->nchnls = ((SF_INFO*) fileParams)->channels;
200       }
201       else {
202         if (csound->oparms->realtime == 0 || forceSync == 1) {
203           fd = csound->FileOpen2(csound, &sf, fileType, name, fileParams,
204                                  "SFDIR;SSDIR", CSFTYPE_UNKNOWN_AUDIO, 0);
205           p->async = 0;
206 
207         } else {
208           p->fd = fd = csound->FileOpenAsync(csound, &sf, fileType,
209                                              name, fileParams,
210                                              "SFDIR;SSDIR", CSFTYPE_UNKNOWN_AUDIO,
211                                              p->bufsize,  0);
212           p->async = 1;
213         }
214         p->nchnls = ((SF_INFO*) fileParams)->channels;
215         do_scale = ((SF_INFO*) fileParams)->format;
216       }
217       do_scale = (SF2TYPE(do_scale) == TYP_RAW ? 0 : 1);
218       if (UNLIKELY(fd == NULL)) {
219         csound->InitError(csound, Str("error opening sound file '%s'"), name);
220         csound->Free(csound, name);
221         return NOTOK;
222       }
223       if (!do_scale) {
224 #ifdef USE_DOUBLE
225         sf_command(sf, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE);
226 #else
227         sf_command(sf, SFC_SET_NORM_FLOAT, NULL, SF_FALSE);
228 #endif
229       }
230       /* if (CS_KSMPS >= 512)
231         buf_reqd = CS_KSMPS * ((SF_INFO*) fileParams)->channels;
232       else
233         buf_reqd = (1 + (int32_t)(512 / CS_KSMPS)) * CS_KSMPS
234                    * ((SF_INFO*) fileParams)->channels;
235       if (UNLIKELY(buf_reqd > pp->buf_size)) {
236         pp->buf_size = buf_reqd;
237         pp->buf = (MYFLT*) csound->ReAlloc(csound, pp->buf, sizeof(MYFLT)
238                                                             * buf_reqd);
239       }
240       */ /* VL - now using per-instance buffer */
241       pp->file_opened[idx].file = sf;
242       pp->file_opened[idx].fd = fd;
243       pp->file_opened[idx].do_scale = do_scale;
244     }
245     /* store file information */
246     pp->file_opened[idx].name = name;
247 
248  returnHandle:
249     /* return 'idx' as file handle */
250     if (fp != NULL) {
251       if (fileType == CSFILE_STD)
252         *((FILE**) fp) = pp->file_opened[idx].raw;
253       else
254         *((SNDFILE**) fp) = pp->file_opened[idx].file;
255     }
256     if (p != (FOUT_FILE*) NULL) {
257       if (fileType == CSFILE_STD) {
258         p->sf = (SNDFILE*) NULL;
259         p->f = pp->file_opened[idx].raw;
260       }
261       else {
262         p->sf = pp->file_opened[idx].file;
263         p->f = (FILE*) NULL;
264       }
265       p->idx = idx + 1;
266       pp->file_opened[idx].refCount++;
267       if (need_deinit) {
268         p->h.insdshead = csound->ids->insdshead;
269         /* FIXME: should check for error here */
270         csound->RegisterDeinitCallback(csound, p, fout_deinit_callback);
271       }
272     }
273     return idx;
274 }
275 
outfile(CSOUND * csound,OUTFILE * p)276 static int32_t outfile(CSOUND *csound, OUTFILE *p)
277 {
278     uint32_t offset = p->h.insdshead->ksmps_offset;
279     uint32_t early  = p->h.insdshead->ksmps_no_end;
280     uint32_t i, j, k, nsmps = CS_KSMPS;
281     uint32_t nargs = p->nargs;
282     MYFLT *buf = (MYFLT *) p->buf.auxp;
283 
284     if (UNLIKELY(early)) nsmps -= early;
285     if (p->f.sf == NULL) {
286       if (p->f.f != NULL) { /* VL: make sure there is an open file */
287         FILE  *fp = p->f.f;
288         for (k = offset; k < nsmps; k++) {
289           for (j = 0; j < nargs; j++)
290             fprintf(fp, "%g ", p->argums[j][k]);
291           fprintf(fp, "\n");
292         }
293       }
294     }
295     else {
296       for (j = offset, k = p->buf_pos; j < nsmps; j++)
297         for (i = 0; i < nargs; i++)
298           buf[k++] = p->argums[i][j] * p->scaleFac;
299       p->buf_pos = k;
300       if (p->buf_pos >= p->guard_pos) {
301 
302         //#ifndef USE_DOUBLE
303         //sf_write_float(p->f.sf, buf, p->buf_pos);
304         //#else
305         //sf_write_double(p->f.sf, buf, p->buf_pos);
306         //#endif
307         if (p->f.async==1)
308           csound->WriteAsync(csound, p->f.fd, buf, p->buf_pos);
309         else sf_write_MYFLT(p->f.sf, buf, p->buf_pos);
310         p->buf_pos = 0;
311       }
312 
313     }
314     return OK;
315 }
316 
outfile_array(CSOUND * csound,OUTFILEA * p)317 static int32_t outfile_array(CSOUND *csound, OUTFILEA *p)
318 {
319     uint32_t offset = p->h.insdshead->ksmps_offset;
320     uint32_t early  = p->h.insdshead->ksmps_no_end;
321     uint32_t i, j, k, nsmps = CS_KSMPS;
322     uint32_t nargs = p->tabin->sizes[0];
323     MYFLT *buf = (MYFLT *) p->buf.auxp;
324     MYFLT *data = p->tabin->data;
325 
326     if (UNLIKELY(early)) nsmps -= early;
327     if (p->f.sf == NULL) {
328       if (p->f.f != NULL) { /* VL: make sure there is an open file */
329         FILE  *fp = p->f.f;
330         for (k = offset; k < nsmps; k++) {
331           for (j = 0; j < nargs; j++)
332             fprintf(fp, "%g ", data[j*CS_KSMPS+k]);
333           fprintf(fp, "\n");
334         }
335       }
336     }
337     else {
338       for (j = offset, k = p->buf_pos; j < nsmps; j++)
339         for (i = 0; i < nargs; i++)
340           buf[k++] = data[i*CS_KSMPS+j] * p->scaleFac;
341       p->buf_pos = k;
342       if (p->buf_pos >= p->guard_pos) {
343 
344         //#ifndef USE_DOUBLE
345         //sf_write_float(p->f.sf, buf, p->buf_pos);
346         //#else
347         //sf_write_double(p->f.sf, buf, p->buf_pos);
348         //#endif
349         if (p->f.async==1)
350           csound->WriteAsync(csound, p->f.fd, buf, p->buf_pos);
351         else
352           sf_write_MYFLT(p->f.sf, buf, p->buf_pos);
353         p->buf_pos = 0;
354        }
355 
356     }
357     return OK;
358 }
359 
360 static const int32_t fout_format_table[51] = {
361     /* 0 - 9 */
362     (SF_FORMAT_FLOAT | SF_FORMAT_RAW), (SF_FORMAT_PCM_16 | SF_FORMAT_RAW),
363     SF_FORMAT_PCM_16, SF_FORMAT_ULAW, SF_FORMAT_PCM_16, SF_FORMAT_PCM_32,
364     SF_FORMAT_FLOAT, SF_FORMAT_PCM_U8, SF_FORMAT_PCM_24, SF_FORMAT_DOUBLE,
365     /* 10 - 19 */
366     SF_FORMAT_WAV, (SF_FORMAT_PCM_S8 | SF_FORMAT_WAV),
367     (SF_FORMAT_ALAW | SF_FORMAT_WAV), (SF_FORMAT_ULAW | SF_FORMAT_WAV),
368     (SF_FORMAT_PCM_16 | SF_FORMAT_WAV), (SF_FORMAT_PCM_32 | SF_FORMAT_WAV),
369     (SF_FORMAT_FLOAT | SF_FORMAT_WAV), (SF_FORMAT_PCM_U8 | SF_FORMAT_WAV),
370     (SF_FORMAT_PCM_24 | SF_FORMAT_WAV), (SF_FORMAT_DOUBLE | SF_FORMAT_WAV),
371     /* 20 - 29 */
372     SF_FORMAT_AIFF, (SF_FORMAT_PCM_S8 | SF_FORMAT_AIFF),
373     (SF_FORMAT_ALAW | SF_FORMAT_AIFF), (SF_FORMAT_ULAW | SF_FORMAT_AIFF),
374     (SF_FORMAT_PCM_16 | SF_FORMAT_AIFF), (SF_FORMAT_PCM_32 | SF_FORMAT_AIFF),
375     (SF_FORMAT_FLOAT | SF_FORMAT_AIFF), (SF_FORMAT_PCM_U8 | SF_FORMAT_AIFF),
376     (SF_FORMAT_PCM_24 | SF_FORMAT_AIFF), (SF_FORMAT_DOUBLE | SF_FORMAT_AIFF),
377     /* 30 - 39 */
378     SF_FORMAT_RAW, (SF_FORMAT_PCM_S8 | SF_FORMAT_RAW),
379     (SF_FORMAT_ALAW | SF_FORMAT_RAW), (SF_FORMAT_ULAW | SF_FORMAT_RAW),
380     (SF_FORMAT_PCM_16 | SF_FORMAT_RAW), (SF_FORMAT_PCM_32 | SF_FORMAT_RAW),
381     (SF_FORMAT_FLOAT | SF_FORMAT_RAW), (SF_FORMAT_PCM_U8 | SF_FORMAT_RAW),
382     (SF_FORMAT_PCM_24 | SF_FORMAT_RAW), (SF_FORMAT_DOUBLE | SF_FORMAT_RAW),
383     /* 40 - 49 */
384     SF_FORMAT_IRCAM, (SF_FORMAT_PCM_S8 | SF_FORMAT_IRCAM),
385     (SF_FORMAT_ALAW | SF_FORMAT_IRCAM), (SF_FORMAT_ULAW | SF_FORMAT_IRCAM),
386     (SF_FORMAT_PCM_16 | SF_FORMAT_IRCAM), (SF_FORMAT_PCM_32 | SF_FORMAT_IRCAM),
387     (SF_FORMAT_FLOAT | SF_FORMAT_IRCAM), (SF_FORMAT_PCM_U8 | SF_FORMAT_IRCAM),
388     (SF_FORMAT_PCM_24 | SF_FORMAT_IRCAM), (SF_FORMAT_DOUBLE | SF_FORMAT_IRCAM),
389     /* 50 */
390     (SF_FORMAT_OGG | SF_FORMAT_VORBIS)
391 };
392 
fout_flush_callback(CSOUND * csound,void * p_)393 static int32_t fout_flush_callback(CSOUND *csound, void *p_)
394 {
395     OUTFILE            *p = (OUTFILE*) p_;
396 
397     if (p->f.sf != NULL && p->buf_pos > 0) {
398       //#ifndef USE_DOUBLE
399       //sf_write_float(p->f.sf, (float*) p->buf.auxp, p->buf_pos);
400       //#else
401       //sf_write_double(p->f.sf, (double*) p->buf.auxp, p->buf_pos);
402       //#endif
403       if (p->f.async == 1)
404         csound->WriteAsync(csound, p->f.fd, (MYFLT *) p->buf.auxp, p->buf_pos);
405       else
406         sf_write_MYFLT(p->f.sf, (MYFLT *) p->buf.auxp, p->buf_pos);
407     }
408     return OK;
409 }
410 
fouta_flush_callback(CSOUND * csound,void * p_)411 static int32_t fouta_flush_callback(CSOUND *csound, void *p_)
412 {
413     OUTFILEA           *p = (OUTFILEA*) p_;
414 
415     if (p->f.sf != NULL && p->buf_pos > 0) {
416       //#ifndef USE_DOUBLE
417       //sf_write_float(p->f.sf, (float*) p->buf.auxp, p->buf_pos);
418       //#else
419       //sf_write_double(p->f.sf, (double*) p->buf.auxp, p->buf_pos);
420       //#endif
421       if (p->f.async == 1)
422         csound->WriteAsync(csound, p->f.fd, (MYFLT *) p->buf.auxp, p->buf_pos);
423       else
424         sf_write_MYFLT(p->f.sf, (MYFLT *) p->buf.auxp, p->buf_pos);
425     }
426     return OK;
427 }
428 
outfile_set_S(CSOUND * csound,OUTFILE * p)429 static int32_t outfile_set_S(CSOUND *csound, OUTFILE *p/*, int32_t istring*/)
430 {
431     SF_INFO sfinfo;
432     int32_t     format_, n, buf_reqd;
433     int32_t istring = 1;
434 
435     memset(&sfinfo, 0, sizeof(SF_INFO));
436     format_ = (int32_t) MYFLT2LRND(*p->iflag);
437     if (format_ >= 51)
438       sfinfo.format = SF_FORMAT_PCM_16 | SF_FORMAT_RAW;
439     else if (format_ < 0) {
440       sfinfo.format = FORMAT2SF(csound->oparms->outformat);
441       sfinfo.format |= TYPE2SF(csound->oparms->filetyp);
442     }
443     else sfinfo.format = fout_format_table[format_];
444     if (!SF2FORMAT(sfinfo.format))
445       sfinfo.format |= FORMAT2SF(csound->oparms->outformat);
446     if (!SF2TYPE(sfinfo.format))
447       sfinfo.format |= TYPE2SF(csound->oparms->filetyp);
448     sfinfo.samplerate = (int32_t) MYFLT2LRND(CS_ESR);
449     p->nargs = p->INOCOUNT - 2;
450     p->buf_pos = 0;
451 
452     if (CS_KSMPS >= 512)
453       p->guard_pos = CS_KSMPS * p->nargs;
454     else
455       p->guard_pos = 512* p->nargs;
456 
457     if (CS_KSMPS >= 512)
458       buf_reqd = CS_KSMPS *  p->nargs;
459     else
460       buf_reqd = (1 + (int32_t)(512 / CS_KSMPS)) * CS_KSMPS *  p->nargs;
461     if (p->buf.auxp == NULL || p->buf.size < buf_reqd*sizeof(MYFLT)) {
462       csound->AuxAlloc(csound, sizeof(MYFLT)*buf_reqd, &p->buf);
463     }
464     p->f.bufsize =  p->buf.size;
465     sfinfo.channels = p->nargs;
466     n = fout_open_file(csound, &(p->f), NULL, CSFILE_SND_W,
467                        p->fname, istring, &sfinfo, 0);
468     if (UNLIKELY(n < 0))
469       return NOTOK;
470 
471     if (((STDOPCOD_GLOBALS*) csound->stdOp_Env)->file_opened[n].do_scale)
472       p->scaleFac = csound->dbfs_to_float;
473     else
474       p->scaleFac = FL(1.0);
475 
476     csound->RegisterDeinitCallback(csound, p, fout_flush_callback);
477     return OK;
478 }
479 
480 /* static int32_t outfile_set(CSOUND *csound, OUTFILE *p){ */
481 /*   return outfile_set_(csound,p,0); */
482 /* } */
483 
484 /* static int32_t outfile_set_S(CSOUND *csound, OUTFILE *p){ */
485 /*   return outfile_set_(csound,p,1); */
486 /* } */
487 
outfile_set_A(CSOUND * csound,OUTFILEA * p)488 static int32_t outfile_set_A(CSOUND *csound, OUTFILEA *p)
489 {
490     SF_INFO sfinfo;
491     int32_t     format_, n, buf_reqd;
492     int32_t len = p->tabin->sizes[0];
493 
494     memset(&sfinfo, 0, sizeof(SF_INFO));
495     format_ = (int32_t) MYFLT2LRND(*p->iflag);
496      if (format_ >=  51)
497       sfinfo.format = SF_FORMAT_PCM_16 | SF_FORMAT_RAW;
498     else if (format_ < 0) {
499       sfinfo.format = FORMAT2SF(csound->oparms->outformat);
500       sfinfo.format |= TYPE2SF(csound->oparms->filetyp);
501     }
502     else
503       sfinfo.format = fout_format_table[format_];
504     if (!SF2FORMAT(sfinfo.format))
505       sfinfo.format |= FORMAT2SF(csound->oparms->outformat);
506     if (!SF2TYPE(sfinfo.format))
507       sfinfo.format |= TYPE2SF(csound->oparms->filetyp);
508     sfinfo.samplerate = (int32_t) MYFLT2LRND(CS_ESR);
509     p->buf_pos = 0;
510 
511     if (CS_KSMPS >= 512)
512       buf_reqd = p->guard_pos = CS_KSMPS * len;
513     else {
514       p->guard_pos = 512 * len;
515       buf_reqd = (1 + (int32_t)(512 / CS_KSMPS)) * p->guard_pos;
516       // Or......
517       //buf_reqd = (1 + (int32_t)(512 / CS_KSMPS)) * CS_KSMPS * len;
518     }
519     if (p->buf.auxp == NULL || p->buf.size < buf_reqd*sizeof(MYFLT)) {
520       csound->AuxAlloc(csound, sizeof(MYFLT)*buf_reqd, &p->buf);
521     }
522     p->f.bufsize =  p->buf.size;
523     sfinfo.channels = len;
524     n = fout_open_file(csound, &(p->f), NULL, CSFILE_SND_W,
525                        p->fname, 1, &sfinfo, 0);
526     if (UNLIKELY(n < 0))
527       return NOTOK;
528 
529     if (((STDOPCOD_GLOBALS*) csound->stdOp_Env)->file_opened[n].do_scale)
530       p->scaleFac = csound->dbfs_to_float;
531     else
532       p->scaleFac = FL(1.0);
533 
534     csound->RegisterDeinitCallback(csound, p, fouta_flush_callback);
535     return OK;
536 }
537 
538 
koutfile(CSOUND * csound,KOUTFILE * p)539 static int32_t koutfile(CSOUND *csound, KOUTFILE *p)
540 {
541     int32_t   i, k;
542     int32_t nargs = p->nargs;
543     MYFLT *buf = (MYFLT *) p->buf.auxp;
544 
545     for (i = 0, k = p->buf_pos; i < nargs; i++)
546       buf[k++] = p->argums[i][0] * p->scaleFac;
547     p->buf_pos = k;
548     if (p->buf_pos >= p->guard_pos) {
549         //#ifndef USE_DOUBLE
550         //sf_write_float(p->f.sf, buf, p->buf_pos);
551         //#else
552         //sf_write_double(p->f.sf, buf, p->buf_pos);
553         //#endif
554       if (p->f.async==1)
555         csound->WriteAsync(csound, p->f.fd, buf, p->buf_pos);
556       else sf_write_MYFLT(p->f.sf, buf, p->buf_pos);
557       p->buf_pos = 0;
558     }
559     return OK;
560 }
561 
koutfile_set_(CSOUND * csound,KOUTFILE * p,int32_t istring)562 static int32_t koutfile_set_(CSOUND *csound, KOUTFILE *p, int32_t istring)
563 {
564     SF_INFO sfinfo;
565     int32_t     format_, n, buf_reqd;
566 
567     memset(&sfinfo, 0, sizeof(SF_INFO));
568     p->nargs = p->INOCOUNT - 2;
569     p->buf_pos = 0;
570 
571     if (CS_KSMPS >= 512)
572       p->guard_pos = CS_KSMPS * p->nargs;
573     else
574       p->guard_pos = 512 * p->nargs;
575 
576     sfinfo.channels = p->nargs;
577     sfinfo.samplerate = (int32_t) MYFLT2LRND(CS_EKR);
578     format_ = (int32_t) MYFLT2LRND(*p->iflag);
579     if ((uint32_t) format_ >= 10ul)
580       sfinfo.format = SF_FORMAT_PCM_16 | SF_FORMAT_RAW;
581     else
582       sfinfo.format = fout_format_table[format_] | SF_FORMAT_RAW;
583 
584     if (CS_KSMPS >= 512)
585       buf_reqd = CS_KSMPS *  p->nargs;
586     else
587       buf_reqd = (1 + (int32_t)(512 / CS_KSMPS)) * CS_KSMPS * p->nargs;
588     if (p->buf.auxp == NULL || p->buf.size < buf_reqd*sizeof(MYFLT)) {
589       csound->AuxAlloc(csound, sizeof(MYFLT)*buf_reqd, &p->buf);
590     }
591     p->f.bufsize = p->buf.size;
592     n = fout_open_file(csound, &(p->f), NULL, CSFILE_SND_W,
593                        p->fname, istring, &sfinfo, 0);
594     if (UNLIKELY(n < 0))
595       return NOTOK;
596 
597     if (((STDOPCOD_GLOBALS*) csound->stdOp_Env)->file_opened[n].do_scale)
598       p->scaleFac = csound->dbfs_to_float;
599     else
600       p->scaleFac = FL(1.0);
601 
602     csound->RegisterDeinitCallback(csound, p, fout_flush_callback);
603     return OK;
604 }
605 
koutfile_set(CSOUND * csound,KOUTFILE * p)606 static int32_t koutfile_set(CSOUND *csound, KOUTFILE *p){
607   return koutfile_set_(csound,p,0);
608 }
609 
koutfile_set_S(CSOUND * csound,KOUTFILE * p)610 static int32_t koutfile_set_S(CSOUND *csound, KOUTFILE *p){
611   return koutfile_set_(csound,p,1);
612 }
613 
614 
615 /*--------------*/
616 
617 /* syntax:
618         ihandle fiopen "filename" [, iascii]
619 */
620 
621 /* open a file and return its handle  */
622 /* the handle is simply a stack index */
623 
fiopen_(CSOUND * csound,FIOPEN * p,int32_t istring)624 static int32_t fiopen_(CSOUND *csound, FIOPEN *p, int32_t istring)
625 {
626     char    *omodes[] = {"w", "r", "wb", "rb"};
627     FILE    *rfp = (FILE*) NULL;
628     int32_t     idx = (int32_t) MYFLT2LRND(*p->iascii), n;
629 
630     if (idx < 0 || idx > 3)
631       idx = 0;
632     n = fout_open_file(csound, (FOUT_FILE*) NULL, &rfp, CSFILE_STD,
633                        p->fname, istring, omodes[idx], 1);
634     if (UNLIKELY(n < 0))
635       return NOTOK;
636     if (idx > 1)
637       setbuf(rfp, NULL);
638     *p->ihandle = (MYFLT) n;
639 
640     return OK;
641 }
642 
fiopen(CSOUND * csound,FIOPEN * p)643 static int32_t fiopen(CSOUND *csound, FIOPEN *p){
644     return fiopen_(csound, p, 0);
645 }
646 
fiopen_S(CSOUND * csound,FIOPEN * p)647 static int32_t fiopen_S(CSOUND *csound, FIOPEN *p){
648     return fiopen_(csound, p, 1);
649 }
650 
ficlose_opcode_(CSOUND * csound,FICLOSE * p,int32_t istring)651 static int32_t ficlose_opcode_(CSOUND *csound, FICLOSE *p, int32_t istring)
652 {
653     STDOPCOD_GLOBALS  *pp = (STDOPCOD_GLOBALS*) csound->stdOp_Env;
654     int32_t               idx = -1;
655 
656     if (istring || csound->ISSTRCOD(*(p->iFile))) {
657       char    *fname = NULL;
658       if (istring) fname = cs_strdup(csound, ((STRINGDAT *)p->iFile)->data);
659       else if (csound->ISSTRCOD(*(p->iFile)))
660         fname = cs_strdup(csound, get_arg_string(csound, *p->iFile));
661       if (UNLIKELY(fname == NULL || fname[0] == (char) 0)) {
662         if (fname != NULL) csound->Free(csound, fname);
663         return csound->InitError(csound, Str("invalid file name"));
664       }
665       for (idx = 0; idx <= pp->file_num; idx++) {
666         if (pp->file_opened[idx].fd != NULL &&
667             pp->file_opened[idx].name != (char*) NULL &&
668             strcmp(fname, pp->file_opened[idx].name) == 0)
669           break;
670       }
671       if (UNLIKELY(idx > pp->file_num)) {
672         csound->Warning(csound, Str("cannot close '%s': "
673                                     "not found in list of open files"), fname);
674         csound->Free(csound, fname);
675         return OK;
676       }
677       csound->Free(csound, fname);
678     }
679     else {
680       idx = (int32_t) MYFLT2LRND(*(p->iFile));
681       if (UNLIKELY(idx < 0 || idx > pp->file_num ||
682                    pp->file_opened[idx].fd == NULL)) {
683         csound->Warning(csound,
684                         Str("cannot close file #%d: not a valid handle"), idx);
685         return OK;
686       }
687     }
688     if (pp->file_opened[idx].refCount) {
689       if (UNLIKELY(!(pp->file_opened[idx].refCount & 0x80000000U))) {
690         pp->file_opened[idx].refCount |= 0x80000000U;
691         csound->Warning(csound, Str("file #%d (%s) is in use, will be closed "
692                                     "when released"),
693                                 idx, pp->file_opened[idx].name);
694       }
695     }
696     else {
697       FOUT_FILE tmp;
698       pp->file_opened[idx].refCount = 1;
699           /*ref count was set to 0x80000001U, but it needs to be 1 */
700       memset(&tmp, 0, sizeof(FOUT_FILE));
701       tmp.h.insdshead = p->h.insdshead;
702       tmp.idx = idx + 1;
703       fout_deinit_callback(csound, (void*) &tmp);
704     }
705 
706     return OK;
707 }
708 
ficlose_opcode(CSOUND * csound,FICLOSE * p)709 static int32_t ficlose_opcode(CSOUND *csound, FICLOSE *p){
710     return ficlose_opcode_(csound,p,0);
711 }
712 
ficlose_opcode_S(CSOUND * csound,FICLOSE * p)713 static int32_t ficlose_opcode_S(CSOUND *csound, FICLOSE *p){
714     return ficlose_opcode_(csound,p,1);
715 }
716 
717 /* syntax:
718    fouti  ihandle, iascii, iflag, iarg1 [, iarg2, ...., iargN]
719 */
720 
ioutfile_set(CSOUND * csound,IOUTFILE * p)721 static int32_t ioutfile_set(CSOUND *csound, IOUTFILE *p)
722 {
723     STDOPCOD_GLOBALS  *pp = (STDOPCOD_GLOBALS*) csound->stdOp_Env;
724     MYFLT   **args = p->argums;
725     FILE    *rfil;
726     uint32_t j;
727     int32_t     n = (int32_t) MYFLT2LRND(*p->ihandle);
728 
729     if (UNLIKELY(n < 0 || n > pp->file_num))
730       return csound->InitError(csound, Str("fouti: invalid file handle"));
731     rfil = pp->file_opened[n].raw;
732     if (UNLIKELY(rfil == NULL))
733       return csound->InitError(csound, Str("fouti: invalid file handle"));
734     if (*p->iascii == 0) { /* ascii format */
735       switch ((int32_t) MYFLT2LRND(*p->iflag)) {
736       case 1:
737         {     /* with prefix (i-statement, p1, p2 and p3) */
738           int32_t     p1 = (int32_t) p->h.insdshead->p1.value;
739           double  p2 = (double) CS_KCNT * CS_ONEDKR;
740           double  p3 = p->h.insdshead->p3.value;
741           if (p3 > FL(0.0))
742             fprintf(rfil, "i %i %f %f ", p1, p2, p3);
743           else
744             fprintf(rfil, "i %i %f . ", p1, p2);
745         }
746         break;
747       case 2: /* with prefix (start at 0 time) */
748         if (pp->fout_kreset == 0)
749           pp->fout_kreset = CS_KCNT;
750         {
751           int32_t p1 = (int32_t) p->h.insdshead->p1.value;
752           double p2 = (double) (CS_KCNT - pp->fout_kreset)
753                       * CS_ONEDKR;
754           double p3 = p->h.insdshead->p3.value;
755           if (p3 > FL(0.0))
756             fprintf(rfil, "i %i %f %f ", p1, p2, p3);
757           else
758             fprintf(rfil, "i %i %f . ", p1, p2);
759         }
760         break;
761       case 3: /* reset */
762         pp->fout_kreset = 0;
763         return OK;
764       }
765       for (j = 0; j < p->INOCOUNT - 3; j++) {
766         fprintf(rfil, " %f", (double) *args[j]);
767       }
768       putc('\n', rfil);
769     }
770     else { /* binary format */
771       for (j = 0; j < p->INOCOUNT - 3; j++) {
772         if (UNLIKELY(1!=fwrite(args[j], sizeof(MYFLT), 1, rfil))) return NOTOK;
773       }
774     }
775     return OK;
776 }
777 
778 
779 
ioutfile_set_r(CSOUND * csound,IOUTFILE_R * p)780 static int32_t ioutfile_set_r(CSOUND *csound, IOUTFILE_R *p)
781 {
782     STDOPCOD_GLOBALS  *pp = (STDOPCOD_GLOBALS*) csound->stdOp_Env;
783     if (p->h.insdshead->xtratim < 1)
784       p->h.insdshead->xtratim = 1;
785     p->counter =  CS_KCNT;
786     p->done = 1;
787     if (*p->iflag == 2 && pp->fout_kreset == 0)
788       pp->fout_kreset = CS_KCNT;
789     return OK;
790 }
791 
ioutfile_r(CSOUND * csound,IOUTFILE_R * p)792 static int32_t ioutfile_r(CSOUND *csound, IOUTFILE_R *p)
793 {
794     STDOPCOD_GLOBALS  *pp;
795     MYFLT **args;
796     FILE  *rfil;
797     uint32_t   j;
798     int32_t n;
799 
800     if (!p->h.insdshead->relesing || !p->done)
801       return OK;
802 
803     pp = (STDOPCOD_GLOBALS*) csound->stdOp_Env;
804     args = p->argums;
805     n = (int32_t) MYFLT2LRND(*p->ihandle);
806     if (UNLIKELY(n < 0 || n > pp->file_num))
807       return csound->InitError(csound, Str("fouti: invalid file handle"));
808     rfil = pp->file_opened[n].raw;
809     if (UNLIKELY(rfil == NULL))
810       return csound->InitError(csound, Str("fouti: invalid file handle"));
811     if (*p->iascii == 0) { /* ascii format */
812       switch ((int32_t) MYFLT2LRND(*p->iflag)) {
813       case 1:
814         {     /* whith prefix (i-statement, p1, p2 and p3) */
815           int32_t p1 = (int32_t) p->h.insdshead->p1.value;
816           double p2 = p->counter * CS_ONEDKR;
817           double p3 = (double) (CS_KCNT - p->counter)
818                       * CS_ONEDKR;
819           fprintf(rfil, "i %i %f %f ", p1, p2, p3);
820         }
821         break;
822       case 2: /* with prefix (start at 0 time) */
823         {
824           int32_t p1 = (int32_t) p->h.insdshead->p1.value;
825           double p2 = (p->counter - pp->fout_kreset) * CS_ONEDKR;
826           double p3 = (double) (CS_KCNT - p->counter)
827                       * CS_ONEDKR;
828           fprintf(rfil, "i %i %f %f ", p1, p2, p3);
829         }
830         break;
831       case 3: /* reset */
832         pp->fout_kreset = 0;
833         return OK;
834       }
835       for (j = 0; j < p->INOCOUNT - 3; j++) {
836         fprintf(rfil, " %f", (double) *args[j]);
837       }
838       putc('\n', rfil);
839     }
840     else { /* binary format */
841       for (j = 0; j < p->INOCOUNT - 3; j++) {
842         if (UNLIKELY(1!=fwrite(args[j], sizeof(MYFLT), 1, rfil))) return NOTOK;
843       }
844     }
845     p->done = 0;
846 
847     return OK;
848 }
849 
850 /*----------------------------------*/
851 
infile_set_(CSOUND * csound,INFILE * p,int32_t istring)852 static int32_t infile_set_(CSOUND *csound, INFILE *p, int32_t istring)
853 {
854     SF_INFO sfinfo;
855     int32_t     n, buf_reqd;
856     p->nargs = p->INOCOUNT - 3;
857     p->currpos = MYFLT2LRND(*p->iskpfrms);
858     p->flag = 1;
859     memset(&sfinfo, 0, sizeof(SF_INFO));
860     sfinfo.samplerate = (int32_t) MYFLT2LRND(CS_ESR);
861     /* Following code is seriously broken*/
862     if ((int32_t) MYFLT2LRND(*p->iflag) == -2)
863       sfinfo.format = FORMAT2SF(AE_FLOAT) | TYPE2SF(TYP_RAW);
864     else if ((int32_t) MYFLT2LRND(*p->iflag) == -1)
865       sfinfo.format = FORMAT2SF(AE_SHORT) | TYPE2SF(TYP_RAW);
866     else
867       sfinfo.format = 0;
868     sfinfo.channels = p->INOCOUNT - 3;
869      if (CS_KSMPS >= 512)
870       p->frames = CS_KSMPS;
871     else
872       p->frames = (int32_t)(512 / CS_KSMPS) * CS_KSMPS;
873 
874     if (CS_KSMPS >= 512)
875       buf_reqd = CS_KSMPS * sfinfo.channels;
876     else
877       buf_reqd = (1 + (int32_t)(512 / CS_KSMPS)) * CS_KSMPS * p->nargs;
878     if (p->buf.auxp == NULL || p->buf.size < buf_reqd*sizeof(MYFLT)) {
879       csound->AuxAlloc(csound, sizeof(MYFLT)*buf_reqd, &p->buf);
880     }
881     p->f.bufsize =  p->buf.size;
882     n = fout_open_file(csound, &(p->f), NULL, CSFILE_SND_R,
883                        p->fname, istring, &sfinfo, 0);
884     if (UNLIKELY(n < 0))
885       return NOTOK;
886 
887     if (((STDOPCOD_GLOBALS*) csound->stdOp_Env)->file_opened[n].do_scale)
888       p->scaleFac = csound->e0dbfs;
889     else
890       p->scaleFac = FL(1.0);
891 
892 
893 
894     p->guard_pos = p->frames * p->nargs;
895     p->buf_pos = p->guard_pos;
896 
897     if (p->f.async == 1)
898     csound->FSeekAsync(csound,p->f.fd, p->currpos*p->f.nchnls, SEEK_SET);
899 
900     return OK;
901 }
902 
infile_set(CSOUND * csound,INFILE * p)903 static int32_t infile_set(CSOUND *csound, INFILE *p){
904     return infile_set_(csound,p,0);
905 }
906 
infile_set_S(CSOUND * csound,INFILE * p)907 static int32_t infile_set_S(CSOUND *csound, INFILE *p){
908     return infile_set_(csound,p,1);
909 }
910 
911 #include "arrays.h"
912 
infile_set_A(CSOUND * csound,INFILEA * p)913 static int32_t infile_set_A(CSOUND *csound, INFILEA *p)
914 {
915     SF_INFO sfinfo;
916     int32_t     n, buf_reqd;
917     p->currpos = MYFLT2LRND(*p->iskpfrms);
918     p->flag = 1;
919     memset(&sfinfo, 0, sizeof(SF_INFO));
920     sfinfo.samplerate = (int32_t) MYFLT2LRND(CS_ESR);
921     if ((int32_t) MYFLT2LRND(*p->iflag) == -2)
922       sfinfo.format = FORMAT2SF(AE_FLOAT) | TYPE2SF(TYP_RAW);
923     else if ((int32_t) MYFLT2LRND(*p->iflag) == -1)
924       sfinfo.format = FORMAT2SF(AE_SHORT) | TYPE2SF(TYP_RAW);
925     else
926       sfinfo.format = 0;
927     sfinfo.channels = p->INOCOUNT - 3;
928     if (CS_KSMPS >= 512)
929       p->frames = CS_KSMPS;
930     else
931       p->frames = (int32_t)(512 / CS_KSMPS) * CS_KSMPS;
932     p->chn = sfinfo.channels;
933     if (CS_KSMPS >= 512)
934       buf_reqd = CS_KSMPS * sfinfo.channels;
935     else
936       buf_reqd = (1 + (int32_t)(512 / CS_KSMPS)) * CS_KSMPS * sfinfo.channels;
937     if (p->buf.auxp == NULL || p->buf.size < buf_reqd*sizeof(MYFLT)) {
938       csound->AuxAlloc(csound, sizeof(MYFLT)*buf_reqd, &p->buf);
939     }
940     p->f.bufsize =  p->buf.size;
941     n = fout_open_file(csound, &(p->f), NULL, CSFILE_SND_R,
942                        p->fname, 1, &sfinfo, 0);
943     if (UNLIKELY(n < 0))
944       return NOTOK;
945 
946     if (((STDOPCOD_GLOBALS*) csound->stdOp_Env)->file_opened[n].do_scale)
947       p->scaleFac = csound->e0dbfs;
948     else
949       p->scaleFac = FL(1.0);
950 
951     p->guard_pos = p->frames * p->chn;
952     p->buf_pos = p->guard_pos;
953 
954     if (p->f.async == 1)
955     csound->FSeekAsync(csound,p->f.fd, p->currpos*p->f.nchnls, SEEK_SET);
956 
957     tabinit(csound, p->tabout, p->chn);
958     return OK;
959 }
960 
infile_act(CSOUND * csound,INFILE * p)961 static int32_t infile_act(CSOUND *csound, INFILE *p)
962 {
963     uint32_t offset = p->h.insdshead->ksmps_offset;
964     uint32_t early  = p->h.insdshead->ksmps_no_end;
965     uint32_t i, k, j = offset;
966     uint32_t nsmps = CS_KSMPS, ksmps, nargs = p->nargs;
967     MYFLT *buf = (MYFLT *) p->buf.auxp;
968 
969     ksmps = nsmps;
970     if (UNLIKELY(offset))
971       for (i = 0; i < nargs; i++)
972         memset(p->argums[i], '\0', offset*sizeof(MYFLT));
973     if (UNLIKELY(early)) {
974       nsmps -= early;
975       for (i = 0; i < nargs; i++)
976         memset(&p->argums[i][nsmps], '\0', early*sizeof(MYFLT));
977     }
978     if (p->flag) {
979       if (p->buf_pos >= p->guard_pos) {
980         if (UNLIKELY(p->f.async == 0)) {
981           sf_seek(p->f.sf, p->currpos*p->f.nchnls, SEEK_SET);
982           p->remain = (uint32_t) sf_read_MYFLT(p->f.sf, (MYFLT*) buf,
983                                                p->frames*p->f.nchnls);
984           p->remain /= p->f.nchnls;
985         } else {
986           p->remain = csoundReadAsync(csound,p->f.fd,(MYFLT *)buf,
987                                       p->frames*p->f.nchnls);
988           p->remain /= p->f.nchnls;
989         }
990         p->currpos += p->frames;
991         p->buf_pos = 0;
992       }
993       if (p->remain < nsmps)
994         nsmps = p->remain;
995       for (k = (uint32_t)p->buf_pos; j < nsmps; j++)
996         for (i = 0; i < nargs; i++)
997           p->argums[i][j] = buf[k++] * p->scaleFac;
998       p->buf_pos = k;
999       p->remain -= ksmps;
1000       if (p->remain <= 0 && p->buf_pos < p->guard_pos) {
1001         p->flag = 0;
1002         for (; j < ksmps; j++)
1003           for (i = 0; i < nargs; i++)
1004             p->argums[i][j] = FL(0.0);
1005       }
1006       return OK;
1007     }
1008     for ( ; j < ksmps; j++)
1009       for (i = 0; i < nargs; i++)
1010         p->argums[i][j] = FL(0.0);
1011 
1012     return OK;
1013 }
1014 
infile_arr(CSOUND * csound,INFILEA * p)1015 static int32_t infile_arr(CSOUND *csound, INFILEA *p)
1016 {
1017     uint32_t offset = p->h.insdshead->ksmps_offset;
1018     uint32_t early  = p->h.insdshead->ksmps_no_end;
1019     uint32_t i, k, j = offset;
1020     uint32_t nsmps = CS_KSMPS, ksmps, chn = p->chn;
1021     MYFLT *buf = (MYFLT *) p->buf.auxp;
1022     MYFLT *data = p->tabout->data;
1023 
1024     ksmps = nsmps;
1025     if (UNLIKELY(offset))
1026       for (i = 0; i < chn; i++)
1027         memset(&data[i*chn], '\0', offset*sizeof(MYFLT));
1028     if (UNLIKELY(early)) {
1029       nsmps -= early;
1030       for (i = 0; i < chn; i++)
1031         memset(&data[i*chn+nsmps], '\0', early*sizeof(MYFLT));
1032     }
1033     if (p->flag) {
1034       if (p->buf_pos >= p->guard_pos) {
1035         if (UNLIKELY(p->f.async == 0)) {
1036           sf_seek(p->f.sf, p->currpos*p->f.nchnls, SEEK_SET);
1037           p->remain = (uint32_t) sf_read_MYFLT(p->f.sf, (MYFLT*) buf,
1038                                                p->frames*p->f.nchnls);
1039           p->remain /= p->f.nchnls;
1040         } else {
1041           p->remain = csoundReadAsync(csound,p->f.fd,(MYFLT *)buf,
1042                                       p->frames*p->f.nchnls);
1043           p->remain /= p->f.nchnls;
1044         }
1045         p->currpos += p->frames;
1046         p->buf_pos = 0;
1047       }
1048       if (p->remain < nsmps)
1049         nsmps = p->remain;
1050       for (k = (uint32_t)p->buf_pos; j < nsmps; j++)
1051         for (i = 0; i < chn; i++)
1052           data[i*chn+j] = buf[k++] * p->scaleFac;
1053       p->buf_pos = k;
1054       p->remain -= ksmps;
1055       if (p->remain <= 0 && p->buf_pos < p->guard_pos) {
1056         p->flag = 0;
1057         for (; j < ksmps; j++)
1058           for (i = 0; i < chn; i++)
1059             data[i*chn+j] = FL(0.0);
1060       }
1061       return OK;
1062     }
1063     for ( ; j < ksmps; j++)
1064       for (i = 0; i < chn; i++)
1065         data[i*chn+j] = FL(0.0);
1066 
1067     return OK;
1068 }
1069 
1070 /* ---------------------------- */
1071 
kinfile_set_(CSOUND * csound,KINFILE * p,int32_t istring)1072 static int32_t kinfile_set_(CSOUND *csound, KINFILE *p, int32_t istring)
1073 {
1074     SF_INFO sfinfo;
1075     int32_t     n, buf_reqd;
1076 
1077     memset(&sfinfo, 0, sizeof(SF_INFO));
1078     sfinfo.samplerate = (int32_t) MYFLT2LRND(CS_EKR);
1079     if ((int32_t) MYFLT2LRND(*p->iflag) == -2)
1080       sfinfo.format = FORMAT2SF(AE_FLOAT) | TYPE2SF(TYP_RAW);
1081     else if ((int32_t) MYFLT2LRND(*p->iflag) == -1)
1082       sfinfo.format = FORMAT2SF(AE_SHORT) | TYPE2SF(TYP_RAW);
1083     else
1084       sfinfo.format = 0;
1085     sfinfo.channels = p->INOCOUNT - 3;
1086 
1087     p->nargs = p->INOCOUNT - 3;
1088     p->currpos = MYFLT2LRND(*p->iskpfrms);
1089     p->flag = 1;
1090 
1091     if (CS_KSMPS >= 512)
1092       p->frames = CS_KSMPS;
1093     else
1094       p->frames = (int32_t)(512 / CS_KSMPS) * CS_KSMPS;
1095 
1096     if (CS_KSMPS >= 512)
1097       buf_reqd = CS_KSMPS *   sfinfo.channels;
1098     else
1099       buf_reqd = (1 + (int32_t)(512 / CS_KSMPS)) * CS_KSMPS * p->nargs;
1100     if (p->buf.auxp == NULL || p->buf.size < buf_reqd*sizeof(MYFLT)) {
1101       csound->AuxAlloc(csound, sizeof(MYFLT)*buf_reqd, &p->buf);
1102     }
1103     p->f.bufsize =  p->buf.size;
1104     n = fout_open_file(csound, &(p->f), NULL, CSFILE_SND_R,
1105                        p->fname, istring, &sfinfo, 0);
1106     if (UNLIKELY(n < 0))
1107       return NOTOK;
1108 
1109     if (((STDOPCOD_GLOBALS*) csound->stdOp_Env)->file_opened[n].do_scale)
1110       p->scaleFac = csound->e0dbfs;
1111     else
1112       p->scaleFac = FL(1.0);
1113 
1114     p->guard_pos = p->frames * p->nargs;
1115     p->buf_pos = p->guard_pos;
1116 
1117     if (p->f.async == 1)
1118     csound->FSeekAsync(csound,p->f.fd, p->currpos*p->f.nchnls, SEEK_SET);
1119 
1120     return OK;
1121 }
1122 
kinfile_set(CSOUND * csound,KINFILE * p)1123 static int32_t kinfile_set(CSOUND *csound, KINFILE *p){
1124     return kinfile_set_(csound,p,0);
1125 }
1126 
kinfile_set_S(CSOUND * csound,KINFILE * p)1127 static int32_t kinfile_set_S(CSOUND *csound, KINFILE *p){
1128     return kinfile_set_(csound,p,1);
1129 }
1130 
1131 
kinfile(CSOUND * csound,KINFILE * p)1132 static int32_t kinfile(CSOUND *csound, KINFILE *p)
1133 {
1134     int32_t   i, k;
1135     int32_t nargs = p->nargs;
1136     MYFLT *buf = (MYFLT *) p->buf.auxp;
1137 
1138     if (p->flag) {
1139       if (p->buf_pos >= p->guard_pos) {
1140         if (UNLIKELY(p->f.async == 0)) {
1141           sf_seek(p->f.sf, p->currpos*p->f.nchnls, SEEK_SET);
1142           p->remain = (uint32_t) sf_read_MYFLT(p->f.sf, (MYFLT*) buf,
1143                                                p->frames*p->f.nchnls);
1144           p->remain /= p->f.nchnls;
1145         } else {
1146           p->remain = csoundReadAsync(csound,p->f.fd,(MYFLT *)buf,
1147                                       p->frames*p->f.nchnls);
1148           p->remain /= p->f.nchnls;
1149         }
1150         p->currpos += p->frames;
1151         p->buf_pos = 0;
1152       }
1153       if (p->remain > 0) {
1154         for (i = 0, k = p->buf_pos; i < nargs; i++)
1155           p->argums[i][0] = buf[k++] * p->scaleFac;
1156         p->buf_pos = k;
1157         p->remain--;
1158         return OK;
1159       }
1160       p->flag = 0;
1161     }
1162     for (i = 0; i < nargs; i++)
1163       p->argums[i][0] = FL(0.0);
1164     return OK;
1165 }
1166 
i_infile_(CSOUND * csound,I_INFILE * p,int32_t istring)1167 static int32_t i_infile_(CSOUND *csound, I_INFILE *p, int32_t istring)
1168 {
1169     int32_t     j, n, nargs;
1170     FILE    *fp = NULL;
1171     MYFLT   **args = p->argums;
1172     char    *omodes[] = {"r", "r", "rb"};
1173     int32_t     idx = (int32_t) MYFLT2LRND(*p->iflag);
1174 
1175     if (UNLIKELY(idx < 0 || idx > 2))
1176       idx = 0;
1177     n = fout_open_file(csound, (FOUT_FILE*) NULL, &fp, CSFILE_STD,
1178                        p->fname, istring, omodes[idx], 0);
1179     if (UNLIKELY(n < 0))
1180       return NOTOK;
1181 
1182     nargs = p->INOCOUNT - 3;
1183     switch ((int32_t) MYFLT2LRND(*p->iflag)) {
1184     case 0: /* ascii file with loop */
1185       {
1186         char  cf[64], *cfp;
1187         int32_t   cc;
1188       newcycle:
1189         for (j = 0; j < nargs; j++) {
1190           cfp = cf;
1191           while ((*cfp = cc = getc(fp)) == 'i' || isspace(*cfp));
1192           if (cc == EOF) {
1193             fseek(fp, 0, SEEK_SET);
1194             goto newcycle;
1195           }
1196           while (isdigit(*cfp) || *cfp == '.' || *cfp == '+' || *cfp == '-') {
1197             *(++cfp) = (char)(cc = getc(fp));
1198           }
1199           *++cfp = '\0';        /* Must terminate string */
1200           *(args[j]) = (MYFLT) atof(cf);
1201           if (cc == EOF) {
1202             fseek(fp, 0, SEEK_SET);
1203             break;
1204           }
1205         }
1206       }
1207       break;
1208     case 1: /* ascii file without loop */
1209       {
1210         char  cf[64], *cfp;
1211         int32_t   cc;
1212         for (j = 0; j < nargs; j++) {
1213           cfp = cf;
1214           while ((*cfp = cc = getc(fp)) == 'i' || isspace(*cfp));
1215           if (cc == EOF) {
1216             *(args[j]) = FL(0.0);
1217             break;
1218           }
1219           while (isdigit(*cfp) || *cfp == '.' || *cfp == '+' || *cfp == '-') {
1220             *(++cfp) = cc = getc(fp);
1221           }
1222           *++cfp = '\0';        /* Must terminate */
1223           *(args[j]) = (MYFLT) atof (cf);
1224           if (cc == EOF) {
1225             *(args[j]) = FL(0.0);
1226             break;
1227           }
1228         }
1229       }
1230       break;
1231     case 2: /* binary floats without loop */
1232       if (fseek(fp, p->currpos * sizeof(float) * nargs, SEEK_SET)<0) return NOTOK;
1233       p->currpos++;
1234       for (j = 0; j < nargs; j++) {
1235         if (1 == fread(args[j], sizeof(float), 1, fp));
1236         else {
1237           p->flag = 0;
1238           *(args[j]) = FL(0.0);
1239         }
1240       }
1241       break;
1242     }
1243     return OK;
1244 }
1245 
i_infile(CSOUND * csound,I_INFILE * p)1246 static int32_t i_infile(CSOUND *csound, I_INFILE *p){
1247     return i_infile_(csound,p,0);
1248 }
1249 
i_infile_S(CSOUND * csound,I_INFILE * p)1250 static int32_t i_infile_S(CSOUND *csound, I_INFILE *p){
1251     return i_infile_(csound,p,1);
1252 }
1253 
1254 
1255 /*---------------------------*/
1256 
incr(CSOUND * csound,INCR * p)1257 static int32_t incr(CSOUND *csound, INCR *p)
1258 {
1259      IGN(csound);
1260     MYFLT *avar = p->avar, *aincr = p->aincr;
1261     uint32_t offset = p->h.insdshead->ksmps_offset;
1262     uint32_t early  = p->h.insdshead->ksmps_no_end;
1263     uint32_t n, nsmps = CS_KSMPS;
1264 
1265     if (UNLIKELY(early)) nsmps -= early;
1266     for (n = offset; n < nsmps; n++)
1267       avar[n] += aincr[n];
1268     return OK;
1269 }
1270 
clear(CSOUND * csound,CLEARS * p)1271 static int32_t clear(CSOUND *csound, CLEARS *p)
1272 {
1273      IGN(csound);
1274     uint32_t   nsmps = CS_KSMPS, j;
1275 
1276     for (j = 0; j < p->INOCOUNT; j++) {
1277       memset(p->argums[j], 0, sizeof(MYFLT)*nsmps);
1278     }
1279     return OK;
1280 }
1281 
1282 /*---------------------------------*/
1283 /* formatted output to a text file */
1284 
fprintf_set_(CSOUND * csound,FPRINTF * p,int32_t istring)1285 static int32_t fprintf_set_(CSOUND *csound, FPRINTF *p, int32_t istring)
1286 {
1287     int32_t     n;
1288     char    *sarg = (char*) p->fmt->data;
1289     char    *sdest = p->txtstring;
1290 
1291     memset(p->txtstring, 0, 8192); /* Nasty to have exposed constant in code */
1292 
1293     if (p->h.opadr != (SUBR) NULL)      /* fprintks */
1294       n = fout_open_file(csound, &(p->f), NULL, CSFILE_STD,
1295                          p->fname, istring, "w", 1);
1296     else                                /* fprints */
1297       n = fout_open_file(csound, (FOUT_FILE*) NULL, &(p->f.f), CSFILE_STD,
1298                          p->fname, istring, "w", 1);
1299     if (UNLIKELY(n < 0))
1300       return NOTOK;
1301     //setvbuf(p->f.f, (char*)NULL, _IOLBF, BUFSIZ); /* Seems a good option */
1302     /* Copy the string to the storage place in PRINTKS.
1303      *
1304      * We will look out for certain special codes and write special
1305      * bytes directly to the string.
1306      *
1307      * There is probably a more elegant way of doing this, then using
1308      * the look flag.  I could use goto - but I would rather not.      */
1309     /* This is really a if then else if...
1310      * construct and is currently grotty -- JPff */
1311     do {
1312       char temp  = *sarg++;
1313       char tempn = *sarg--;
1314       /* Look for a single caret and insert an escape char.  */
1315       if ((temp  == '^') && (tempn != '^')) {
1316         *sdest++ = 0x1B; /* ESC */
1317       }
1318       /* Look for a double caret and insert a single caret
1319          - stepping forward one */
1320       else if ((temp  == '^') && (tempn == '^')) {
1321         *sdest++ = '^';
1322         sarg++;
1323       }
1324       /* Look for a single tilde and insert an escape followed by a '['.
1325        * ESC[ is the escape sequence for ANSI consoles */
1326       else if ((temp  == '~') && (tempn != '~')) {
1327         *sdest++ = 0x1B; /* ESC */
1328         *sdest++ = '[';
1329       }
1330       /* Look for a double tilde and insert a tilde caret
1331          - stepping forward one. */
1332       else if ((temp  == '~') && (tempn == '~')) {
1333         *sdest++ = '~';
1334         sarg++;
1335       }
1336       /* Look for \n, \N etc */
1337       else if (temp == '\\') {
1338         switch (tempn) {
1339         case 'r': case 'R':
1340           *sdest++ = '\r';
1341           sarg++;
1342           break;
1343         case 'n': case 'N':
1344           *sdest++ = '\n';
1345           sarg++;
1346           break;
1347         case 't': case 'T':
1348           *sdest++ = '\t';
1349           sarg++;
1350           break;
1351         case 'a': case 'A':
1352           *sdest++ = '\a';
1353           sarg++;
1354           break;
1355         case 'b': case 'B':
1356           *sdest++ = '\b';
1357           sarg++;
1358           break;
1359         case '\\':
1360           *sdest++ = '\\';
1361           sarg++;
1362           break;
1363         default:
1364           *sdest++ = tempn;
1365           sarg++;
1366           break;
1367         }
1368       }
1369       else if (temp == '%') {
1370         /* an extra option to specify tab and return as %t and %r */
1371         switch (tempn) {
1372         case 'r': case 'R':
1373           *sdest++ = '\r';
1374           sarg++;
1375           break;
1376         case 'n': case 'N':
1377           *sdest++ = '\n';
1378           sarg++;
1379           break;
1380         case 't': case 'T':
1381           *sdest++ = '\t';
1382           sarg++;
1383           break;
1384         case '!':       /* and a ';' */
1385           *sdest++ = ';';
1386           sarg++;
1387           break;
1388         default:
1389           *sdest++ = temp;
1390           break;
1391         }
1392       }
1393       else {
1394         /* If none of these match, then copy the character directly
1395          * and try again.      */
1396         *sdest++ = temp;
1397       }
1398       /* Increment pointer and process next character until end of string.  */
1399     } while (*++sarg != 0);
1400     return OK;
1401 }
1402 
fprintf_set(CSOUND * csound,FPRINTF * p)1403 static int32_t fprintf_set(CSOUND *csound, FPRINTF *p){
1404     return fprintf_set_(csound,p,0);
1405 }
1406 
fprintf_set_S(CSOUND * csound,FPRINTF * p)1407 static int32_t fprintf_set_S(CSOUND *csound, FPRINTF *p){
1408     return fprintf_set_(csound,p,1);
1409 }
1410 
1411 
1412 
1413 /* perform a sprintf-style format -- matt ingalls */
sprints1(char * outstring,char * fmt,MYFLT ** kvals,int32 numVals)1414 void sprints1(char *outstring,  char *fmt, MYFLT **kvals, int32 numVals)
1415 {
1416     char strseg[8192];
1417     int32_t len = 8192;
1418     int32_t i = 0, j = 0;
1419     char *segwaiting = 0;
1420     while (*fmt) {
1421       if (*fmt == '%') {
1422         /* if already a segment waiting, then lets print it */
1423         if (segwaiting) {
1424           strseg[i] = '\0';
1425           switch (*segwaiting) {
1426           case '%':
1427             strNcpy(outstring, "%%", len);
1428             j--;
1429             break;
1430           case 'd':
1431           case 'i':
1432           case 'o':
1433           case 'x':
1434           case 'X':
1435           case 'u':
1436           case 'c':
1437             snprintf(outstring, len, strseg, (int32_t) MYFLT2LRND(*kvals[j]));
1438             break;
1439           case 'h':
1440             snprintf(outstring, len, strseg, (int16) MYFLT2LRND(*kvals[j]));
1441             break;
1442           case 'l':
1443             snprintf(outstring, len, strseg, (int32) MYFLT2LRND(*kvals[j]));
1444             break;
1445           case 's':
1446             snprintf(outstring, len, strseg, ((STRINGDAT*)(kvals[j]))->data);
1447             break;
1448           default:
1449             snprintf(outstring, len, strseg, *kvals[j]);
1450             break;
1451           }
1452           len -= strlen(outstring);
1453           outstring += strlen(outstring);
1454           i = 0;
1455           segwaiting = 0;
1456 
1457           /* prevent potential problems */
1458           /* if user didnt give enough input params */
1459           if (j < numVals-1)
1460             j++;
1461         }
1462         /* copy the '%' */
1463         strseg[i++] = *fmt++;
1464 
1465         /* find the format code */
1466         segwaiting = fmt;
1467         while (*segwaiting && !isalpha(*segwaiting) && !(*segwaiting=='%'))
1468           segwaiting++;
1469       }
1470       else
1471         strseg[i++] = *fmt++;
1472     }
1473 
1474     if (i) {
1475       strseg[i] = '\0';
1476       if (segwaiting) {
1477         switch (*segwaiting) {
1478           case '%':
1479             strNcpy(outstring, "%%", len);
1480             j--;
1481             break;
1482         case 'd':
1483         case 'i':
1484         case 'o':
1485         case 'x':
1486         case 'X':
1487         case 'u':
1488         case 'c':
1489           snprintf(outstring, len, strseg, (int32_t) MYFLT2LRND(*kvals[j]));
1490           break;
1491         case 'h':
1492           snprintf(outstring, len, strseg, (int16) MYFLT2LRND(*kvals[j]));
1493           break;
1494         case 'l':
1495           snprintf(outstring, len, strseg, (int64_t) MYFLT2LRND(*kvals[j]));
1496           break;
1497 
1498         default:
1499           snprintf(outstring, len, strseg, *kvals[j]);
1500           break;
1501         }
1502       }
1503       else
1504         snprintf(outstring, len, "%s", strseg);
1505     }
1506 
1507 }
1508 
fprintf_k(CSOUND * csound,FPRINTF * p)1509 static int32_t fprintf_k(CSOUND *csound, FPRINTF *p)
1510 {
1511     char    string[8192];
1512 
1513     (void) csound;
1514     sprints1(string, p->txtstring, p->argums, p->INOCOUNT - 2);
1515     fprintf(p->f.f, "%s", string);
1516     fflush(p->f.f);
1517     return OK;
1518 }
1519 
1520 /* i-rate fprints */
fprintf_i(CSOUND * csound,FPRINTF * p)1521 static int32_t fprintf_i(CSOUND *csound, FPRINTF *p)
1522 {
1523     char    string[8192];
1524 
1525     if (UNLIKELY(fprintf_set(csound, p) != OK))
1526       return NOTOK;
1527     sprints1(string, p->txtstring, p->argums, p->INOCOUNT - 2);
1528     fprintf(p->f.f,"%s", string);
1529     fflush(p->f.f);
1530     return OK;
1531 }
1532 
fprintf_i_S(CSOUND * csound,FPRINTF * p)1533 static int32_t fprintf_i_S(CSOUND *csound, FPRINTF *p)
1534 {
1535     char    string[8192];
1536 
1537     if (UNLIKELY(fprintf_set_S(csound, p) != OK))
1538       return NOTOK;
1539     sprints1(string, p->txtstring, p->argums, p->INOCOUNT - 2);
1540     fprintf(p->f.f, "%s", string);
1541     fflush(p->f.f);
1542     return OK;
1543 }
1544 
1545 #define S(x)    sizeof(x)
1546 static OENTRY localops[] = {
1547 
1548     {"fprints",    S(FPRINTF),      0, 1,  "",     "SSN",
1549         (SUBR) fprintf_i_S, (SUBR) NULL,(SUBR) NULL, NULL, },
1550     {"fprints.i",    S(FPRINTF),      0, 1,  "",     "iSN",
1551         (SUBR) fprintf_i, (SUBR) NULL,(SUBR) NULL, NULL},
1552     { "fprintks",   S(FPRINTF),    WR, 3,  "",     "SSN",
1553         (SUBR) fprintf_set_S,     (SUBR) fprintf_k,   (SUBR) NULL, NULL,},
1554     { "fprintks.i",   S(FPRINTF),    WR, 3,  "",     "iSN",
1555         (SUBR) fprintf_set,     (SUBR) fprintf_k,   (SUBR) NULL, NULL},
1556      { "vincr",      S(INCR),       WI, 2,  "",     "aa",
1557         (SUBR) NULL,            (SUBR) incr, NULL         },
1558     { "clear",      S(CLEARS),      WI, 2,  "",     "y",
1559         (SUBR) NULL,            (SUBR) clear, NULL},
1560     { "fout",       S(OUTFILE),     0, 3,  "",     "Siy",
1561         (SUBR) outfile_set_S,     (SUBR) outfile, NULL},
1562     { "fout.A",     S(OUTFILEA),    0, 3,  "",     "Sia[]",
1563         (SUBR) outfile_set_A,     (SUBR) outfile_array, NULL},
1564     /* { "fout.i",       S(OUTFILE),     0, 3,  "",     "iiy", */
1565     /*     (SUBR) outfile_set,     (SUBR) outfile, NULL}, */
1566     { "foutk",      S(KOUTFILE),    0, 3,  "",     "Siz",
1567         (SUBR) koutfile_set_S,    (SUBR) koutfile,    (SUBR) NULL, NULL },
1568     { "foutk.i",      S(KOUTFILE),    0, 3,  "",     "iiz",
1569         (SUBR) koutfile_set,    (SUBR) koutfile,    (SUBR) NULL, NULL },
1570     { "fouti",      S(IOUTFILE),    0, 1,  "",     "iiim",
1571         (SUBR) ioutfile_set,    (SUBR) NULL,        (SUBR) NULL, NULL         },
1572     { "foutir",     S(IOUTFILE_R),  0, 3,  "",     "iiim",
1573         (SUBR) ioutfile_set_r,  (SUBR) ioutfile_r,  (SUBR) NULL, NULL},
1574     { "fiopen",     S(FIOPEN),      0, 1,  "i",    "Si",
1575         (SUBR) fiopen_S,          (SUBR) NULL,        (SUBR) NULL, NULL},
1576     { "fiopen.i",     S(FIOPEN),      0, 1,  "i",    "ii",
1577         (SUBR) fiopen,          (SUBR) NULL,        (SUBR) NULL, NULL},
1578     { "ficlose",    S(FICLOSE),     0, 1,  "",     "S",
1579         (SUBR) ficlose_opcode_S,  (SUBR) NULL,        (SUBR) NULL, NULL},
1580     { "ficlose.S",  S(FICLOSE),     0, 1,  "",     "i",
1581         (SUBR) ficlose_opcode,  (SUBR) NULL,        (SUBR) NULL, NULL },
1582     { "fin.a",      S(INFILE),     WI|_QQ, 3,  "",      "Siiy",
1583         (SUBR) infile_set_S,    (SUBR) infile_act, NULL},
1584     { "fin.A",      S(INFILEA),    WI, 3,  "",     "Siia[]",
1585         (SUBR) infile_set_A,    (SUBR) infile_arr, NULL},
1586     { "fin.i",      S(INFILE),     WI|_QQ, 3,  "",     "iiiy",
1587         (SUBR) infile_set,      (SUBR) infile_act, NULL},
1588     { "fink",       S(KINFILE),    WI, 3,  "",     "Siiz",
1589         (SUBR) kinfile_set_S,     (SUBR) kinfile,     (SUBR) NULL, NULL},
1590     { "fink.i",       S(KINFILE),  WI, 3,  "",     "iiiz",
1591         (SUBR) kinfile_set,     (SUBR) kinfile,     (SUBR) NULL, NULL},
1592     { "fini",       S(I_INFILE),   WI, 1,  "",     "Siim",
1593       (SUBR) i_infile_S,        (SUBR) NULL,        (SUBR) NULL, NULL },
1594     { "fini.i",       S(I_INFILE), WI, 1,  "",     "iiim",
1595         (SUBR) i_infile,        (SUBR) NULL,        (SUBR) NULL, NULL}
1596 };
1597 
fout_init_(CSOUND * csound)1598 int32_t fout_init_(CSOUND *csound)
1599 {
1600     return csound->AppendOpcodes(csound, &(localops[0]),
1601                                  (int32_t) (sizeof(localops) / sizeof(OENTRY)));
1602 }
1603