1 /*
2 libsnd_u.c:
3
4 Copyright (C) 2005 Barry Vercoe, John ffitch, Istvan Varga
5
6 This file is part of Csound.
7
8 The Csound Library is free software; you can redistribute it
9 and/or modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 Csound is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with Csound; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 02110-1301 USA
22 */
23
24 #include "csoundCore.h"
25 #include "soundio.h"
26 #include <sndfile.h>
27
rewriteheader(void * ofd)28 void rewriteheader(void *ofd)
29 {
30 if (LIKELY(ofd != NULL))
31 sf_command((SNDFILE *)ofd, SFC_UPDATE_HEADER_NOW, NULL, 0);
32 }
33
34 /* Stand-Alone sndgetset() */
35 /* used by SoundAnal progs */
36 /* Returns NULL on failure */
37
SAsndgetset(CSOUND * csound,char * infilnam,void * ap_,MYFLT * abeg_time,MYFLT * ainput_dur,MYFLT * asr,int channel)38 void *SAsndgetset(CSOUND *csound, char *infilnam, void *ap_,
39 MYFLT *abeg_time, MYFLT *ainput_dur, MYFLT *asr,
40 int channel)
41 {
42 SOUNDIN **ap = (SOUNDIN**) ap_;
43 SOUNDIN *p;
44 SNDFILE *infile = NULL;
45
46 csound->esr = FL(0.0); /* set esr 0. with no orchestra */
47 *ap = p = (SOUNDIN*) csound->Calloc(csound, sizeof(SOUNDIN));
48 strNcpy(p->sfname, infilnam, 512); //p->sfname[511] = '\0';
49 if (UNLIKELY(channel < 1 && channel != ALLCHNLS)) {
50 csound->Message(csound, Str("channel request %d illegal\n"), channel);
51 csound->Free(csound, p);
52 *ap = NULL;
53 return NULL;
54 }
55 p->channel = channel;
56 p->analonly = 1;
57 p->sr = (int) (*asr + FL(0.5));
58 p->skiptime = *abeg_time;
59 if ((infile = sndgetset(csound, p)) == NULL) /* open sndfil, do skiptime */
60 return(NULL);
61 if (UNLIKELY(p->framesrem < (int64_t) 0)) {
62 csound->Warning(csound, Str("undetermined file length, "
63 "will attempt requested duration"));
64 }
65 else {
66 if (*ainput_dur <= FL(0.0)) { /* 0 durtim, use to EOF */
67 p->getframes = p->framesrem;
68 *ainput_dur = (MYFLT) ((double) p->getframes / (double) p->sr);
69 }
70 /* else chk that input dur is within filetime rem */
71 else {
72 p->getframes = (int64_t) ((double) p->sr * (double) *ainput_dur + 0.5);
73 if (UNLIKELY(p->getframes > p->framesrem)) {
74 p->getframes = p->framesrem;
75 csound->Warning(csound, Str("full requested duration not available"));
76 }
77 }
78 csound->Message(csound, Str("analysing %ld sample frames (%3.1f secs)"),
79 (long) p->getframes, *ainput_dur);
80 if (*abeg_time != FL(0.0))
81 csound->Message(csound, Str(" from timepoint %3.1f\n"), *abeg_time);
82 else
83 csound->Message(csound, "\n");
84 }
85 return (void*) infile;
86 }
87
88 /* special handling of sound input to accomodate reads thru pipes & net
89 * where nbytes rcvd can be < n requested
90 *
91 * extra arg passed for filetyp testing on POST-HEADER reads of audio samples
92 */
sreadin(CSOUND * csound,SNDFILE * infd,MYFLT * inbuf,int nsamples,SOUNDIN * p)93 static int sreadin(CSOUND *csound, SNDFILE *infd, MYFLT *inbuf,
94 int nsamples, SOUNDIN *p)
95 {
96 /* return the number of samples read */
97 int n, ntot = 0;
98 do {
99 n = sf_read_MYFLT(infd, inbuf + ntot, nsamples - ntot);
100 if (UNLIKELY(n < 0))
101 csound->Die(csound, Str("soundfile read error"));
102 } while (n > 0 && (ntot += n) < nsamples);
103 if (p->audrem > (int64_t) 0) {
104 if ((int64_t) ntot > p->audrem) /* chk haven't exceeded */
105 ntot = (int) p->audrem; /* limit of audio data */
106 p->audrem -= (int64_t) ntot;
107 return ntot;
108 }
109 return 0;
110 }
111
112 /* core of soundinset */
113 /* called from sndinset, SAsndgetset, & gen01 */
114 /* Return NULL on failure */
115
sndgetset(CSOUND * csound,void * p_)116 void *sndgetset(CSOUND *csound, void *p_)
117 {
118 SOUNDIN *p = (SOUNDIN*) p_;
119 int n;
120 int framesinbuf, skipframes;
121 char *sfname;
122 SF_INFO sfinfo;
123
124 sfname = &(p->sfname[0]);
125 /* IV - Feb 26 2005: should initialise sfinfo structure */
126 memset(&sfinfo, 0, sizeof(SF_INFO));
127 sfinfo.format = (p->format<0 ? /* store default sample format, */
128 ((int) FORMAT2SF(-p->format) | SF_FORMAT_RAW) : 0);
129 sfinfo.channels = 1; /* number of channels, */
130 if (p->analonly) /* and sample rate */
131 sfinfo.samplerate = (int) p->sr;
132 else
133 sfinfo.samplerate = (int) ((double) csound->esr + 0.5);
134 if (sfinfo.samplerate < 1)
135 sfinfo.samplerate = (int) ((double) DFLT_SR + 0.5);
136 /* open with full dir paths */
137 p->fd = csound->FileOpen2(csound, &(p->sinfd), CSFILE_SND_R,
138 sfname, &sfinfo, "SFDIR;SSDIR",
139 CSFTYPE_UNKNOWN_AUDIO, 0);
140 if (UNLIKELY(p->fd == NULL)) {
141 csound->ErrorMsg(csound, Str("soundin cannot open %s: %s"),
142 sfname, sf_strerror(NULL));
143 goto err_return;
144 }
145 /* & record fullpath filnam */
146 sfname = csound->GetFileName(p->fd);
147
148 /* copy type from headata */
149 p->format = SF2FORMAT(sfinfo.format);
150 p->sampframsiz = (int) sfsampsize(sfinfo.format) * (int) sfinfo.channels;
151 p->nchanls = sfinfo.channels;
152 framesinbuf = (int) SNDINBUFSIZ / (int) p->nchanls;
153 p->bufsmps = framesinbuf * p->nchanls;
154 p->endfile = 0;
155 p->filetyp = SF2TYPE(sfinfo.format);
156 if (p->analonly) { /* anal: if sr param val */
157 if (p->sr != 0 && p->sr != sfinfo.samplerate) { /* use it */
158 csound->Warning(csound, Str("-s %d overriding soundfile sr %d"),
159 (int) p->sr, (int) sfinfo.samplerate);
160 sfinfo.samplerate = p->sr;
161 }
162 }
163 else if (UNLIKELY(sfinfo.samplerate != (int) ((double) csound->esr + 0.5))) {
164 csound->Warning(csound, /* non-anal: cmp w. esr */
165 "%s sr = %d, orch sr = %7.1f",
166 sfname, (int) sfinfo.samplerate, csound->esr);
167 }
168 if (UNLIKELY(p->channel != ALLCHNLS && p->channel > sfinfo.channels)) {
169 csound->ErrorMsg(csound, Str("error: req chan %d, file %s has only %d"),
170 (int) p->channel, sfname, (int) sfinfo.channels);
171 goto err_return;
172 }
173 p->sr = (int) sfinfo.samplerate;
174 if (csound->oparms_.msglevel & 3) {
175 csound->Message(csound, Str("audio sr = %d, "), (int) p->sr);
176 switch (p->nchanls) {
177 case 1: csound->Message(csound, Str("monaural")); break;
178 case 2: csound->Message(csound, Str("stereo")); break;
179 case 4: csound->Message(csound, Str("quad")); break;
180 case 6: csound->Message(csound, Str("hex")); break;
181 case 8: csound->Message(csound, Str("oct")); break;
182 default: csound->Message(csound, Str("%d-channels"), (int) p->nchanls);
183 }
184 if (p->nchanls > 1) {
185 if (p->channel == ALLCHNLS)
186 csound->Message(csound, Str(", reading %s channels"),
187 (p->nchanls == 2 ? Str("both") : Str("all")));
188 else
189 csound->Message(csound, Str(", reading channel %d"),
190 (int) p->channel);
191 }
192 csound->Message(csound, Str("\nopening %s infile %s\n"),
193 type2string(p->filetyp), sfname);
194 }
195 p->audrem = (int64_t) sfinfo.frames * (int64_t) sfinfo.channels;
196 p->framesrem = (int64_t) sfinfo.frames; /* find frames rem */
197 skipframes = (int) ((double) p->skiptime * (double) p->sr
198 + (p->skiptime >= FL(0.0) ? 0.5 : -0.5));
199 if (skipframes < 0) {
200 n = -skipframes;
201 if (UNLIKELY(n > framesinbuf)) {
202 csound->ErrorMsg(csound, Str("soundin: invalid skip time"));
203 goto err_return;
204 }
205 n *= (int) sfinfo.channels;
206 p->inbufp = &(p->inbuf[0]);
207 p->bufend = p->inbufp;
208 do {
209 *(p->bufend++) = FL(0.0);
210 } while (--n);
211 }
212 else if (skipframes < framesinbuf) { /* if sound within 1st buf */
213 n = sreadin(csound, p->sinfd, p->inbuf, p->bufsmps, p);
214 p->bufend = &(p->inbuf[0]) + n;
215 p->inbufp = &(p->inbuf[0]) + (skipframes * (int) sfinfo.channels);
216 if (p->inbufp >= p->bufend) {
217 p->inbufp = p->bufend;
218 p->audrem = (int64_t) 0;
219 p->endfile = 1;
220 }
221 }
222 else if ((int64_t) skipframes >= p->framesrem) {
223 n = framesinbuf * (int) sfinfo.channels;
224 p->inbufp = &(p->inbuf[0]);
225 p->bufend = p->inbufp;
226 do {
227 *(p->bufend++) = FL(0.0);
228 } while (--n);
229 p->audrem = (int64_t) 0;
230 p->endfile = 1;
231 }
232 else { /* for greater skiptime: */
233 /* else seek to bndry */
234 if (UNLIKELY(sf_seek(p->sinfd, (sf_count_t) skipframes, SEEK_SET) < 0)) {
235 csound->ErrorMsg(csound, Str("soundin seek error"));
236 goto err_return;
237 }
238 /* now rd fulbuf */
239 if ((n = sreadin(csound, p->sinfd, p->inbuf, p->bufsmps, p)) == 0)
240 p->endfile = 1;
241 p->inbufp = p->inbuf;
242 p->bufend = p->inbuf + n;
243 }
244 if (p->framesrem != (int64_t) -1)
245 p->framesrem -= (int64_t) skipframes; /* sampleframes to EOF */
246
247 return p->sinfd; /* return the active fd */
248
249 err_return:
250 if (p->fd != NULL)
251 csound->FileClose(csound, p->fd);
252 p->sinfd = NULL;
253 p->fd = NULL;
254 return NULL;
255 }
256
257 /* a simplified soundin */
258
getsndin(CSOUND * csound,void * fd_,MYFLT * fp,int nlocs,void * p_)259 int getsndin(CSOUND *csound, void *fd_, MYFLT *fp, int nlocs, void *p_)
260 {
261 SNDFILE *fd = (SNDFILE*) fd_;
262 SOUNDIN *p = (SOUNDIN*) p_;
263 int i = 0, n;
264 MYFLT scalefac;
265
266 if (p->format == AE_FLOAT || p->format == AE_DOUBLE) {
267 if (p->filetyp == TYP_WAV || p->filetyp == TYP_AIFF ||
268 p->filetyp == TYP_W64)
269 scalefac = csound->e0dbfs;
270 else
271 scalefac = FL(1.0);
272 if (p->do_floatscaling)
273 scalefac *= p->fscalefac;
274 }
275 else
276 scalefac = csound->e0dbfs;
277
278 if (p->nchanls == 1 || p->channel == ALLCHNLS) { /* MONO or ALLCHNLS */
279 for ( ; i < nlocs; i++) {
280 if (p->inbufp >= p->bufend) {
281 if ((n = sreadin(csound, fd, p->inbuf, p->bufsmps, p)) <= 0)
282 break;
283 p->inbufp = p->inbuf;
284 p->bufend = p->inbuf + n;
285 }
286 fp[i] = *p->inbufp++ * scalefac;
287 }
288 }
289 else { /* MULTI-CHANNEL, SELECT ONE */
290 int chcnt;
291 for ( ; i < nlocs; i++) {
292 if (p->inbufp >= p->bufend) {
293 if ((n = sreadin(csound, fd, p->inbuf, p->bufsmps, p)) <= 0)
294 break;
295 p->inbufp = p->inbuf;
296 p->bufend = p->inbuf + n;
297 }
298 chcnt = 0;
299 do {
300 if (++chcnt == p->channel)
301 fp[i] = *p->inbufp * scalefac;
302 p->inbufp++;
303 } while (chcnt < p->nchanls);
304 }
305 }
306
307 n = i;
308 memset(&(fp[i]), 0, (nlocs-i)*sizeof(MYFLT)); /* if incomplete PAD */
309 /* for ( ; i < nlocs; i++) /\* if incomplete *\/ */
310 /* fp[i] = FL(0.0); /\* pad with 0's *\/ */
311 return n;
312 }
313
dbfs_init(CSOUND * csound,MYFLT dbfs)314 void dbfs_init(CSOUND *csound, MYFLT dbfs)
315 {
316 csound->dbfs_to_float = FL(1.0) / dbfs;
317 csound->e0dbfs = dbfs;
318 /* probably want this message written just before note messages start... */
319 csound->Message(csound, Str("0dBFS level = %.1f\n"), dbfs);
320 }
321
type2string(int x)322 char *type2string(int x)
323 {
324 switch (x) {
325 case TYP_WAV: return "WAV";
326 case TYP_AIFF: return "AIFF";
327 case TYP_AU: return "AU";
328 case TYP_RAW: return "RAW";
329 case TYP_PAF: return "PAF";
330 case TYP_SVX: return "SVX";
331 case TYP_NIST: return "NIST";
332 case TYP_VOC: return "VOC";
333 case TYP_IRCAM: return "IRCAM";
334 case TYP_W64: return "W64";
335 case TYP_MAT4: return "MAT4";
336 case TYP_MAT5: return "MAT5";
337 case TYP_PVF: return "PVF";
338 case TYP_XI: return "XI";
339 case TYP_HTK: return "HTK";
340 case TYP_SDS: return "SDS";
341 case TYP_SD2: return "SD2";
342 case TYP_FLAC: return "FLAC";
343 case TYP_CAF: return "CAF";
344 case TYP_WVE: return "WVE";
345 case TYP_OGG: return "OGG";
346 case TYP_MPC2K: return "MPC2K";
347 case TYP_RF64: return "RF64";
348 default: return Str("unknown");
349 }
350 }
351
sfsampsize(int type)352 int sfsampsize(int type)
353 {
354 switch (type & SF_FORMAT_SUBMASK) {
355 case SF_FORMAT_PCM_16: return 2; /* Signed 16 bit data */
356 case SF_FORMAT_PCM_32: return 4; /* Signed 32 bit data */
357 case SF_FORMAT_FLOAT: return 4; /* 32 bit float data */
358 case SF_FORMAT_PCM_24: return 3; /* Signed 24 bit data */
359 case SF_FORMAT_DOUBLE: return 8; /* 64 bit float data */
360 }
361 return 1;
362 }
363
getstrformat(int format)364 char *getstrformat(int format) /* used here, and in sfheader.c */
365 {
366 switch (format) {
367 case AE_UNCH: return Str("unsigned bytes"); /* J. Mohr 1995 Oct 17 */
368 case AE_CHAR: return Str("signed chars");
369 case AE_ALAW: return Str("alaw bytes");
370 case AE_ULAW: return Str("ulaw bytes");
371 case AE_SHORT: return Str("shorts");
372 case AE_LONG: return Str("longs");
373 case AE_FLOAT: return Str("floats");
374 case AE_DOUBLE: return Str("double floats");
375 case AE_24INT: return Str("24bit ints"); /* RWD 5:2001 */
376 case AE_VORBIS: return Str("vorbis encoding");
377 }
378 return Str("unknown");
379 }
380
381 /* type should be one of Csound's TYP_XXX macros,
382 encoding should be one of its AE_XXX macros. */
type2csfiletype(int type,int encoding)383 int type2csfiletype(int type, int encoding)
384 {
385 switch (type) {
386 case TYP_RAW: return CSFTYPE_RAW_AUDIO;
387 case TYP_IRCAM: return CSFTYPE_IRCAM;
388 case TYP_AIFF:
389 switch (encoding) {
390 case AE_CHAR:
391 case AE_SHORT:
392 case AE_24INT:
393 case AE_LONG:
394 return CSFTYPE_AIFF;
395 default: return CSFTYPE_AIFC;
396 }
397 case TYP_WAV: return CSFTYPE_WAVE;
398 case TYP_AU: return CSFTYPE_AU;
399 case TYP_W64: return CSFTYPE_W64;
400 case TYP_WAVEX: return CSFTYPE_WAVEX;
401 case TYP_AVR: return CSFTYPE_AVR;
402 case TYP_HTK: return CSFTYPE_HTK;
403 case TYP_MAT4: return CSFTYPE_MAT4;
404 case TYP_MAT5: return CSFTYPE_MAT5;
405 case TYP_NIST: return CSFTYPE_NIST;
406 case TYP_PAF: return CSFTYPE_PAF;
407 case TYP_PVF: return CSFTYPE_PVF;
408 case TYP_SVX: return CSFTYPE_SVX;
409 case TYP_VOC: return CSFTYPE_VOC;
410 case TYP_XI: return CSFTYPE_XI;
411 case TYP_SDS: return CSFTYPE_SDS;
412 case TYP_SD2: return CSFTYPE_SD2;
413 case TYP_FLAC: return CSFTYPE_FLAC;
414 case TYP_CAF: return CSFTYPE_CAF;
415 case TYP_WVE: return CSFTYPE_WVE;
416 case TYP_OGG: return CSFTYPE_OGG;
417 case TYP_MPC2K: return CSFTYPE_MPC2K;
418 case TYP_RF64: return CSFTYPE_RF64;
419 default: return CSFTYPE_UNKNOWN_AUDIO;
420 }
421 }
422
423 /* type should be one of libsndfile's format values. */
sftype2csfiletype(int type)424 int sftype2csfiletype(int type)
425 {
426 /* mask out the endian-ness bits */
427 int typemod = type & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK);
428 return type2csfiletype(SF2TYPE(typemod), SF2FORMAT(typemod));
429 }
430