1 /*
2     sndlib.c:
3 
4     Copyright (C) 2004 John ffitch
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"                 /*             SNDLIB.C         */
25 #include "soundio.h"
26 #include <stdlib.h>
27 #include <time.h>
28 #include <inttypes.h>
29 
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33 
34 #ifdef PIPES
35 # if defined(SGI) || defined(LINUX) || defined(__BEOS__) || defined(NeXT) ||  \
36      defined(__MACH__)
37 #  define _popen popen
38 #  define _pclose pclose
39 # endif
40 extern  FILE *  _popen(const char *, const char *);
41 extern  int     _pclose(FILE *);
42 #endif
43 
44 static  void    sndwrterr(CSOUND *, int, int);
45 static  void    sndfilein_noscale(CSOUND *csound);
46 
47 #define STA(x)   (csound->libsndStatics.x)
48 
alloc_globals(CSOUND * csound)49 static inline void alloc_globals(CSOUND *csound)
50 {
51     csound->libsndStatics.nframes = (uint32)1;
52 }
53 
54 /* The interface requires 2 functions:
55    spoutran to transfer nspout items to buffer
56    audtran to actually write the data
57 
58    spoutran is called with nchnls*ksamps items and this need to be
59    buffered until outbufsiz items have been accumulated.  It will call
60    audtran to flush when this happens.
61 */
62 
spoutsf(CSOUND * csound)63 static void spoutsf(CSOUND *csound)
64 {
65     uint32_t   chn = 0;
66     int     n;
67     int spoutrem = csound->nspout;
68     MYFLT   *sp = csound->spout;
69     MYFLT   absamp = FL(0.0);
70     uint32  nframes = csound->libsndStatics.nframes;
71  nchk:
72     /* if nspout remaining > buf rem, prepare to send in parts */
73     if ((n = spoutrem) > (int) csound->libsndStatics.outbufrem) {
74       n = (int) csound->libsndStatics.outbufrem;
75     }
76     spoutrem -= n;
77     csound->libsndStatics.outbufrem -= n;
78     do {
79       absamp = *sp++;
80       if (csound->libsndStatics.osfopen) {
81         *csound->libsndStatics.outbufp++ = (absamp * csound->dbfs_to_float);
82       }
83       if (absamp < FL(0.0)) {
84         absamp = -absamp;
85       }
86       if (absamp > csound->maxamp[chn]) {   /*  maxamp this seg  */
87         csound->maxamp[chn] = absamp;
88         csound->maxpos[chn] = nframes;
89       }
90       if (absamp > csound->e0dbfs) {        /* out of range?     */
91         csound->rngcnt[chn]++;              /*  report it        */
92         csound->rngflg = 1;
93       }
94       if (csound->multichan) {
95         if (++chn >= csound->nchnls) {
96             chn = 0;
97             nframes++;
98         }
99       } else {
100         nframes++;
101       }
102     } while (--n);
103     if (!csound->libsndStatics.outbufrem) {
104       if (csound->libsndStatics.osfopen) {
105         csound->nrecs++;
106         csound->audtran(csound, csound->libsndStatics.outbuf,
107                         csound->libsndStatics.outbufsiz); /* Flush buffer */
108         csound->libsndStatics.outbufp = (MYFLT*) csound->libsndStatics.outbuf;
109       }
110       csound->libsndStatics.outbufrem = csound->oparms_.outbufsamps;
111       if (spoutrem) {
112         goto nchk;
113       }
114     }
115     csound->libsndStatics.nframes = nframes;
116 }
117 
118 /* special version of spoutsf for "raw" floating point files */
119 
spoutsf_noscale(CSOUND * csound)120 static void spoutsf_noscale(CSOUND *csound)
121 {
122     uint32_t chn = 0;
123     int      n, spoutrem = csound->nspout;
124     MYFLT    *sp = csound->spout;
125     MYFLT    absamp = FL(0.0);
126     uint32   nframes = csound->libsndStatics.nframes;
127 
128  nchk:
129     /* if nspout remaining > buf rem, prepare to send in parts */
130     if ((n = spoutrem) > (int) csound->libsndStatics.outbufrem)
131       n = (int)csound->libsndStatics.outbufrem;
132     spoutrem -= n;
133     csound->libsndStatics.outbufrem -= n;
134     do {
135       absamp = *sp++;
136       if (csound->libsndStatics.osfopen)
137         *csound->libsndStatics.outbufp++ = absamp;
138       if (absamp < FL(0.0))
139         absamp = -absamp;
140       if (absamp > csound->maxamp[chn]) {   /*  maxamp this seg  */
141         csound->maxamp[chn] = absamp;
142         csound->maxpos[chn] = nframes;
143       }
144       if (++chn >= csound->nchnls)
145         chn = 0, nframes++;
146     } while (--n);
147 
148     if (!csound->libsndStatics.outbufrem) {
149       if (csound->libsndStatics.osfopen) {
150         csound->nrecs++;
151         csound->audtran(csound, csound->libsndStatics.outbuf,
152                         csound->libsndStatics.outbufsiz); /* Flush buffer */
153         csound->libsndStatics.outbufp = (MYFLT*) csound->libsndStatics.outbuf;
154       }
155       csound->libsndStatics.outbufrem = csound->oparms_.outbufsamps;
156       if (spoutrem) goto nchk;
157     }
158     csound->libsndStatics.nframes = nframes;
159 }
160 
161 /* diskfile write option for audtran's */
162 /*      assigned during sfopenout()    */
163 
writesf(CSOUND * csound,const MYFLT * outbuf,int nbytes)164 static void writesf(CSOUND *csound, const MYFLT *outbuf, int nbytes)
165 {
166     OPARMS  *O = csound->oparms;
167     int     n;
168 
169     if (UNLIKELY(STA(outfile) == NULL))
170       return;
171     n = (int) sf_write_MYFLT(STA(outfile), (MYFLT*) outbuf,
172                              nbytes / sizeof(MYFLT)) * (int) sizeof(MYFLT);
173     if (UNLIKELY(n < nbytes))
174       sndwrterr(csound, n, nbytes);
175     if (UNLIKELY(O->rewrt_hdr))
176       rewriteheader((void *)STA(outfile));
177     switch (O->heartbeat) {
178       case 1:
179         csound->MessageS(csound, CSOUNDMSG_REALTIME,
180                                  "%c\010", "|/-\\"[csound->nrecs & 3]);
181         break;
182       case 2:
183         csound->MessageS(csound, CSOUNDMSG_REALTIME, ".");
184         break;
185       case 3:
186         {
187           char    s[512];
188           CS_SPRINTF(s, "%ld(%.3f)%n", (long) csound->nrecs,
189                   csound->icurTime/csound->esr, &n);
190           if (n > 0) {
191             memset(&(s[n]), '\b', n);
192             s[n + n] = '\0';
193             csound->MessageS(csound, CSOUNDMSG_REALTIME, "%s",  s);
194           }
195         }
196         break;
197       case 4:
198         csound->MessageS(csound, CSOUNDMSG_REALTIME, "%s", "\a");
199         break;
200     }
201 }
202 
writesf_dither_16(CSOUND * csound,const MYFLT * outbuf,int nbytes)203 static void writesf_dither_16(CSOUND *csound, const MYFLT *outbuf, int nbytes)
204 {
205     OPARMS  *O = csound->oparms;
206     int     n;
207     int m = nbytes / sizeof(MYFLT);
208     MYFLT *buf = (MYFLT*) outbuf;
209     int    dith;
210 
211     if (UNLIKELY(STA(outfile) == NULL))
212       return;
213     dith = STA(dither);
214     for (n=0; n<m; n++) {
215       int   tmp = ((dith * 15625) + 1) & 0xFFFF;
216       int   rnd = ((tmp * 15625) + 1) & 0xFFFF;
217       MYFLT result;
218       dith = rnd;
219       rnd = (rnd+tmp)>>1;           /* triangular distribution */
220       result = (MYFLT) (rnd - 0x8000)  / ((MYFLT) 0x10000);
221       result /= ((MYFLT) 0x7fff);
222       buf[n] += result;
223     }
224     STA(dither) = dith;
225     n = (int) sf_write_MYFLT(STA(outfile), (MYFLT*) outbuf,
226                              nbytes / sizeof(MYFLT)) * (int) sizeof(MYFLT);
227     if (UNLIKELY(n < nbytes))
228       sndwrterr(csound, n, nbytes);
229     if (UNLIKELY(O->rewrt_hdr))
230       rewriteheader(STA(outfile));
231     switch (O->heartbeat) {
232       case 1:
233         csound->MessageS(csound, CSOUNDMSG_REALTIME,
234                                  "%c\010", "|/-\\"[csound->nrecs & 3]);
235         break;
236       case 2:
237         csound->MessageS(csound, CSOUNDMSG_REALTIME, ".");
238         break;
239       case 3:
240         {
241           char    s[512];
242           CS_SPRINTF(s, "%ld(%.3f)%n", (long) csound->nrecs,
243                   csound->icurTime/csound->esr, &n);
244           if (n > 0) {
245             memset(&(s[n]), '\b', n);
246             s[n + n] = '\0';
247             csound->MessageS(csound, CSOUNDMSG_REALTIME, "%s", s);
248           }
249         }
250         break;
251       case 4:
252         csound->MessageS(csound, CSOUNDMSG_REALTIME, "\a");
253         break;
254     }
255 }
256 
writesf_dither_8(CSOUND * csound,const MYFLT * outbuf,int nbytes)257 static void writesf_dither_8(CSOUND *csound, const MYFLT *outbuf, int nbytes)
258 {
259     OPARMS  *O = csound->oparms;
260     int     n;
261     int m = nbytes / sizeof(MYFLT);
262     MYFLT *buf = (MYFLT*) outbuf;
263     int dith;
264 
265     if (UNLIKELY(STA(outfile) == NULL))
266       return;
267     dith = STA(dither);
268     for (n=0; n<m; n++) {
269       int   tmp = ((dith * 15625) + 1) & 0xFFFF;
270       int   rnd = ((tmp * 15625) + 1) & 0xFFFF;
271       MYFLT result;
272       dith = rnd;
273       rnd = (rnd+tmp)>>1;           /* triangular distribution */
274       result = (MYFLT) (rnd - 0x8000)  / ((MYFLT) 0x10000);
275       result /= ((MYFLT) 0x7f);
276       buf[n] += result;
277     }
278     STA(dither) = dith;
279     n = (int) sf_write_MYFLT(STA(outfile), (MYFLT*) outbuf,
280                              nbytes / sizeof(MYFLT)) * (int) sizeof(MYFLT);
281     if (UNLIKELY(n < nbytes))
282       sndwrterr(csound, n, nbytes);
283     if (UNLIKELY(O->rewrt_hdr))
284       rewriteheader(STA(outfile));
285     switch (O->heartbeat) {
286       case 1:
287         csound->MessageS(csound, CSOUNDMSG_REALTIME,
288                                  "%c\010", "|/-\\"[csound->nrecs & 3]);
289         break;
290       case 2:
291         csound->MessageS(csound, CSOUNDMSG_REALTIME, ".");
292         break;
293       case 3:
294         {
295           char    s[512];
296           CS_SPRINTF(s, "%ld(%.3f)%n", (long) csound->nrecs,
297                   csound->icurTime/csound->esr, &n);
298           if (n > 0) {
299             memset(&(s[n]), '\b', n);
300             s[n + n] = '\0';
301             csound->MessageS(csound, CSOUNDMSG_REALTIME, "%s", s);
302           }
303         }
304         break;
305       case 4:
306         csound->MessageS(csound, CSOUNDMSG_REALTIME, "\a");
307         break;
308     }
309 }
310 
writesf_dither_u16(CSOUND * csound,const MYFLT * outbuf,int nbytes)311 static void writesf_dither_u16(CSOUND *csound, const MYFLT *outbuf, int nbytes)
312 {
313     OPARMS  *O = csound->oparms;
314     int     n;
315     int m = nbytes / sizeof(MYFLT);
316     MYFLT *buf = (MYFLT*) outbuf;
317     int dith;
318 
319     if (UNLIKELY(STA(outfile) == NULL))
320       return;
321     dith = STA(dither);
322     for (n=0; n<m; n++) {
323       int   rnd = ((dith * 15625) + 1) & 0xFFFF;
324       MYFLT result;
325       dith =  rnd;
326       result = (MYFLT) (rnd - 0x8000)  / ((MYFLT) 0x10000);
327       result /= ((MYFLT) 0x7fff);
328       buf[n] += result;
329     }
330     STA(dither) = dith;
331     n = (int) sf_write_MYFLT(STA(outfile), (MYFLT*) outbuf,
332                              nbytes / sizeof(MYFLT)) * (int) sizeof(MYFLT);
333     if (UNLIKELY(n < nbytes))
334       sndwrterr(csound, n, nbytes);
335     if (UNLIKELY(O->rewrt_hdr))
336       rewriteheader(STA(outfile));
337     switch (O->heartbeat) {
338       case 1:
339         csound->MessageS(csound, CSOUNDMSG_REALTIME,
340                                  "%c\010", "|/-\\"[csound->nrecs & 3]);
341         break;
342       case 2:
343         csound->MessageS(csound, CSOUNDMSG_REALTIME, ".");
344         break;
345       case 3:
346         {
347           char    s[512];
348           CS_SPRINTF(s, "%ld(%.3f)%n", (long) csound->nrecs,
349                   csound->icurTime/csound->esr, &n);
350           if (n > 0) {
351             memset(&(s[n]), '\b', n);
352             s[n + n] = '\0';
353             csound->MessageS(csound, CSOUNDMSG_REALTIME, "%s",  s);
354           }
355         }
356         break;
357       case 4:
358         csound->MessageS(csound, CSOUNDMSG_REALTIME, "%s",  "\a");
359         break;
360     }
361 }
362 
writesf_dither_u8(CSOUND * csound,const MYFLT * outbuf,int nbytes)363 static void writesf_dither_u8(CSOUND *csound, const MYFLT *outbuf, int nbytes)
364 {
365     OPARMS  *O = csound->oparms;
366     int     n;
367     int m = nbytes / sizeof(MYFLT);
368     MYFLT *buf = (MYFLT*) outbuf;
369     int dith;
370 
371     if (UNLIKELY(STA(outfile) == NULL))
372       return;
373     dith = STA(dither);
374     for (n=0; n<m; n++) {
375       int   rnd = ((dith * 15625) + 1) & 0xFFFF;
376       MYFLT result;
377       STA(dither) = rnd;
378       result = (MYFLT) (rnd - 0x8000)  / ((MYFLT) 0x10000);
379       result /= ((MYFLT) 0x7f);
380       buf[n] += result;
381     }
382     STA(dither) = dith;
383     n = (int) sf_write_MYFLT(STA(outfile), (MYFLT*) outbuf,
384                              nbytes / sizeof(MYFLT)) * (int) sizeof(MYFLT);
385     if (UNLIKELY(n < nbytes))
386       sndwrterr(csound, n, nbytes);
387     if (UNLIKELY(O->rewrt_hdr))
388       rewriteheader(STA(outfile));
389     switch (O->heartbeat) {
390       case 1:
391         csound->MessageS(csound, CSOUNDMSG_REALTIME,
392                                  "%c\010", "|/-\\"[csound->nrecs & 3]);
393         break;
394       case 2:
395         csound->MessageS(csound, CSOUNDMSG_REALTIME, ".");
396         break;
397       case 3:
398         {
399           char    s[512];
400           CS_SPRINTF(s, "%ld(%.3f)%n", (long) csound->nrecs,
401                   csound->icurTime/csound->esr, &n);
402           if (n > 0) {
403             memset(&(s[n]), '\b', n);
404             s[n + n] = '\0';
405             csound->MessageS(csound, CSOUNDMSG_REALTIME, "%s", s);
406           }
407         }
408         break;
409       case 4:
410         csound->MessageS(csound, CSOUNDMSG_REALTIME, "\a");
411         break;
412     }
413 }
414 
readsf(CSOUND * csound,MYFLT * inbuf,int inbufsize)415 static int readsf(CSOUND *csound, MYFLT *inbuf, int inbufsize)
416 {
417     int i, n;
418 
419     (void) csound;
420     n = inbufsize / (int) sizeof(MYFLT);
421     i = (int) sf_read_MYFLT(STA(infile), inbuf, n);
422     if (UNLIKELY(i < 0))
423       return inbufsize;
424     memset(&inbuf[i], 0, (n-i)*sizeof(MYFLT));
425     return inbufsize;
426 }
427 
428 /* Checks if the specified file name is a real-time audio device. */
429 /* Returns the device number (defaults to 1024) if it is, and -1 otherwise. */
430 /* If a device name is specified, and 'devName' is not NULL, a pointer to it */
431 /* is stored in *devName. */
432 /* Called from musmon, str_ops and here */
433 
check_rtaudio_name(char * fName,char ** devName,int isOutput)434 int check_rtaudio_name(char *fName, char **devName, int isOutput)
435 {
436     char  *s;
437 
438     if (devName != NULL)
439       *devName = (char*) NULL;
440     if (fName == NULL)
441       return -1;
442     s = fName;
443     if ((isOutput && strncmp(fName, "dac", 3) == 0) ||
444         (!isOutput && strncmp(fName, "adc", 3) == 0))
445       s += 3;
446     else if (strncmp(fName, "devaudio", 8) == 0)
447       s += 8;
448     else
449       return -1;
450     if (*s == (char) '\0')
451       return 1024;
452     if (*s == (char) ':') {
453       if (devName != NULL) {
454        *devName = &(s[1]);
455       }
456       return 1024;
457     }
458     else {
459       int devNum = 0;
460       while (*s >= (char) '0' && *s <= (char) '9') {
461         devNum = devNum * 10 + ((int) *s - (int) '0');
462         if (devNum >= 1024)
463           break;
464         if (*(++s) == (char) '\0')
465           return devNum;
466       }
467     }
468     return -1;
469 }
470 
sfopenin(CSOUND * csound)471 void sfopenin(CSOUND *csound)           /* init for continuous soundin */
472 {
473     OPARMS  *O = csound->oparms;
474     char    *sfname, *fullName;
475     SF_INFO sfinfo;
476     int     fileType = (int) TYP_RAW;
477     int     isfd = 0;   /* stdin */
478 
479     alloc_globals(csound);
480     STA(inbufrem) = (uint32) 0;    /* start with empty buffer */
481     sfname = O->infilename;
482     if (UNLIKELY(sfname == NULL || sfname[0] == '\0'))
483       csound->Die(csound, Str("error: no input file name"));
484 
485     if (strcmp(sfname, "stdin") == 0) {
486       STA(pipdevin) = 1;
487     }
488 #ifdef PIPES
489     else if (sfname[0] == '|') {
490       STA(pin) = _popen(sfname + 1, "r");
491       isfd = fileno(STA(pin));
492       STA(pipdevin) = 1;
493     }
494 #endif
495     else {
496       csRtAudioParams   parm;
497       /* check for real time audio input, and get device name/number */
498       parm.devNum = check_rtaudio_name(sfname, &(parm.devName), 0);
499       if (parm.devNum >= 0) {
500         /* set device parameters */
501         parm.bufSamp_SW   =
502           (unsigned int) O->inbufsamps / (unsigned int) csound->inchnls;
503         parm.bufSamp_HW   = O->oMaxLag;
504         parm.nChannels    = csound->inchnls;
505         parm.sampleFormat = O->informat;
506         parm.sampleRate   = (float) csound->esr;
507         /* open devaudio for input */
508         if (UNLIKELY(csound->recopen_callback(csound, &parm) != 0))
509           csoundDie(csound, Str("Failed to initialise real time audio input"));
510         /*  & redirect audio gets  */
511         csound->audrecv = csound->rtrecord_callback;
512         STA(pipdevin) = 2;       /* no backward seeks !     */
513         goto inset;             /* no header processing    */
514       }
515     }
516     /* open file */
517     memset(&sfinfo, 0, sizeof(SF_INFO));
518     if (STA(pipdevin)) {
519       STA(infile) = sf_open_fd(isfd, SFM_READ, &sfinfo, 0);
520       if (UNLIKELY(STA(infile) == NULL)) {
521         /* open failed: possibly raw file, but cannot seek back to try again */
522         const char *sfError = Str(sf_strerror(NULL));
523         csoundDie(csound, Str("isfinit: cannot open %s -- %s"), sfname, sfError);
524       }
525     }
526     else {
527       fullName = csoundFindInputFile(csound, sfname, "SFDIR;SSDIR");
528       if (UNLIKELY(fullName == NULL))                     /* if not found */
529         csoundDie(csound, Str("isfinit: cannot open %s"), sfname);
530       STA(infile) = sf_open(fullName, SFM_READ, &sfinfo);
531       if (STA(infile) == NULL) {
532         /* open failed: maybe raw file ? */
533         memset(&sfinfo, 0, sizeof(SF_INFO));
534         sfinfo.samplerate = (int) MYFLT2LRND(csound->esr);
535         sfinfo.channels = csound->nchnls;
536         /* FIXME: assumes input sample format is same as output */
537         sfinfo.format = TYPE2SF(TYP_RAW) | FORMAT2SF(O->outformat);
538         STA(infile) = sf_open(fullName, SFM_READ, &sfinfo);  /* try again */
539       }
540       if (UNLIKELY(STA(infile) == NULL)) {
541         const char *sfError = Str(sf_strerror(NULL));
542         csoundDie(csound, Str("isfinit: cannot open %s -- %s"), fullName, sfError);
543       }
544       /* only notify the host if we opened a real file, not stdin or a pipe */
545       csoundNotifyFileOpened(csound, fullName,
546                               sftype2csfiletype(sfinfo.format), 0, 0);
547       sfname = fullName;
548     }
549     /* chk the hdr codes  */
550     if (sfinfo.samplerate != (int) MYFLT2LRND(csound->esr)) {
551       csound->Warning(csound, Str("audio_in %s has sr = %d, orch sr = %d"),
552                               sfname, (int) sfinfo.samplerate,
553                               (int) MYFLT2LRND(csound->esr));
554     }
555     if (sfinfo.channels != csound->inchnls) {
556       csound->Warning(csound, Str("audio_in %s has %d chnls, orch %d chnls_i"),
557                               sfname, (int) sfinfo.channels, csound->inchnls);
558     }
559     /* Do we care about the format?  Can assume float?? */
560     O->informat = SF2FORMAT(sfinfo.format);
561     fileType = (int) SF2TYPE(sfinfo.format);
562     csound->audrecv = readsf;           /* will use standard audio gets  */
563     if ((O->informat == AE_FLOAT || O->informat == AE_DOUBLE) &&
564         !(fileType == TYP_WAV || fileType == TYP_AIFF || fileType == TYP_W64)) {
565       /* do not scale "raw" floating point files */
566       csound->spinrecv = sndfilein_noscale;
567     }
568 
569  inset:
570     /* calc inbufsize reqd */
571     STA(inbufsiz) = (unsigned) (O->inbufsamps * sizeof(MYFLT));
572     STA(inbuf) = (MYFLT*) csound->Calloc(csound,
573                                          STA(inbufsiz)); /* alloc inbuf space */
574     if (STA(pipdevout) == 2)
575       csound->Message(csound,
576                       Str("reading %d sample blks of %lu-bit floats from %s\n"),
577                       O->inbufsamps * O->sfsampsize,
578                       (unsigned long) sizeof(MYFLT)*8, sfname);
579     else {
580       csound->Message(csound,
581                       Str("reading %d-byte blks of %s from %s (%s)\n"),
582                       O->inbufsamps * (int) sfsampsize(FORMAT2SF(O->informat)),
583                       getstrformat(O->informat), sfname, type2string(fileType));
584     }
585     STA(isfopen) = 1;
586 }
587 
copyrightcode(int n)588 static char* copyrightcode(int n)
589 {
590       char* a[] = {
591         "All Rights Reserved\n",
592         "Creative Commons Attribution-NonCommercial-NoDerivatives\nCC BY-NC-ND\n)",
593         "Creative Commons Attribution-NonCommercial-ShareAlike\nCC BY-NC-SA\n",
594         "Creative Commons Attribution-NonCommercial\nCC BY-NC\n",
595         "Creative Commons Attribution-NoDerivatives\nCC BY-ND\n",
596         "Creative Commons Attribution-ShareAlike\nCC BY-SA\n",
597         "Creative Commons Attribution\nCC BY\n",
598         "Licenced under BSD\n"
599       };
600       if (n>=8) n = 0;
601       return a[n];
602 }
603 
sfopenout(CSOUND * csound)604 void sfopenout(CSOUND *csound)                  /* init for sound out       */
605 {                                               /* (not called if nosound)  */
606     OPARMS  *O = csound->oparms;
607     char    *s, *fName, *fullName;
608     SF_INFO sfinfo;
609     int     osfd = 1;   /* stdout */
610 
611     alloc_globals(csound);
612     if (O->outfilename == NULL) {
613       switch (O->filetyp) {
614       case TYP_WAV:
615       case TYP_W64:
616       case TYP_WAVEX:
617       case TYP_RF64:
618         O->outfilename = "test.wav";
619         break;
620       case TYP_AIFF:
621         O->outfilename = "test.aif";
622         break;
623       case TYP_AU:
624         O->outfilename = "test.au";
625         break;
626       case TYP_PAF:
627         O->outfilename = "test.paf";
628         break;
629       case TYP_SVX:
630         O->outfilename = "test.svx";
631         break;
632       case TYP_NIST:
633         O->outfilename = "test.sph";
634         break;
635       case TYP_VOC:
636         O->outfilename = "test.voc";
637         break;
638       /* case TYP_IRCAM: */
639       /*   O->outfilename = ""; */
640       /*   break; */
641       /* case TYP_MAT4: */
642       /*   O->outfilename = ""; */
643       /*   break;  */
644       /* case TYP_MAT5: */
645       /*   O->outfilename = ""; */
646       /*   break;  */
647       /* case TYP_PVF: */
648       /*   O->outfilename = ""; */
649       /*   break;   */
650       case TYP_XI:
651         O->outfilename = "test.xi";
652         break;
653       /* case TYP_HTK: */
654       /*   O->outfilename = ""; */
655       /*   break;   */
656       /* case TYP_SDS: */
657       /*   O->outfilename = "test.sds"; */
658       /*   break;   */
659       case TYP_AVR:
660         O->outfilename = "test.avr";
661         break;
662       case TYP_SD2:
663         O->outfilename = "test.sd2";
664         break;
665       case TYP_FLAC:
666         O->outfilename = "test.flac";
667         break;
668       case TYP_CAF:
669         O->outfilename = "test.caf";
670         break;
671       case TYP_OGG:
672         O->outfilename = "test.ogg";
673         break;
674       /* case TYP_MPC2K: */
675       /*   O->outfilename = ""; */
676       /*   break; */
677       default:
678         O->outfilename = "test";
679         break;
680       }
681     }
682     STA(sfoutname) = fName = O->outfilename;
683 
684     if (strcmp(fName, "stdout") == 0) {
685       STA(pipdevout) = 1;
686     }
687 #ifdef PIPES
688     else if (fName[0] == '|') {
689       STA(pout) = _popen(fName+1, "w");
690       osfd = fileno(STA(pout));
691       STA(pipdevout) = 1;
692       if (O->filetyp == TYP_AIFF || O->filetyp == TYP_WAV) {
693         char fmt_name[6];
694         if (O->sfsampsize == 8) {
695           strcpy(fmt_name, "AU");
696           O->filetyp = TYP_AU;
697         }
698         else {
699           strcpy(fmt_name, "IRCAM");
700           O->filetyp = TYP_IRCAM;
701         }
702         csound->Message(csound, Str("Output file type changed to %s "
703                                     "for use in pipe\n"), fmt_name);
704       }
705     }
706 #endif
707     else {
708       csRtAudioParams   parm;
709       /* check for real time audio output, and get device name/number */
710       parm.devNum = check_rtaudio_name(fName, &(parm.devName), 1);
711       if (parm.devNum >= 0) {
712         /* set device parameters */
713         parm.bufSamp_SW   = (unsigned int) O->outbufsamps / csound->nchnls;
714         parm.bufSamp_HW   = O->oMaxLag;
715         parm.nChannels    = csound->nchnls;
716         parm.sampleFormat = O->outformat;
717         parm.sampleRate   = (float) csound->esr;
718         csound->spoutran  = spoutsf;
719         /* open devaudio for output */
720         if (UNLIKELY(csound->playopen_callback(csound, &parm) != 0))
721           csoundDie(csound, Str("Failed to initialise real time audio output"));
722         /*  & redirect audio puts  */
723         csound->audtran = csound->rtplay_callback;
724         STA(outbufrem)  = parm.bufSamp_SW * parm.nChannels;
725         STA(pipdevout)  = 2;      /* no backward seeks !   */
726         if (O->realtime == 1)     /* set realtime priority mode */
727           csound->realtime_audio_flag = 1;
728         goto outset;              /* no header needed      */
729       }
730       else if (strcmp(fName, "null") == 0) {
731         STA(outfile) = NULL;
732         if (csound->dither_output && csound->oparms->outformat!=AE_FLOAT &&
733             csound->oparms->outformat!=AE_DOUBLE) {
734           if (csound->oparms->outformat==AE_SHORT)
735             if (csound->dither_output==1)
736               csound->audtran = writesf_dither_16;
737             else
738               csound->audtran = writesf_dither_u16;
739           else if (csound->oparms->outformat==AE_CHAR)
740             if (csound->dither_output==1)
741               csound->audtran = writesf_dither_8;
742             else
743               csound->audtran = writesf_dither_u8;
744           else
745             csound->audtran = writesf;
746         }
747         else
748           csound->audtran = writesf;
749         goto outset;
750       }
751     }
752     /* set format parameters */
753     memset(&sfinfo, 0, sizeof(SF_INFO));
754     //sfinfo.frames     = 0;
755     sfinfo.samplerate = (int) MYFLT2LRND(csound->esr);
756     sfinfo.channels   = csound->nchnls;
757     sfinfo.format     = TYPE2SF(O->filetyp) | FORMAT2SF(O->outformat);
758     /* open file */
759     if (STA(pipdevout)) {
760       STA(outfile) = sf_open_fd(osfd, SFM_WRITE, &sfinfo, 0);
761 #ifdef PIPES
762       if (STA(outfile) == NULL) {
763         char fmt_name[6];
764         if (O->sfsampsize == 8) {
765           if (UNLIKELY(O->filetyp == TYP_AU))
766             csoundDie(csound, Str("sfinit: cannot open fd %d\n%s"), osfd,
767                       Str(sf_strerror(NULL)));
768           strcpy(fmt_name, "AU");
769           O->filetyp = TYP_AU;
770         }
771         else {
772           if (UNLIKELY(O->filetyp == TYP_IRCAM))
773             csoundDie(csound, Str("sfinit: cannot open fd %d\n%s"), osfd,
774                       Str(sf_strerror(NULL)));
775           strcpy(fmt_name, "IRCAM");
776           O->filetyp = TYP_IRCAM;
777         }
778         csound->Message(csound, Str("Output file type changed to %s "
779                                     "for use in pipe\n"), fmt_name);
780         sfinfo.format = TYPE2SF(O->filetyp) | FORMAT2SF(O->outformat);
781         STA(outfile) = sf_open_fd(osfd, SFM_WRITE, &sfinfo, 0);
782       }
783 #endif
784       if (UNLIKELY(STA(outfile) == NULL))
785         csoundDie(csound, Str("sfinit: cannot open fd %d\n%s"), osfd,
786                   Str(sf_strerror(NULL)));
787       sf_command(STA(outfile), SFC_SET_VBR_ENCODING_QUALITY,
788                  &O->quality, sizeof(double));
789     }
790     else {
791       fullName = csoundFindOutputFile(csound, fName, "SFDIR");
792       if (UNLIKELY(fullName == NULL))
793         csoundDie(csound, Str("sfinit: cannot open %s"), fName);
794       STA(sfoutname) = fullName;
795       STA(outfile)   = sf_open(fullName, SFM_WRITE, &sfinfo);
796       if (UNLIKELY(STA(outfile) == NULL))
797         csoundDie(csound, Str("sfinit: cannot open %s\n%s"),
798                   fullName, sf_strerror (NULL));
799       sf_command(STA(outfile), SFC_SET_VBR_ENCODING_QUALITY,
800                  &O->quality, sizeof(double));
801       /* only notify the host if we opened a real file, not stdout or a pipe */
802       csoundNotifyFileOpened(csound, fullName,
803                               type2csfiletype(O->filetyp, O->outformat), 1, 0);
804     }
805     /* IV - Feb 22 2005: clip integer formats */
806     if (O->outformat != AE_FLOAT && O->outformat != AE_DOUBLE)
807       sf_command(STA(outfile), SFC_SET_CLIPPING, NULL, SF_TRUE);
808     sf_command(STA(outfile), SFC_SET_ADD_PEAK_CHUNK,
809                NULL, (csound->peakchunks ? SF_TRUE : SF_FALSE));
810 #ifdef SOME_FINE_DAY
811     if (csound->dither_output) {        /* This may not be written yet!! */
812       SF_DITHER_INFO  ditherInfo;
813       memset(&ditherInfo, 0, sizeof(SF_DITHER_INFO));
814       ditherInfo.type  = SFD_TRIANGULAR_PDF | SFD_DEFAULT_LEVEL;
815       ditherInfo.level = 1.0;
816       ditherInfo.name  = (char*) NULL;
817       sf_command(STA(outfile), SFC_SET_DITHER_ON_WRITE,
818                  &ditherInfo, sizeof(SF_DITHER_INFO));
819     }
820 #endif
821     if (!(O->outformat == AE_FLOAT || O->outformat == AE_DOUBLE) ||
822         (O->filetyp == TYP_WAV || O->filetyp == TYP_AIFF ||
823          O->filetyp == TYP_W64))
824       csound->spoutran = spoutsf;       /* accumulate output */
825     else
826       csound->spoutran = spoutsf_noscale;
827     if (csound->dither_output && csound->oparms->outformat!=AE_FLOAT &&
828         csound->oparms->outformat!=AE_DOUBLE) {
829       if (csound->oparms->outformat==AE_SHORT)
830         csound->audtran = writesf_dither_16;
831       else if (csound->oparms->outformat==AE_CHAR)
832         csound->audtran = writesf_dither_8;
833       else
834         csound->audtran = writesf;
835     }
836     else
837       csound->audtran = writesf;
838     /* Write any tags. */
839     if ((s = csound->SF_id_title) != NULL && *s != '\0')
840       sf_set_string(STA(outfile), SF_STR_TITLE, s);
841     if ((s = csound->SF_csd_licence) == NULL || *s == '\0')
842       s = csound->SF_id_copyright;
843     if (s != NULL && *s != '\0')
844       sf_set_string(STA(outfile), SF_STR_COPYRIGHT, s);
845     else if (csound->SF_id_scopyright>=0) {
846       char buff[256];
847       time_t tt = time(NULL);
848       strftime(buff, 256, "Copyright %Y: ", gmtime(&tt));
849       strncat(buff,copyrightcode(csound->SF_id_scopyright), 255);
850       buff[255] = '\0';
851       sf_set_string(STA(outfile), SF_STR_COPYRIGHT, buff);
852     }
853     if ((s = csound->SF_id_software) != NULL && *s != '\0')
854       sf_set_string(STA(outfile), SF_STR_SOFTWARE, s);
855     if ((s = csound->SF_id_artist) != NULL && *s != '\0')
856       sf_set_string(STA(outfile), SF_STR_ARTIST, s);
857     if ((s = csound->SF_id_comment) != NULL && *s != '\0')
858       sf_set_string(STA(outfile), SF_STR_COMMENT, s);
859     if ((s = csound->SF_id_date) != NULL && *s != '\0')
860       sf_set_string(STA(outfile), SF_STR_DATE, s);
861     /* file is now open */
862     STA(osfopen) = 1;
863 
864  outset:
865     O->sfsampsize = (int) sfsampsize(FORMAT2SF(O->outformat));
866     /* calc outbuf size & alloc bufspace */
867     STA(outbufsiz) = O->outbufsamps * sizeof(MYFLT);
868     STA(outbufp)   = STA(outbuf) = csound->Malloc(csound, STA(outbufsiz));
869     if (STA(pipdevout) == 2)
870       csound->Message(csound,
871                       Str("writing %d sample blks of %lu-bit floats to %s\n"),
872                       O->outbufsamps, (unsigned long) sizeof(MYFLT)*8,
873                       STA(sfoutname));
874     else {
875      csound->Message(csound, Str("writing %d-byte blks of %s to %s"),
876                     O->outbufsamps * O->sfsampsize,
877                     getstrformat(O->outformat), STA(sfoutname));
878 
879     if (O->sfheader == 0)
880       csound->Message(csound, Str(" (raw)\n"));
881     else
882       csound->Message(csound, " (%s)\n", type2string(O->filetyp));
883     }
884     STA(osfopen)   = 1;
885     STA(outbufrem) = O->outbufsamps;
886 }
887 
sfclosein(CSOUND * csound)888 void sfclosein(CSOUND *csound)
889 {
890     alloc_globals(csound);
891     if (!STA(isfopen))
892       return;
893     if (STA(pipdevin) == 2 && (!STA(osfopen) || STA(pipdevout) != 2)) {
894       /* close only if not open for output too */
895       csound->rtclose_callback(csound);
896     }
897     else if (STA(pipdevin) != 2) {
898       if (STA(infile) != NULL)
899         sf_close(STA(infile));
900 #ifdef PIPES
901       if (STA(pin) != NULL) {
902         _pclose(STA(pin));
903         STA(pin) = NULL;
904       }
905 #endif
906       STA(infile) = NULL;
907     }
908     STA(isfopen) = 0;
909 }
910 
sfcloseout(CSOUND * csound)911 void sfcloseout(CSOUND *csound)
912 {
913     OPARMS  *O = csound->oparms;
914     int     nb;
915 
916     alloc_globals(csound);
917     if (!STA(osfopen))
918       return;
919     if ((nb = (O->outbufsamps - STA(outbufrem)) * sizeof(MYFLT)) > 0) {
920       /* flush outbuffer */
921       csound->nrecs++;
922       csound->audtran(csound, STA(outbuf), nb);
923     }
924     if (STA(pipdevout) == 2 && (!STA(isfopen) || STA(pipdevin) != 2)) {
925       /* close only if not open for input too */
926       csound->rtclose_callback(csound);
927     }
928     if (STA(pipdevout) == 2)
929       goto report;
930     if (STA(outfile) != NULL) {
931       if (!STA(pipdevout) && O->outformat != AE_VORBIS)
932         sf_command(STA(outfile), SFC_UPDATE_HEADER_NOW, NULL, 0);
933       sf_close(STA(outfile));
934       STA(outfile) = NULL;
935     }
936 #ifdef PIPES
937     if (STA(pout) != NULL) {
938       _pclose(STA(pout));
939       STA(pout) = NULL;
940     }
941 #endif
942 
943  report:
944     if (STA(pipdevout) == 2) {
945       csound->Message(csound,
946                       "%"PRIi32" %d %s%lu%s%s\n",
947                       csound->nrecs, O->outbufsamps, Str("sample blks of "),
948                       (unsigned long)sizeof(MYFLT)*8,Str("-bit floats written to "),
949                       STA(sfoutname));
950     }
951     else {
952       csound->Message(csound, Str("%"PRIi32" %d sample blks of %s written to %s"),
953                       O->outbufsamps, O->outbufsamps * O->sfsampsize,
954                       getstrformat(O->outformat), STA(sfoutname));
955       if (O->sfheader == 0)
956         csound->Message(csound, Str(" (raw)\n"));
957       else
958         csound->Message(csound, " (%s)\n", type2string(O->filetyp));
959     }
960     STA(osfopen) = 0;
961 }
962 
963 /* report soundfile write(osfd) error   */
964 /* called after chk of write() bytecnt  */
965 
sndwrterr(CSOUND * csound,int nret,int nput)966 static void sndwrterr(CSOUND *csound, int nret, int nput)
967 {
968     csound->ErrorMsg(csound,
969                      Str("soundfile write returned bytecount of %d, not %d"),
970                      nret, nput);
971     csound->ErrorMsg(csound,
972                      Str("(disk may be full...\n closing the file ...)"));
973     STA(outbufrem) = csound->oparms->outbufsamps;  /* consider buf is flushed */
974     sfcloseout(csound);                           /* & try to close the file */
975     csound->Die(csound, Str("\t... closed\n"));
976 }
977 
sfnopenout(CSOUND * csound)978 void sfnopenout(CSOUND *csound)
979 {
980     alloc_globals(csound);
981     csound->Message(csound, Str("not writing to sound disk\n"));
982     /* init counter, though not writing */
983     STA(outbufrem) = csound->oparms->outbufsamps;
984 }
985 
sndfilein_(CSOUND * csound,MYFLT scaleFac)986 static inline void sndfilein_(CSOUND *csound, MYFLT scaleFac)
987 {
988     OPARMS  *O = csound->oparms;
989     int     i, n, nsmps, bufpos;
990 
991     nsmps = csound->nspin;
992     bufpos = (int) O->inbufsamps - (int) STA(inbufrem);
993     for (i = 0; i<nsmps; i++) {
994       if ((int) STA(inbufrem) < 1) {
995         STA(inbufrem) = 0U;
996         do {
997           n = ((int) O->inbufsamps - (int) STA(inbufrem)) * (int) sizeof(MYFLT);
998           n = csound->audrecv(csound, STA(inbuf) + (int) STA(inbufrem), n);
999           STA(inbufrem) += (unsigned int) (n / (int) sizeof(MYFLT));
1000         } while ((int) STA(inbufrem) < (int) O->inbufsamps);
1001         bufpos = 0;
1002       }
1003       csound->spin[i] = STA(inbuf)[bufpos++] * scaleFac;
1004       STA(inbufrem)--;
1005     }
1006 }
1007 
sndfilein(CSOUND * csound)1008 static void sndfilein(CSOUND *csound)
1009 {
1010     sndfilein_(csound, csound->e0dbfs);
1011 }
1012 
1013 /* special version of sndfilein for "raw" floating point files */
1014 
sndfilein_noscale(CSOUND * csound)1015 static void sndfilein_noscale(CSOUND *csound)
1016 {
1017     sndfilein_(csound, FL(1.0));
1018 }
1019 
audrecv_dummy(CSOUND * csound,MYFLT * buf,int nbytes)1020 static int audrecv_dummy(CSOUND *csound, MYFLT *buf, int nbytes)
1021 {
1022     (void) csound; (void) buf;
1023     return nbytes;
1024 }
1025 
audtran_dummy(CSOUND * csound,const MYFLT * buf,int nbytes)1026 static void audtran_dummy(CSOUND *csound, const MYFLT *buf, int nbytes)
1027 {
1028     (void) csound; (void) buf; (void) nbytes;
1029 }
1030 
1031 /* direct recv & tran calls to the right audio formatter  */
1032 /*                            & init its audio_io bufptr  */
1033 
iotranset(CSOUND * csound)1034 void iotranset(CSOUND *csound)
1035 {
1036     OPARMS  *O;
1037 
1038     csound->spinrecv = sndfilein;
1039     csound->spoutran = spoutsf;
1040     if (!csound->enableHostImplementedAudioIO)
1041       return;
1042     alloc_globals(csound);
1043     O               = csound->oparms;
1044     csound->audrecv = audrecv_dummy;
1045     csound->audtran = audtran_dummy;
1046     STA(inbufrem)   = (unsigned int) O->inbufsamps;
1047     STA(outbufrem)  = (unsigned int) O->outbufsamps;
1048     if (!csound->hostRequestedBufferSize) {
1049       O->sfread    = 0;
1050       O->sfwrite   = 0;
1051       STA(osfopen) = 0;
1052       return;
1053     }
1054     STA(inbufsiz)  = (unsigned int) (O->inbufsamps * (int) sizeof(MYFLT));
1055     STA(inbuf)     = (MYFLT*) csound->Calloc(csound, STA(inbufsiz));
1056     STA(outbufsiz) = (unsigned int) (O->outbufsamps * (int) sizeof(MYFLT));
1057     STA(outbuf)    = (MYFLT*) csound->Calloc(csound, STA(outbufsiz));
1058     STA(outbufp)   = STA(outbuf);
1059     O->sfread      = 1;
1060     O->sfwrite     = 1;
1061     STA(osfopen)   = 1;
1062 }
1063 
csoundGetInputBuffer(CSOUND * csound)1064 PUBLIC MYFLT *csoundGetInputBuffer(CSOUND *csound)
1065 {
1066     return STA(inbuf);
1067 }
1068 
csoundGetOutputBuffer(CSOUND * csound)1069 PUBLIC MYFLT *csoundGetOutputBuffer(CSOUND *csound)
1070 {
1071     return STA(outbuf);
1072 }
1073