1 /*
2 mixer.cXF
3
4 Copyright (C) 1995 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 /*******************************************************\
25 * mixer.c *
26 * mix a set of sound files with arbitary starts *
27 * jpff 23 Sep 1994 *
28 * including lifting from Csound itself *
29 \*******************************************************/
30
31
32 /* Notes:
33 * This makes a mess of multichannel inputs.
34 * Needs to take much more care
35 */
36
37 #include "std_util.h"
38 #include "soundio.h"
39 #include <ctype.h>
40 #include <inttypes.h>
41
42 /* Constants */
43
44 #define NUMBER_OF_SAMPLES (65536)
45 #define NUMBER_OF_FILES (32)
46
47 #define FIND(MSG) if (*s == '\0') \
48 if (UNLIKELY(!(--argc) || ((s = *++argv) && *s == '-'))) \
49 csound->Die(csound, Str("mixer: error: %s"), MSG);
50
51 typedef struct scalepoint {
52 MYFLT y0;
53 MYFLT y1;
54 MYFLT yr;
55 int32_t x0;
56 int32_t x1;
57 struct scalepoint *next;
58 } scalepoint;
59
60 typedef struct inputs {
61 long start; /* Time this file starts in samples */
62 MYFLT time; /* Time this file starts in secs */
63 char * name; /* Name of file */
64 int32_t use_table; /* Should we use multiplier or table */
65 MYFLT factor; /* Gain factor */
66 char * fname; /* Name of scale table file */
67 scalepoint *fulltable; /* Scaling table */
68 scalepoint *table; /* current position in table */
69 SNDFILE *fd; /* File descriptor handle */
70 int16 channels[5]; /* destinations of channels */
71 int32_t non_clear; /* Boolean to say if fiddled mixing */
72 SOUNDIN * p; /* Csound structure */
73 } inputs;
74
75 typedef struct mixer_globals_ {
76 CSOUND *csound;
77 inputs mixin[NUMBER_OF_FILES];
78 int32_t outputs;
79 int32_t debug;
80 uint32_t outbufsiz;
81 MYFLT *out_buf;
82 int32_t outrange; /* Count samples out of range */
83 } MIXER_GLOBALS;
84
85 /* Static function prototypes */
86
87 static void InitScaleTable(MIXER_GLOBALS *, int32_t);
88 static MYFLT gain(MIXER_GLOBALS *, int32_t, int32_t);
89 static SNDFILE *MXsndgetset(CSOUND*,inputs *);
90 static void MixSound(MIXER_GLOBALS *, int32_t, SNDFILE *, OPARMS *);
91
92 static const char *usage_txt[] = {
93 Str_noop("Usage:\tmixer [-flags] soundfile [-flags] soundfile ..."),
94 Str_noop("Legal flags are:"),
95 Str_noop("-o fnam\tsound output filename"),
96 Str_noop("-A\tcreate an AIFF format output soundfile"),
97 Str_noop("-W\tcreate a WAV format output soundfile"),
98 Str_noop("-h\tno header on output soundfile"),
99 Str_noop("-8\t8-bit unsigned_char sound samples"),
100 Str_noop("-c\t8-bit signed_char sound samples"),
101 Str_noop("-8\t8-bit unsigned_char sound samples"),
102 Str_noop("-a\talaw sound samples"),
103 Str_noop("-u\tulaw sound samples"),
104 Str_noop("-s\tshort_int sound samples"),
105 Str_noop("-l\tlong_int sound samples"),
106 Str_noop("-f\tfloat sound samples"),
107 Str_noop("-R\tcontinually rewrite header while writing soundfile (WAV/AIFF)"),
108 Str_noop("-H#\tprint a heartbeat style 1, 2 or 3 at each soundfile write"),
109 Str_noop("-N\tnotify (ring the bell) when score or miditrack is done"),
110 Str_noop("-F fpnum\tamount to scale amplitude for next input"),
111 Str_noop("-F fname\tfile of a scale table for next input"),
112 Str_noop("-S integer\tsample number at which to insert file"),
113 Str_noop("-T fpnum\ttime at which to insert file"),
114 Str_noop("-1 -2 -3 -4\tinclude named channel"),
115 Str_noop("-^ n m\tinclude channel n and output as channel m"),
116 Str_noop("-v\tverbose mode for debugging"),
117 Str_noop("-- fname\tLog output to file"),
118 Str_noop("flag defaults: mixer -s -otest -F 1.0 -S 0"),
119 NULL
120 };
121
usage(CSOUND * csound,const char * mesg,...)122 static void usage(CSOUND *csound, const char *mesg, ...)
123 {
124 const char **sp;
125 va_list args;
126
127 for (sp = &(usage_txt[0]); *sp != NULL; sp++)
128 csound->Message(csound, "%s\n", Str(*sp));
129
130 va_start(args, mesg);
131 csound->ErrMsgV(csound, Str("mixer: error: "), mesg, args);
132 va_end(args);
133 csound->LongJmp(csound, 1);
134 }
135
set_output_format(CSOUND * csound,char c,char outformch,OPARMS * O)136 static char set_output_format(CSOUND *csound, char c, char outformch, OPARMS *O)
137 {
138 (void) csound;
139 switch (c) {
140 case 'a': O->outformat = AE_ALAW; /* a-law soundfile */
141 break;
142 case 'c': O->outformat = AE_CHAR; /* signed 8-bit soundfile */
143 break;
144 case '8': O->outformat = AE_UNCH; /* unsigned 8-bit soundfile */
145 break;
146 case 'f': O->outformat = AE_FLOAT; /* float soundfile */
147 break;
148 case 's': O->outformat = AE_SHORT; /* short_int soundfile*/
149 break;
150 case 'l': O->outformat = AE_LONG; /* long_int soundfile */
151 break;
152 case 'u': O->outformat = AE_ULAW; /* mu-law soundfile */
153 break;
154 case '3': O->outformat = AE_24INT; /* 24bit packed soundfile*/
155 break;
156 case 'e': O->outformat = AE_FLOAT; /* float soundfile (for rescaling) */
157 break;
158 default: return outformch; /* do nothing */
159 }
160 return c;
161 }
162
mixer_main(CSOUND * csound,int argc,char ** argv)163 static int mixer_main(CSOUND *csound, int argc, char **argv)
164 {
165 OPARMS O;
166 char *inputfile = NULL;
167 SNDFILE *outfd;
168 int32_t i;
169 char outformch='s', c, *s;
170 const char *envoutyp;
171 int32_t n = 0;
172 SF_INFO sfinfo;
173 MIXER_GLOBALS *pp = (MIXER_GLOBALS*) csound->Calloc(csound,
174 sizeof(MIXER_GLOBALS));
175 inputs *mixin = &(pp->mixin[0]);
176
177 csound->GetOParms(csound, &O);
178
179 pp->csound = csound;
180 /*csound->dbfs_to_float = csound->e0dbfs = FL(1.0);*/
181 /* Check arguments */
182 if ((envoutyp = csound->GetEnv(csound, "SFOUTYP")) != NULL) {
183 if (strcmp(envoutyp, "AIFF") == 0)
184 O.filetyp = TYP_AIFF;
185 else if (strcmp(envoutyp, "WAV") == 0)
186 O.filetyp = TYP_WAV;
187 else if (strcmp(envoutyp, "IRCAM") == 0)
188 O.filetyp = TYP_IRCAM;
189 else {
190 csound->ErrorMsg(csound, Str("%s not a recognized SFOUTYP env setting"),
191 envoutyp);
192 return -1;
193 }
194 }
195 mixin[n].start = -1; mixin[n].time = -FL(1.0);
196 mixin[n].factor = FL(1.0); mixin[n].non_clear = 0;
197 mixin[n].fulltable = NULL; mixin[n].use_table = 0;
198 for (i=1; i<5; i++) mixin[n].channels[i] = 0;
199 if (UNLIKELY(!(--argc)))
200 usage(csound,"%s", Str("Insufficient arguments"));
201 do {
202 s = *++argv;
203 if (*s++ == '-') /* read all flags: */
204 while ((c = *s++) != '\0')
205 switch(c) {
206 case 'o':
207 FIND(Str("no outfilename"))
208 O.outfilename = s; /* soundout name */
209 for ( ; *s != '\0'; s++) ;
210 if (UNLIKELY(strcmp(O.outfilename, "stdin") == 0))
211 csound->Die(csound, "%s", Str("mixer: -o cannot be stdin"));
212 #if defined(WIN32)
213 if (UNLIKELY(strcmp(O.outfilename,"stdout") == 0)) {
214 csound->Die(csound, "%s", Str("mixer: stdout audio not supported"));
215 }
216 #endif
217 break;
218 case 'A':
219 O.filetyp = TYP_AIFF; /* AIFF output request */
220 break;
221 case 'J':
222 O.filetyp = TYP_IRCAM; /* IRCAM output request */
223 break;
224 case 'W':
225 O.filetyp = TYP_WAV; /* WAV output request */
226 break;
227 case 'F':
228 FIND(Str("no scale factor"));
229 if (isdigit(*s) || *s == '-' || *s == '+')
230 mixin[n].factor = (MYFLT) atof(s);
231 else {
232 mixin[n].fname = (char*) csound->Malloc(csound, strlen(s) + 1);
233 strcpy(mixin[n].fname, s);
234 mixin[n].use_table = 1;
235 }
236 while (*++s);
237 break;
238 case 'S':
239 FIND(Str("no start sample"));
240 mixin[n].start = atoi(s);
241 while (*++s);
242 if (UNLIKELY(mixin[n].time >= FL(0.0))) {
243 csound->Warning(csound, "%s", Str("-S overriding -T"));
244 mixin[n].time = -FL(1.0);
245 }
246 break;
247 case 'T':
248 FIND(Str("no start time"));
249 mixin[n].time = (MYFLT) atof(s);
250 while (*++s);
251 if (UNLIKELY(mixin[n].start >= 0)) {
252 csound->Warning(csound, "%s", Str("-T overriding -S"));
253 mixin[n].start = -1;
254 }
255 break;
256 case '1':
257 case '2':
258 case '3':
259 case '4':
260 {
261 int32_t src = c - '0';
262 if (src > pp->outputs)
263 pp->outputs = src;
264 mixin[n].channels[src] = src;
265 mixin[n].non_clear = 1;
266 break;
267 }
268 case '^':
269 {
270 int32_t src = c, dst;
271 FIND(Str("no source channel number"));
272 src = atoi(s);
273 while (*++s);
274 FIND(Str("no destination channel number"));
275 dst = atoi(s);
276 while (*++s);
277 if (UNLIKELY(src > 4 || src < 1 || dst > 4 || dst < 1)) {
278 csound->Warning(csound, "%s",
279 Str("illegal channel number ignored"));
280 break;
281 }
282 if (dst > pp->outputs)
283 pp->outputs = dst;
284 mixin[n].channels[dst] = src;
285 mixin[n].non_clear = 1;
286 break;
287 }
288 case 'h':
289 O.filetyp = TYP_RAW; /* skip sfheader */
290 break;
291 case 'c':
292 case 'a':
293 case 'u':
294 case '8':
295 case 's':
296 case 'l':
297 case 'f':
298 outformch = set_output_format(csound, c, outformch, &O);
299 break;
300 case 'R':
301 O.rewrt_hdr = 1;
302 break;
303 case 'H':
304 if (isdigit(*s)) {
305 int32_t n;
306 sscanf(s, "%d%n", &O.heartbeat, &n);
307 s += n;
308 }
309 else O.heartbeat = 1;
310 break;
311 case 'N':
312 O.ringbell = 1; /* notify on completion */
313 break;
314 case 'v': /* Verbose mode */
315 pp->debug = 1;
316 break;
317 default:
318 usage(csound, Str("unknown flag -%c"), c);
319 }
320 else {
321 int32_t i;
322 mixin[n].name = --s;
323 if (!mixin[n].non_clear)
324 for (i=1; i<5; i++) mixin[n].channels[i] = i;
325 if (UNLIKELY(n++ >= NUMBER_OF_FILES-1)) {
326 usage(csound,Str("Too many mixin"));
327 }
328 mixin[n].start = -1;
329 mixin[n].time = -1;
330 mixin[n].factor = FL(1.0);
331 mixin[n].non_clear = 0;
332 }
333 } while (--argc);
334
335 /* Read sound files */
336 if (UNLIKELY(n == 0)) {
337 csound->ErrorMsg(csound, "%s", Str("No mixin"));
338 return -1;
339 }
340 for (i = 0; i < n; i++) {
341 if (UNLIKELY(!MXsndgetset(csound, &mixin[i]))) {
342 csound->ErrorMsg(csound, Str("%s: error while opening %s"),
343 argv[0], inputfile);
344 return -1;
345 }
346 mixin[i].p->channel = ALLCHNLS;
347 if (i>0) {
348 if (UNLIKELY(mixin[0].p->sr != mixin[i].p->sr)) {
349 csound->ErrorMsg(csound, "%s", Str("Input formats not the same"));
350 return -1;
351 }
352 }
353 if (mixin[i].non_clear) {
354 int32_t j;
355 for (j = 1; j<5; j++)
356 if (pp->outputs < mixin[i].channels[j]) {
357 pp->outputs = mixin[i].channels[j];
358 }
359 }
360 else if (pp->outputs < mixin[i].p->nchanls)
361 pp->outputs = mixin[i].p->nchanls;
362 if (mixin[i].time >= FL(0.0)) {
363 MYFLT sval = (MYFLT) mixin[i].time * (MYFLT) mixin[i].p->sr;
364 mixin[i].start = (long) MYFLT2LRND(sval);
365 }
366 else if (mixin[i].start < 0L)
367 mixin[i].start = 0L;
368 if (mixin[i].use_table) InitScaleTable(pp, i);
369 }
370
371 if (!O.outformat) /* if no audioformat yet */
372 O.outformat = mixin[0].p->format; /* Copy from first input file */
373 O.sfsampsize = csound->sfsampsize(FORMAT2SF(O.outformat));
374 if (!O.filetyp)
375 O.filetyp = mixin[0].p->filetyp; /* Copy from input file */
376 O.sfheader = (O.filetyp == TYP_RAW ? 0 : 1);
377 if (!O.sfheader) /* can't rewrite header if no header requested */
378 O.rewrt_hdr = 0;
379 #ifdef NeXT
380 if (O.outfilename == NULL && !O.filetyp) O.outfilename = "test.snd";
381 else if (O.outfilename == NULL) O.outfilename = "test";
382 #else
383 if (O.outfilename == NULL) {
384 if (O.filetyp == TYP_WAV) O.outfilename = "test.wav";
385 else if (O.filetyp == TYP_AIFF) O.outfilename = "test.aif";
386 else O.outfilename = "test";
387 }
388 #endif
389 csound->SetUtilSr(csound, (MYFLT)mixin[0].p->sr);
390 memset(&sfinfo, 0, sizeof(SF_INFO));
391 //sfinfo.frames = 0/*was -1*/;
392 sfinfo.samplerate = mixin[0].p->sr;
393 sfinfo.channels /*= csound->nchnls*/ = (int32_t) mixin[0].p->nchanls;
394 sfinfo.format = TYPE2SF(O.filetyp) | FORMAT2SF(O.outformat);
395 if (strcmp(O.outfilename, "stdout") == 0) {
396 outfd = sf_open_fd(1, SFM_WRITE, &sfinfo, 0);
397 if (outfd != NULL) {
398 if (UNLIKELY(csound->CreateFileHandle(csound,
399 &outfd, CSFILE_SND_W,
400 "stdout") == NULL)) {
401 sf_close(outfd);
402 return -1;
403 }
404 }
405 }
406 else if (csound->FileOpen2(csound, &outfd, CSFILE_SND_W, O.outfilename,
407 &sfinfo, "SFDIR", csound->type2csfiletype(O.filetyp,
408 O.outformat), 0) == NULL)
409 outfd = NULL;
410 if (UNLIKELY(outfd == NULL)) {
411 csound->ErrorMsg(csound, Str("mixer: error opening output file '%s': %s"),
412 O.outfilename, Str(sf_strerror(NULL)));
413 return -1;
414 }
415 if (UNLIKELY(O.rewrt_hdr))
416 sf_command(outfd, SFC_SET_UPDATE_HEADER_AUTO, NULL, 0);
417 /* calc outbuf size & alloc bufspace */
418 pp->outbufsiz = NUMBER_OF_SAMPLES * pp->outputs;
419 pp->out_buf = csound->Malloc(csound, pp->outbufsiz * sizeof(MYFLT));
420 pp->outbufsiz *= O.sfsampsize;
421 csound->Message(csound, Str("writing %d-byte blks of %s to %s (%s)\n"),
422 pp->outbufsiz,
423 csound->getstrformat(O.outformat), O.outfilename,
424 csound->type2string(O.filetyp));
425 MixSound(pp, n, outfd, &O);
426 if (O.ringbell)
427 csound->MessageS(csound, CSOUNDMSG_REALTIME, "\007");
428 return 0;
429 }
430
431 static void
InitScaleTable(MIXER_GLOBALS * pp,int32_t i)432 InitScaleTable(MIXER_GLOBALS *pp, int32_t i)
433 {
434 CSOUND *csound = pp->csound;
435 FILE *f;
436 inputs *mixin = &(pp->mixin[0]);
437 MYFLT samplepert = (MYFLT) mixin[i].p->sr;
438 MYFLT x, y;
439 scalepoint *tt = (scalepoint*) csound->Malloc(csound, sizeof(scalepoint));
440
441 if (UNLIKELY(csound->FileOpen2(csound, &f, CSFILE_STD, mixin[i].fname,
442 "r", NULL, CSFTYPE_FLOATS_TEXT, 0) == NULL)) {
443 csound->Die(csound, Str("Cannot open scale table file %s"),
444 mixin[i].fname);
445 return; /* not reached */
446 }
447 mixin[i].fulltable = mixin[i].table = tt;
448 tt->x0 = 0; tt->y0 = FL(0.0); tt->x1 = 0; tt->y1 = FL(0.0);
449 tt->yr = FL(0.0); tt->next = NULL;
450 #ifdef USE_DOUBLE
451 while (fscanf(f, "%lf %lf\n", &x, &y) == 2) {
452 #else
453 while (fscanf(f, "%f %f\n", &x, &y) == 2) {
454 #endif
455 scalepoint *newpoint;
456 newpoint = (scalepoint*) csound->Malloc(csound, sizeof(scalepoint));
457 newpoint->x0 = tt->x1;
458 newpoint->y0 = tt->y1;
459 newpoint->x1 = (int32_t) (x*samplepert);
460 newpoint->y1 = y;
461 if (newpoint->x1 == newpoint->x0) {
462 MYFLT div = (MYFLT)(tt->x1 - tt->x0);
463 tt->y1 = y;
464 if (LIKELY(div))
465 tt->yr = (y - tt->y0)/div;
466 else tt->yr = y;
467 csound->Free(csound, newpoint);
468 }
469 else {
470 newpoint->yr =
471 (y - newpoint->y0)/((MYFLT)(newpoint->x1 - newpoint->x0));
472 tt->next = newpoint;
473 newpoint->next = NULL;
474 tt = newpoint;
475 }
476 }
477 {
478 scalepoint *newpoint =
479 (scalepoint*) csound->Malloc(csound, sizeof(scalepoint));
480 tt->next = newpoint;
481 newpoint->x0 = tt->x1;
482 newpoint->y0 = tt->y1;
483 newpoint->x1 = 0x7fffffff;
484 newpoint->y1 = FL(0.0);
485 newpoint->next = NULL;
486 newpoint->yr = (x == newpoint->x0 ?
487 -newpoint->y0 :
488 -newpoint->y0/((MYFLT)(0x7fffffff-newpoint->x0)));
489 }
490 if (pp->debug) {
491 scalepoint *tt = mixin[i].table;
492 csound->Message(csound, "Scale table is\n");
493 while (tt != NULL) {
494 csound->Message(csound, "(%d %f) -> %d %f [%f]\n",
495 tt->x0, tt->y0, tt->x1, tt->y1, tt->yr);
496 tt = tt->next;
497 }
498 csound->Message(csound, "END of Table\n");
499 }
500 mixin[i].use_table = 1;
501 }
502
503 static MYFLT gain(MIXER_GLOBALS *pp, int32_t n, int32_t i)
504 {
505 CSOUND *csound = pp->csound;
506 inputs *mixin = &(pp->mixin[0]);
507
508 if (!mixin[n].use_table) return mixin[n].factor;
509 if (i<mixin[n].table->x0) mixin[n].table = mixin[n].fulltable;
510 while (i<mixin[n].table->x0 ||
511 i>=mixin[n].table->x1) {/* Get correct segment */
512 if (UNLIKELY(pp->debug))
513 csound->Message(csound, "Table %d: %d (%d %f) -> %d %f [%f]\n",
514 n, i, mixin[n].table->x0, mixin[n].table->y0,
515 mixin[n].table->x1, mixin[n].table->y1,
516 mixin[n].table->yr);
517 mixin[n].table = mixin[n].table->next;
518 }
519 return mixin[n].factor*(mixin[n].table->y0 +
520 mixin[n].table->yr*(MYFLT)(i - mixin[n].table->x0));
521 }
522
523 static SNDFILE *MXsndgetset(CSOUND *csound, inputs *ddd)
524 {
525 SNDFILE *infd;
526 MYFLT dur;
527 SOUNDIN *p;
528
529 csound->SetUtilSr(csound, FL(0.0)); /* set esr 0. with no orchestra */
530 ddd->p = p = (SOUNDIN *) csound->Calloc(csound, sizeof(SOUNDIN));
531 p->analonly = 1;
532 p->channel = ALLCHNLS;
533 p->skiptime = FL(0.0);
534 strNcpy(p->sfname, ddd->name, MAXSNDNAME-1);
535 /* open sndfil, do skiptime */
536 if (UNLIKELY((infd = csound->sndgetset(csound, p)) == NULL))
537 return NULL;
538 p->getframes = p->framesrem;
539 dur = (MYFLT) p->getframes / p->sr;
540 csound->Message(csound, "%s %" PRId64 " %s (%3.1f secs)\n",
541 Str("mixing"), p->getframes, Str("sample frames"), dur);
542 ddd->fd = infd;
543 return infd;
544 }
545
546 static void MixSound(MIXER_GLOBALS *pp, int32_t n, SNDFILE *outfd, OPARMS *O)
547 {
548 CSOUND *csound = pp->csound;
549 inputs *mixin = &(pp->mixin[0]);
550 MYFLT *buffer = (MYFLT*) csound->Calloc(csound, sizeof(MYFLT)
551 * 6 * NUMBER_OF_SAMPLES);
552 MYFLT *ibuffer = (MYFLT*) csound->Calloc(csound, sizeof(MYFLT)
553 * 6 * NUMBER_OF_SAMPLES);
554 long read_in;
555 MYFLT tpersample;
556 MYFLT max, min;
557 long lmaxpos, lminpos;
558 int32_t maxtimes, mintimes;
559 long sample = 0;
560 int32_t i, j, k;
561 long bytes = 0;
562 int32_t block = 0;
563 int32_t more_to_read = 1;
564 int32_t size;
565 int32_t this_block;
566 int32_t outputs = pp->outputs;
567
568 tpersample = FL(1.0)/(MYFLT)mixin[0].p->sr;
569 max = FL(0.0); lmaxpos = 0; maxtimes = 0;
570 min = FL(0.0); lminpos = 0; mintimes = 0;
571 while (more_to_read) {
572 more_to_read = 0;
573 size = NUMBER_OF_SAMPLES;
574 for (i = 0; i < n; i++)
575 if (mixin[i].start > sample && mixin[i].start - sample < size)
576 size = mixin[i].start - sample;
577 /* for (j=0; j<size*outputs; j++) buffer[j] = FL(0.0); */
578 memset(buffer, 0, sizeof(MYFLT)*size*outputs);
579 this_block = 0;
580 for (i = 0; i<n; i++) {
581 if (sample >= mixin[i].start) {
582 read_in = csound->getsndin(csound, mixin[i].fd, ibuffer,
583 size*mixin[i].p->nchanls, mixin[i].p);
584 if (csound->Get0dBFS(csound)!=FL(1.0)) { /* Optimisation? */
585 MYFLT xx = 1.0/csound->Get0dBFS(csound);
586 for(j=0; j < read_in; j++)
587 ibuffer[j] *= xx;
588 }
589 read_in /= mixin[i].p->nchanls;
590 if (read_in > this_block) this_block = read_in;
591 if (mixin[i].non_clear) {
592 for (k = 1; k<=mixin[i].p->nchanls; k++)
593 if (mixin[i].channels[k]) {
594 for (j=0; j<read_in; j++) {
595 buffer[j*outputs+mixin[i].channels[k]-1] +=
596 ibuffer[j*outputs+k-1] *
597 gain(pp, i, sample + j + mixin[i].channels[k] - 1);
598 }
599 }
600 mixin[i].fulltable = mixin[i].table;
601 }
602 else {
603 for (k = 1; k<=mixin[i].p->nchanls; k++) {
604 for (j=0; j<read_in; j++) {
605 buffer[j*outputs+k-1] +=
606 ibuffer[j*outputs + k - 1] * gain(pp, i, sample + j + k - 1);
607 }
608 }
609 mixin[i].fulltable = mixin[i].table;
610 }
611 if (read_in < size) {
612 mixin[i].start = 0x7ffffff;
613 }
614 else more_to_read++;
615 }
616 else if (mixin[i].start > sample && mixin[i].start != 0x7ffffff)
617 more_to_read++;
618 }
619 for (j = 0; j < this_block * outputs; j++) {
620 if (UNLIKELY(buffer[j] > 1.0 || buffer[j] < -(1.0)))
621 pp->outrange++;
622 if (buffer[j] == max) maxtimes++;
623 if (buffer[j] == min) mintimes++;
624 if (buffer[j] > max) max = buffer[j], lmaxpos = sample+j, maxtimes=1;
625 if (buffer[j] < min) min = buffer[j], lminpos = sample+j, mintimes=1;
626 }
627 sf_write_MYFLT(outfd, buffer, this_block * outputs);
628 block++;
629 bytes += O->sfsampsize * this_block * outputs;
630 switch (O->heartbeat) {
631 case 1:
632 csound->MessageS(csound, CSOUNDMSG_REALTIME, "%c\b", "|/-\\"[block&3]);
633 break;
634 case 2:
635 csound->MessageS(csound, CSOUNDMSG_REALTIME, ".");
636 break;
637 case 3:
638 {
639 int32_t n;
640 csound->MessageS(csound, CSOUNDMSG_REALTIME, "%d%n", block, &n);
641 while (n--) csound->MessageS(csound, CSOUNDMSG_REALTIME, "\b");
642 }
643 break;
644 case 4:
645 csound->MessageS(csound, CSOUNDMSG_REALTIME, "\007");
646 break;
647 }
648 sample += size;
649 }
650 csound->rewriteheader((struct SNFDILE*)outfd);
651 min *= (DFLT_DBFS);
652 max *= (DFLT_DBFS);
653 csound->Message(csound, Str("Max val %d at index %ld (time %.4f, chan %d) "
654 "%d times\n"),
655 (int32_t) max, lmaxpos, tpersample * (lmaxpos/outputs),
656 (int32_t) lmaxpos % outputs, maxtimes);
657 csound->Message(csound, Str("Min val %d at index %ld (time %.4f, chan %d) "
658 "%d times\n"),
659 (int32_t) min, lminpos, tpersample * (lminpos/outputs),
660 (int32_t) lminpos % outputs, mintimes);
661 if (UNLIKELY(pp->outrange))
662 csound->Message(csound, Str("%d sample%s out of range\n"),
663 pp->outrange, (pp->outrange == 1 ? "" : "s"));
664 else
665 csound->Message(csound, Str("Max scale factor = %.3f\n"),
666 DFLT_DBFS / ((max > -min) ? max : -min));
667 }
668
669 /* module interface */
670
671 int32_t mixer_init_(CSOUND *csound)
672 {
673 char buf[128];
674 int32_t retval = csound->AddUtility(csound, "mixer", mixer_main);
675
676 snprintf(buf, 128, Str("Mixes sound files (max. %d)"),
677 (int32_t) NUMBER_OF_FILES);
678 if (!retval) {
679 retval = csound->SetUtilityDescription(csound, "mixer", buf);
680 }
681 return retval;
682 }
683