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