Fix some greedy sed changes in imported code. Also provide a sys/types.h for compatib...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / d_soundfile.c
blob67a80c9d3a4af809dc66a5284488b394e022db61
1 /* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5 /* this file contains, first, a collection of soundfile access routines, a
6 sort of soundfile library. Second, the "soundfiler" object is defined which
7 uses the routines to read or write soundfiles, synchronously, from garrays.
8 These operations are not to be done in "real time" as they may have to wait
9 for disk accesses (even the write routine.) Finally, the realtime objects
10 readsf~ and writesf~ are defined which confine disk operations to a separate
11 thread so that they can be used in real time. The readsf~ and writesf~
12 objects use Posix-like threads. */
14 #ifdef ROCKBOX
15 #include "plugin.h"
16 #include "../../pdbox.h"
17 #else /* ROCKBOX */
18 #ifdef UNIX
19 #include <unistd.h>
20 #include <fcntl.h>
21 #endif
22 #include <pthread.h>
23 #ifdef MSW
24 #include <io.h>
25 #endif
26 #include <stdio.h>
27 #include <string.h>
28 #include <errno.h>
29 #endif /* ROCKBOX */
31 #include "m_pd.h"
33 #define MAXSFCHANS 64
35 /***************** soundfile header structures ************************/
37 typedef unsigned short uint16;
38 typedef unsigned long uint32;
40 #define FORMAT_WAVE 0
41 #define FORMAT_AIFF 1
42 #define FORMAT_NEXT 2
44 /* the NeXTStep sound header structure; can be big or little endian */
46 typedef struct _nextstep
48 char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
49 uint32 ns_onset; /* byte offset of first sample */
50 uint32 ns_length; /* length of sound in bytes */
51 uint32 ns_format; /* format; see below */
52 uint32 ns_sr; /* sample rate */
53 uint32 ns_nchans; /* number of channels */
54 char ns_info[4]; /* comment */
55 } t_nextstep;
57 #define NS_FORMAT_LINEAR_16 3
58 #define NS_FORMAT_LINEAR_24 4
59 #define NS_FORMAT_FLOAT 6
60 #define SCALE (1./(1024. * 1024. * 1024. * 2.))
62 /* the WAVE header. All Wave files are little endian. We assume
63 the "fmt" chunk comes first which is usually the case but perhaps not
64 always; same for AIFF and the "COMM" chunk. */
66 typedef unsigned word;
67 typedef unsigned long dword;
69 typedef struct _wave
71 char w_fileid[4]; /* chunk id 'RIFF' */
72 uint32 w_chunksize; /* chunk size */
73 char w_waveid[4]; /* wave chunk id 'WAVE' */
74 char w_fmtid[4]; /* format chunk id 'fmt ' */
75 uint32 w_fmtchunksize; /* format chunk size */
76 uint16 w_fmttag; /* format tag (WAV_INT etc) */
77 uint16 w_nchannels; /* number of channels */
78 uint32 w_samplespersec; /* sample rate in hz */
79 uint32 w_navgbytespersec; /* average bytes per second */
80 uint16 w_nblockalign; /* number of bytes per frame */
81 uint16 w_nbitspersample; /* number of bits in a sample */
82 char w_datachunkid[4]; /* data chunk id 'data' */
83 uint32 w_datachunksize; /* length of data chunk */
84 } t_wave;
86 typedef struct _fmt /* format chunk */
88 uint16 f_fmttag; /* format tag, 1 for PCM */
89 uint16 f_nchannels; /* number of channels */
90 uint32 f_samplespersec; /* sample rate in hz */
91 uint32 f_navgbytespersec; /* average bytes per second */
92 uint16 f_nblockalign; /* number of bytes per frame */
93 uint16 f_nbitspersample; /* number of bits in a sample */
94 } t_fmt;
96 typedef struct _wavechunk /* ... and the last two items */
98 char wc_id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */
99 uint32 wc_size; /* length of data chunk */
100 } t_wavechunk;
102 #define WAV_INT 1
103 #define WAV_FLOAT 3
105 /* the AIFF header. I'm assuming AIFC is compatible but don't really know
106 that. */
108 typedef struct _datachunk
110 char dc_id[4]; /* data chunk id 'SSND' */
111 uint32 dc_size; /* length of data chunk */
112 } t_datachunk;
114 typedef struct _comm
116 uint16 c_nchannels; /* number of channels */
117 uint16 c_nframeshi; /* # of sample frames (hi) */
118 uint16 c_nframeslo; /* # of sample frames (lo) */
119 uint16 c_bitspersamp; /* bits per sample */
120 unsigned char c_samprate[10]; /* sample rate, 80-bit float! */
121 } t_comm;
123 /* this version is more convenient for writing them out: */
124 typedef struct _aiff
126 char a_fileid[4]; /* chunk id 'FORM' */
127 uint32 a_chunksize; /* chunk size */
128 char a_aiffid[4]; /* aiff chunk id 'AIFF' */
129 char a_fmtid[4]; /* format chunk id 'COMM' */
130 uint32 a_fmtchunksize; /* format chunk size, 18 */
131 uint16 a_nchannels; /* number of channels */
132 uint16 a_nframeshi; /* # of sample frames (hi) */
133 uint16 a_nframeslo; /* # of sample frames (lo) */
134 uint16 a_bitspersamp; /* bits per sample */
135 unsigned char a_samprate[10]; /* sample rate, 80-bit float! */
136 } t_aiff;
138 #define AIFFHDRSIZE 38 /* probably not what sizeof() gives */
141 #define AIFFPLUS (AIFFHDRSIZE + 8) /* header size including first chunk hdr */
143 #define WHDR1 sizeof(t_nextstep)
144 #define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
145 #define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
147 #define READHDRSIZE (16 > WHDR2 + 2 ? 16 : WHDR2 + 2)
149 #define OBUFSIZE MAXPDSTRING /* assume MAXPDSTRING is bigger than headers */
151 #ifdef MSW
152 #include <fcntl.h>
153 #define BINCREATE _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY
154 #else
155 #define BINCREATE O_WRONLY | O_CREAT | O_TRUNC
156 #endif
158 /* this routine returns 1 if the high order byte comes at the lower
159 address on our architecture (big-endianness.). It's 1 for Motorola,
160 0 for Intel: */
162 extern int garray_ambigendian(void);
164 /* byte swappers */
166 static uint32 swap4(uint32 n, int doit)
168 if (doit)
169 return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
170 ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
171 else return (n);
174 static uint16 swap2(uint32 n, int doit)
176 if (doit)
177 return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
178 else return (n);
181 static void swapstring(char *foo, int doit)
183 if (doit)
185 char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
186 foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
190 /******************** soundfile access routines **********************/
192 /* This routine opens a file, looks for either a nextstep or "wave" header,
193 * seeks to end of it, and fills in bytes per sample and number of channels.
194 * Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
195 * are supported. If "headersize" is nonzero, the
196 * caller should supply the number of channels, endinanness, and bytes per
197 * sample; the header is ignored. Otherwise, the routine tries to read the
198 * header and fill in the properties.
201 int open_soundfile(const char *dirname, const char *filename, int headersize,
202 int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
203 long skipframes)
205 char buf[OBUFSIZE], *bufptr;
206 #ifdef ROCKBOX
207 int fd, nchannels, bigendian, bytespersamp, swap, sysrtn;
208 #else
209 int fd, format, nchannels, bigendian, bytespersamp, swap, sysrtn;
210 #endif
211 long bytelimit = 0x7fffffff;
212 #ifndef ROCKBOX
213 errno = 0;
214 #endif
215 fd = open_via_path(dirname, filename,
216 "", buf, &bufptr, MAXPDSTRING, 1);
217 if (fd < 0)
218 return (-1);
219 if (headersize >= 0) /* header detection overridden */
221 bigendian = *p_bigendian;
222 nchannels = *p_nchannels;
223 bytespersamp = *p_bytespersamp;
224 bytelimit = *p_bytelimit;
226 else
228 int bytesread = read(fd, buf, READHDRSIZE);
229 int format;
230 if (bytesread < 4)
231 goto badheader;
232 if (!strncmp(buf, ".snd", 4))
233 format = FORMAT_NEXT, bigendian = 1;
234 else if (!strncmp(buf, "dns.", 4))
235 format = FORMAT_NEXT, bigendian = 0;
236 else if (!strncmp(buf, "RIFF", 4))
238 if (bytesread < 12 || strncmp(buf + 8, "WAVE", 4))
239 goto badheader;
240 format = FORMAT_WAVE, bigendian = 0;
242 else if (!strncmp(buf, "FORM", 4))
244 if (bytesread < 12 || strncmp(buf + 8, "AIFF", 4))
245 goto badheader;
246 format = FORMAT_AIFF, bigendian = 1;
248 else
249 goto badheader;
250 swap = (bigendian != garray_ambigendian());
251 if (format == FORMAT_NEXT) /* nextstep header */
253 #ifndef ROCKBOX
254 uint32 param;
255 #endif
256 if (bytesread < (int)sizeof(t_nextstep))
257 goto badheader;
258 nchannels = swap4(((t_nextstep *)buf)->ns_nchans, swap);
259 format = swap4(((t_nextstep *)buf)->ns_format, swap);
260 headersize = swap4(((t_nextstep *)buf)->ns_onset, swap);
261 if (format == NS_FORMAT_LINEAR_16)
262 bytespersamp = 2;
263 else if (format == NS_FORMAT_LINEAR_24)
264 bytespersamp = 3;
265 else if (format == NS_FORMAT_FLOAT)
266 bytespersamp = 4;
267 else goto badheader;
268 bytelimit = 0x7fffffff;
270 else if (format == FORMAT_WAVE) /* wave header */
272 /* This is awful. You have to skip over chunks,
273 except that if one happens to be a "fmt" chunk, you want to
274 find out the format from that one. The case where the
275 "fmt" chunk comes after the audio isn't handled. */
276 headersize = 12;
277 if (bytesread < 20)
278 goto badheader;
279 /* First we guess a number of channels, etc., in case there's
280 no "fmt" chunk to follow. */
281 nchannels = 1;
282 bytespersamp = 2;
283 /* copy the first chunk header to beginnning of buffer. */
284 memcpy(buf, buf + headersize, sizeof(t_wavechunk));
285 /* post("chunk %c %c %c %c",
286 ((t_wavechunk *)buf)->wc_id[0],
287 ((t_wavechunk *)buf)->wc_id[1],
288 ((t_wavechunk *)buf)->wc_id[2],
289 ((t_wavechunk *)buf)->wc_id[3]); */
290 /* read chunks in loop until we get to the data chunk */
291 while (strncmp(((t_wavechunk *)buf)->wc_id, "data", 4))
293 long chunksize = swap4(((t_wavechunk *)buf)->wc_size,
294 swap), seekto = headersize + chunksize + 8, seekout;
296 if (!strncmp(((t_wavechunk *)buf)->wc_id, "fmt ", 4))
298 long commblockonset = headersize + 8;
299 seekout = lseek(fd, commblockonset, SEEK_SET);
300 if (seekout != commblockonset)
301 goto badheader;
302 if (read(fd, buf, sizeof(t_fmt)) < (int) sizeof(t_fmt))
303 goto badheader;
304 nchannels = swap2(((t_fmt *)buf)->f_nchannels, swap);
305 format = swap2(((t_fmt *)buf)->f_nbitspersample, swap);
306 if (format == 16)
307 bytespersamp = 2;
308 else if (format == 24)
309 bytespersamp = 3;
310 else if (format == 32)
311 bytespersamp = 4;
312 else goto badheader;
314 seekout = lseek(fd, seekto, SEEK_SET);
315 if (seekout != seekto)
316 goto badheader;
317 if (read(fd, buf, sizeof(t_wavechunk)) <
318 (int) sizeof(t_wavechunk))
319 goto badheader;
320 /* post("new chunk %c %c %c %c at %d",
321 ((t_wavechunk *)buf)->wc_id[0],
322 ((t_wavechunk *)buf)->wc_id[1],
323 ((t_wavechunk *)buf)->wc_id[2],
324 ((t_wavechunk *)buf)->wc_id[3], seekto); */
325 headersize = seekto;
327 bytelimit = swap4(((t_wavechunk *)buf)->wc_size, swap);
328 headersize += 8;
330 else
332 /* AIFF. same as WAVE; actually predates it. Disgusting. */
333 headersize = 12;
334 if (bytesread < 20)
335 goto badheader;
336 /* First we guess a number of channels, etc., in case there's
337 no COMM block to follow. */
338 nchannels = 1;
339 bytespersamp = 2;
340 /* copy the first chunk header to beginnning of buffer. */
341 memcpy(buf, buf + headersize, sizeof(t_datachunk));
342 /* read chunks in loop until we get to the data chunk */
343 while (strncmp(((t_datachunk *)buf)->dc_id, "SSND", 4))
345 long chunksize = swap4(((t_datachunk *)buf)->dc_size,
346 swap), seekto = headersize + chunksize + 8, seekout;
347 /* post("chunk %c %c %c %c seek %d",
348 ((t_datachunk *)buf)->dc_id[0],
349 ((t_datachunk *)buf)->dc_id[1],
350 ((t_datachunk *)buf)->dc_id[2],
351 ((t_datachunk *)buf)->dc_id[3], seekto); */
352 if (!strncmp(((t_datachunk *)buf)->dc_id, "COMM", 4))
354 long commblockonset = headersize + 8;
355 seekout = lseek(fd, commblockonset, SEEK_SET);
356 if (seekout != commblockonset)
357 goto badheader;
358 if (read(fd, buf, sizeof(t_comm)) <
359 (int) sizeof(t_comm))
360 goto badheader;
361 nchannels = swap2(((t_comm *)buf)->c_nchannels, swap);
362 format = swap2(((t_comm *)buf)->c_bitspersamp, swap);
363 if (format == 16)
364 bytespersamp = 2;
365 else if (format == 24)
366 bytespersamp = 3;
367 else goto badheader;
369 seekout = lseek(fd, seekto, SEEK_SET);
370 if (seekout != seekto)
371 goto badheader;
372 if (read(fd, buf, sizeof(t_datachunk)) <
373 (int) sizeof(t_datachunk))
374 goto badheader;
375 headersize = seekto;
377 bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap);
378 headersize += 8;
381 /* seek past header and any sample frames to skip */
382 sysrtn = lseek(fd, nchannels * bytespersamp * skipframes + headersize, 0);
383 if (sysrtn != nchannels * bytespersamp * skipframes + headersize)
384 return (-1);
385 bytelimit -= nchannels * bytespersamp * skipframes;
386 if (bytelimit < 0)
387 bytelimit = 0;
388 /* copy sample format back to caller */
389 *p_bigendian = bigendian;
390 *p_nchannels = nchannels;
391 *p_bytespersamp = bytespersamp;
392 *p_bytelimit = bytelimit;
393 return (fd);
394 badheader:
395 /* the header wasn't recognized. We're threadable here so let's not
396 print out the error... */
397 #ifndef ROCKBOX
398 errno = EIO;
399 #endif
400 return (-1);
403 static void soundfile_xferin(int sfchannels, int nvecs, t_sample **vecs,
404 long itemsread, unsigned char *buf, int nitems, int bytespersamp,
405 int bigendian)
407 int i, j;
408 unsigned char *sp, *sp2;
409 t_sample *fp;
410 int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
411 int bytesperframe = bytespersamp * sfchannels;
412 for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
414 if (bytespersamp == 2)
416 if (bigendian)
418 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
419 j < nitems; j++, sp2 += bytesperframe, fp++)
420 *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
422 else
424 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
425 j < nitems; j++, sp2 += bytesperframe, fp++)
426 *fp = ((short*)sp2)[0]<<(fix1-16);
429 else if (bytespersamp == 3)
431 if (bigendian)
433 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
434 j < nitems; j++, sp2 += bytesperframe, fp++)
435 *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
436 | (sp2[2] << 8));
438 else
440 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
441 j < nitems; j++, sp2 += bytesperframe, fp++)
442 *fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
443 | (sp2[0] << 8));
446 else if (bytespersamp == 4)
448 if (bigendian)
450 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
451 j < nitems; j++, sp2 += bytesperframe, fp++)
452 *(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16)
453 | (sp2[2] << 8) | sp2[3]);
455 else
457 for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
458 j < nitems; j++, sp2 += bytesperframe, fp++)
459 *(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16)
460 | (sp2[1] << 8) | sp2[0]);
464 /* zero out other outputs */
465 for (i = sfchannels; i < nvecs; i++)
466 for (j = nitems, fp = vecs[i]; j--; )
467 *fp++ = 0;
471 /* soundfiler_write ...
473 usage: write [flags] filename table ...
474 flags:
475 -nframes <frames>
476 -skip <frames>
477 -bytes <bytes per sample>
478 -normalize
479 -nextstep
480 -wave
481 -big
482 -little
485 /* the routine which actually does the work should LATER also be called
486 from garray_write16. */
489 /* Parse arguments for writing. The "obj" argument is only for flagging
490 errors. For streaming to a file the "normalize", "onset" and "nframes"
491 arguments shouldn't be set but the calling routine flags this. */
493 static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
494 t_symbol **p_filesym,
495 int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
496 int *p_normalize, long *p_onset, long *p_nframes, float *p_rate)
498 int argc = *p_argc;
499 t_atom *argv = *p_argv;
500 int bytespersamp = 2, bigendian = 0,
501 endianness = -1, swap, filetype = -1, normalize = 0;
502 long onset = 0, nframes = 0x7fffffff;
503 t_symbol *filesym;
504 float rate = -1;
506 while (argc > 0 && argv->a_type == A_SYMBOL &&
507 *argv->a_w.w_symbol->s_name == '-')
509 char *flag = argv->a_w.w_symbol->s_name + 1;
510 if (!strcmp(flag, "skip"))
512 if (argc < 2 || argv[1].a_type != A_FLOAT ||
513 ((onset = argv[1].a_w.w_float) < 0))
514 goto usage;
515 argc -= 2; argv += 2;
517 else if (!strcmp(flag, "nframes"))
519 if (argc < 2 || argv[1].a_type != A_FLOAT ||
520 ((nframes = argv[1].a_w.w_float) < 0))
521 goto usage;
522 argc -= 2; argv += 2;
524 else if (!strcmp(flag, "bytes"))
526 if (argc < 2 || argv[1].a_type != A_FLOAT ||
527 ((bytespersamp = argv[1].a_w.w_float) < 2) ||
528 bytespersamp > 4)
529 goto usage;
530 argc -= 2; argv += 2;
532 else if (!strcmp(flag, "normalize"))
534 normalize = 1;
535 argc -= 1; argv += 1;
537 else if (!strcmp(flag, "wave"))
539 filetype = FORMAT_WAVE;
540 argc -= 1; argv += 1;
542 else if (!strcmp(flag, "nextstep"))
544 filetype = FORMAT_NEXT;
545 argc -= 1; argv += 1;
547 else if (!strcmp(flag, "aiff"))
549 filetype = FORMAT_AIFF;
550 argc -= 1; argv += 1;
552 else if (!strcmp(flag, "big"))
554 endianness = 1;
555 argc -= 1; argv += 1;
557 else if (!strcmp(flag, "little"))
559 endianness = 0;
560 argc -= 1; argv += 1;
562 else if (!strcmp(flag, "r") || !strcmp(flag, "rate"))
564 if (argc < 2 || argv[1].a_type != A_FLOAT ||
565 ((rate = argv[1].a_w.w_float) <= 0))
566 goto usage;
567 argc -= 2; argv += 2;
569 else goto usage;
571 if (!argc || argv->a_type != A_SYMBOL)
572 goto usage;
573 filesym = argv->a_w.w_symbol;
575 /* check if format not specified and fill in */
576 if (filetype < 0)
578 if (strlen(filesym->s_name) >= 5 &&
579 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".aif") ||
580 !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".AIF")))
581 filetype = FORMAT_AIFF;
582 if (strlen(filesym->s_name) >= 6 &&
583 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".aiff") ||
584 !strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".AIFF")))
585 filetype = FORMAT_AIFF;
586 if (strlen(filesym->s_name) >= 5 &&
587 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".snd") ||
588 !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".SND")))
589 filetype = FORMAT_NEXT;
590 if (strlen(filesym->s_name) >= 4 &&
591 (!strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".au") ||
592 !strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".AU")))
593 filetype = FORMAT_NEXT;
594 if (filetype < 0)
595 filetype = FORMAT_WAVE;
597 /* don't handle AIFF floating point samples */
598 if (bytespersamp == 4)
600 if (filetype == FORMAT_AIFF)
602 pd_error(obj, "AIFF floating-point file format unavailable");
603 goto usage;
606 /* for WAVE force little endian; for nextstep use machine native */
607 if (filetype == FORMAT_WAVE)
609 bigendian = 0;
610 if (endianness == 1)
611 pd_error(obj, "WAVE file forced to little endian");
613 else if (filetype == FORMAT_AIFF)
615 bigendian = 1;
616 if (endianness == 0)
617 pd_error(obj, "AIFF file forced to big endian");
619 else if (endianness == -1)
621 bigendian = garray_ambigendian();
623 else bigendian = endianness;
624 swap = (bigendian != garray_ambigendian());
626 argc--; argv++;
628 *p_argc = argc;
629 *p_argv = argv;
630 *p_filesym = filesym;
631 *p_filetype = filetype;
632 *p_bytespersamp = bytespersamp;
633 *p_swap = swap;
634 *p_normalize = normalize;
635 *p_onset = onset;
636 *p_nframes = nframes;
637 *p_bigendian = bigendian;
638 *p_rate = rate;
639 return (0);
640 usage:
641 return (-1);
644 static int create_soundfile(t_canvas *canvas, const char *filename,
645 int filetype, int nframes, int bytespersamp,
646 int bigendian, int nchannels, int swap, float samplerate)
648 char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
649 char headerbuf[WRITEHDRSIZE];
650 t_wave *wavehdr = (t_wave *)headerbuf;
651 t_nextstep *nexthdr = (t_nextstep *)headerbuf;
652 t_aiff *aiffhdr = (t_aiff *)headerbuf;
653 int fd, headersize = 0;
655 strncpy(filenamebuf, filename, MAXPDSTRING-10);
656 filenamebuf[MAXPDSTRING-10] = 0;
658 if (filetype == FORMAT_NEXT)
660 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd"))
661 strcat(filenamebuf, ".snd");
662 if (bigendian)
663 strncpy(nexthdr->ns_fileid, ".snd", 4);
664 else strncpy(nexthdr->ns_fileid, "dns.", 4);
665 nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap);
666 nexthdr->ns_length = 0;
667 nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 :
668 (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);
669 nexthdr->ns_sr = swap4(samplerate, swap);
670 nexthdr->ns_nchans = swap4(nchannels, swap);
671 strcpy(nexthdr->ns_info, "Pd ");
672 swapstring(nexthdr->ns_info, swap);
673 headersize = sizeof(t_nextstep);
675 else if (filetype == FORMAT_AIFF)
677 long datasize = nframes * nchannels * bytespersamp;
678 long longtmp;
679 static unsigned char dogdoo[] =
680 {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
681 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
682 strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
683 strcat(filenamebuf, ".aif");
684 strncpy(aiffhdr->a_fileid, "FORM", 4);
685 aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
686 strncpy(aiffhdr->a_aiffid, "AIFF", 4);
687 strncpy(aiffhdr->a_fmtid, "COMM", 4);
688 aiffhdr->a_fmtchunksize = swap4(18, swap);
689 aiffhdr->a_nchannels = swap2(nchannels, swap);
690 longtmp = swap4(nframes, swap);
691 memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
692 aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
693 memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
694 longtmp = swap4(datasize, swap);
695 memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
696 headersize = AIFFPLUS;
698 else /* WAVE format */
700 long datasize = nframes * nchannels * bytespersamp;
701 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
702 strcat(filenamebuf, ".wav");
703 strncpy(wavehdr->w_fileid, "RIFF", 4);
704 wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
705 strncpy(wavehdr->w_waveid, "WAVE", 4);
706 strncpy(wavehdr->w_fmtid, "fmt ", 4);
707 wavehdr->w_fmtchunksize = swap4(16, swap);
708 wavehdr->w_fmttag =
709 swap2((bytespersamp == 4 ? WAV_FLOAT : WAV_INT), swap);
710 wavehdr->w_nchannels = swap2(nchannels, swap);
711 wavehdr->w_samplespersec = swap4(samplerate, swap);
712 wavehdr->w_navgbytespersec =
713 swap4((int)(samplerate * nchannels * bytespersamp), swap);
714 wavehdr->w_nblockalign = swap2(nchannels * bytespersamp, swap);
715 wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
716 strncpy(wavehdr->w_datachunkid, "data", 4);
717 wavehdr->w_datachunksize = swap4(datasize, swap);
718 headersize = sizeof(t_wave);
721 canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING);
722 sys_bashfilename(buf2, buf2);
723 #ifdef ROCKBOX
724 if ((fd = open(buf2, BINCREATE)) < 0)
725 #else
726 if ((fd = open(buf2, BINCREATE, 0666)) < 0)
727 #endif
728 return (-1);
730 if (write(fd, headerbuf, headersize) < headersize)
732 close (fd);
733 return (-1);
735 return (fd);
738 static void soundfile_finishwrite(void *obj, char *filename, int fd,
739 int filetype, long nframes, long itemswritten, int bytesperframe, int swap)
741 if (itemswritten < nframes)
743 if (nframes < 0x7fffffff)
744 pd_error(obj, "soundfiler_write: %d out of %d bytes written",
745 itemswritten, nframes);
746 /* try to fix size fields in header */
747 if (filetype == FORMAT_WAVE)
749 long datasize = itemswritten * bytesperframe, mofo;
751 if (lseek(fd,
752 ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
753 SEEK_SET) == 0)
754 goto baddonewrite;
755 mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
756 if (write(fd, (char *)(&mofo), 4) < 4)
757 goto baddonewrite;
758 if (lseek(fd,
759 ((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0,
760 SEEK_SET) == 0)
761 goto baddonewrite;
762 mofo = swap4(datasize, swap);
763 if (write(fd, (char *)(&mofo), 4) < 4)
764 goto baddonewrite;
766 if (filetype == FORMAT_AIFF)
768 long mofo;
769 if (lseek(fd,
770 ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
771 SEEK_SET) == 0)
772 goto baddonewrite;
773 mofo = swap4(nframes, swap);
774 if (write(fd, (char *)(&mofo), 4) < 4)
775 goto baddonewrite;
777 if (filetype == FORMAT_NEXT)
779 /* do it the lazy way: just set the size field to 'unknown size'*/
780 uint32 nextsize = 0xffffffff;
781 if (lseek(fd, 8, SEEK_SET) == 0)
783 goto baddonewrite;
785 if (write(fd, &nextsize, 4) < 4)
787 goto baddonewrite;
791 return;
792 baddonewrite:
793 #ifdef ROCKBOX
794 post("%s: error", filename);
795 #else
796 post("%s: %s", filename, strerror(errno));
797 #endif
800 static void soundfile_xferout(int nchannels, t_sample **vecs,
801 unsigned char *buf, int nitems, long onset, int bytespersamp,
802 int bigendian, float normalfactor)
804 int i, j;
805 unsigned char *sp, *sp2;
806 t_sample *fp;
807 int bytesperframe = bytespersamp * nchannels;
808 long xx;
809 for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
811 if (bytespersamp == 2)
813 float ff = normalfactor * 32768.;
814 if (bigendian)
816 for (j = 0, sp2 = sp, fp = vecs[i] + onset;
817 j < nitems; j++, sp2 += bytesperframe, fp++)
819 int xx = 32768. + (*fp * ff);
820 xx -= 32768;
821 if (xx < -32767)
822 xx = -32767;
823 if (xx > 32767)
824 xx = 32767;
825 sp2[0] = (xx >> 8);
826 sp2[1] = xx;
829 else
831 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
832 j < nitems; j++, sp2 += bytesperframe, fp++)
834 int xx = 32768. + (*fp * ff);
835 xx -= 32768;
836 if (xx < -32767)
837 xx = -32767;
838 if (xx > 32767)
839 xx = 32767;
840 sp2[1] = (xx >> 8);
841 sp2[0] = xx;
845 else if (bytespersamp == 3)
847 float ff = normalfactor * 8388608.;
848 if (bigendian)
850 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
851 j < nitems; j++, sp2 += bytesperframe, fp++)
853 int xx = 8388608. + (*fp * ff);
854 xx -= 8388608;
855 if (xx < -8388607)
856 xx = -8388607;
857 if (xx > 8388607)
858 xx = 8388607;
859 sp2[0] = (xx >> 16);
860 sp2[1] = (xx >> 8);
861 sp2[2] = xx;
864 else
866 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
867 j < nitems; j++, sp2 += bytesperframe, fp++)
869 int xx = 8388608. + (*fp * ff);
870 xx -= 8388608;
871 if (xx < -8388607)
872 xx = -8388607;
873 if (xx > 8388607)
874 xx = 8388607;
875 sp2[2] = (xx >> 16);
876 sp2[1] = (xx >> 8);
877 sp2[0] = xx;
881 else if (bytespersamp == 4)
883 if (bigendian)
885 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
886 j < nitems; j++, sp2 += bytesperframe, fp++)
888 #ifdef ROCKBOX
889 union f2i f2i;
890 f2i.f = *fp * normalfactor;
891 xx = f2i.i;
892 #else /* ROCKBOX */
893 float f2 = *fp * normalfactor;
894 xx = *(long *)&f2;
895 #endif /* ROCKBOX */
896 sp2[0] = (xx >> 24); sp2[1] = (xx >> 16);
897 sp2[2] = (xx >> 8); sp2[3] = xx;
900 else
902 for (j = 0, sp2 = sp, fp=vecs[i] + onset;
903 j < nitems; j++, sp2 += bytesperframe, fp++)
905 #ifdef ROCKBOX
906 union f2i f2i;
907 f2i.f = *fp * normalfactor;
908 xx = f2i.i;
909 #else /* ROCKBOX */
910 float f2 = *fp * normalfactor;
911 xx = *(long *)&f2;
912 #endif /* ROCKBOX */
913 sp2[3] = (xx >> 24); sp2[2] = (xx >> 16);
914 sp2[1] = (xx >> 8); sp2[0] = xx;
922 /* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
923 #define DEFMAXSIZE 4000000 /* default maximum 16 MB per channel */
924 #define SAMPBUFSIZE 1024
927 static t_class *soundfiler_class;
929 typedef struct _soundfiler
931 t_object x_obj;
932 t_canvas *x_canvas;
933 } t_soundfiler;
935 static t_soundfiler *soundfiler_new(void)
937 t_soundfiler *x = (t_soundfiler *)pd_new(soundfiler_class);
938 x->x_canvas = canvas_getcurrent();
939 outlet_new(&x->x_obj, &s_float);
940 return (x);
943 /* soundfiler_read ...
945 usage: read [flags] filename table ...
946 flags:
947 -skip <frames> ... frames to skip in file
948 -nframes <frames>
949 -onset <frames> ... onset in table to read into (NOT DONE YET)
950 -raw <headersize channels bytes endian>
951 -resize
952 -maxsize <max-size>
955 static void soundfiler_read(t_soundfiler *x, t_symbol *s,
956 int argc, t_atom *argv)
958 #ifdef ROCKBOX
959 (void) s;
960 #endif
961 int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0,
962 resize = 0, i, j;
963 #ifdef ROCKBOX
964 long skipframes = 0, nframes = 0, finalsize = 0,
965 #else
966 long skipframes = 0, nframes = 0, finalsize = 0, itemsleft,
967 #endif
968 maxsize = DEFMAXSIZE, itemsread = 0, bytelimit = 0x7fffffff;
969 int fd = -1;
970 char endianness, *filename;
971 t_garray *garrays[MAXSFCHANS];
972 t_sample *vecs[MAXSFCHANS];
973 char sampbuf[SAMPBUFSIZE];
974 int bufframes, nitems;
975 #ifdef ROCKBOX
976 int fp;
977 #else
978 FILE *fp;
979 #endif
980 while (argc > 0 && argv->a_type == A_SYMBOL &&
981 *argv->a_w.w_symbol->s_name == '-')
983 char *flag = argv->a_w.w_symbol->s_name + 1;
984 if (!strcmp(flag, "skip"))
986 if (argc < 2 || argv[1].a_type != A_FLOAT ||
987 ((skipframes = argv[1].a_w.w_float) < 0))
988 goto usage;
989 argc -= 2; argv += 2;
991 else if (!strcmp(flag, "nframes"))
993 if (argc < 2 || argv[1].a_type != A_FLOAT ||
994 ((nframes = argv[1].a_w.w_float) < 0))
995 goto usage;
996 argc -= 2; argv += 2;
998 else if (!strcmp(flag, "raw"))
1000 if (argc < 5 ||
1001 argv[1].a_type != A_FLOAT ||
1002 ((headersize = argv[1].a_w.w_float) < 0) ||
1003 argv[2].a_type != A_FLOAT ||
1004 ((channels = argv[2].a_w.w_float) < 1) ||
1005 (channels > MAXSFCHANS) ||
1006 argv[3].a_type != A_FLOAT ||
1007 ((bytespersamp = argv[3].a_w.w_float) < 2) ||
1008 (bytespersamp > 4) ||
1009 argv[4].a_type != A_SYMBOL ||
1010 ((endianness = argv[4].a_w.w_symbol->s_name[0]) != 'b'
1011 && endianness != 'l' && endianness != 'n'))
1012 goto usage;
1013 if (endianness == 'b')
1014 bigendian = 1;
1015 else if (endianness == 'l')
1016 bigendian = 0;
1017 else
1018 bigendian = garray_ambigendian();
1019 argc -= 5; argv += 5;
1021 else if (!strcmp(flag, "resize"))
1023 resize = 1;
1024 argc -= 1; argv += 1;
1026 else if (!strcmp(flag, "maxsize"))
1028 if (argc < 2 || argv[1].a_type != A_FLOAT ||
1029 ((maxsize = argv[1].a_w.w_float) < 0))
1030 goto usage;
1031 resize = 1; /* maxsize implies resize. */
1032 argc -= 2; argv += 2;
1034 else goto usage;
1036 if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL)
1037 goto usage;
1038 filename = argv[0].a_w.w_symbol->s_name;
1039 argc--; argv++;
1041 for (i = 0; i < argc; i++)
1043 int vecsize;
1044 if (argv[i].a_type != A_SYMBOL)
1045 goto usage;
1046 if (!(garrays[i] =
1047 (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
1049 pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name);
1050 goto done;
1052 else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
1053 error("%s: bad template for tabwrite",
1054 argv[i].a_w.w_symbol->s_name);
1055 if (finalsize && finalsize != vecsize && !resize)
1057 post("soundfiler_read: arrays have different lengths; resizing...");
1058 resize = 1;
1060 finalsize = vecsize;
1062 fd = open_soundfile(canvas_getdir(x->x_canvas)->s_name, filename,
1063 headersize, &bytespersamp, &bigendian, &channels, &bytelimit,
1064 skipframes);
1066 if (fd < 0)
1068 #ifdef ROCKBOX
1069 pd_error(x, "soundfiler_read: %s: %s",
1070 filename,
1071 "unknown or bad header format");
1072 #else
1073 pd_error(x, "soundfiler_read: %s: %s", filename, (errno == EIO ?
1074 "unknown or bad header format" : strerror(errno)));
1075 #endif
1076 goto done;
1079 if (resize)
1081 /* figure out what to resize to */
1082 long poswas, eofis, framesinfile;
1084 poswas = lseek(fd, 0, SEEK_CUR);
1085 eofis = lseek(fd, 0, SEEK_END);
1086 if (poswas < 0 || eofis < 0)
1088 pd_error(x, "lseek failed");
1089 goto done;
1091 lseek(fd, poswas, SEEK_SET);
1092 framesinfile = (eofis - poswas) / (channels * bytespersamp);
1093 if (framesinfile > maxsize)
1095 pd_error(x, "soundfiler_read: truncated to %d elements", maxsize);
1096 framesinfile = maxsize;
1098 if (framesinfile > bytelimit / (channels * bytespersamp))
1099 framesinfile = bytelimit / (channels * bytespersamp);
1100 finalsize = framesinfile;
1101 for (i = 0; i < argc; i++)
1103 int vecsize;
1105 garray_resize(garrays[i], finalsize);
1106 /* for sanity's sake let's clear the save-in-patch flag here */
1107 garray_setsaveit(garrays[i], 0);
1108 garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
1109 /* if the resize failed, garray_resize reported the error */
1110 if (vecsize != framesinfile)
1112 pd_error(x, "resize failed");
1113 goto done;
1117 if (!finalsize) finalsize = 0x7fffffff;
1118 if (finalsize > bytelimit / (channels * bytespersamp))
1119 finalsize = bytelimit / (channels * bytespersamp);
1120 #ifdef ROCKBOX
1121 fp = fd;
1122 #else
1123 fp = fdopen(fd, "rb");
1124 #endif
1125 bufframes = SAMPBUFSIZE / (channels * bytespersamp);
1127 for (itemsread = 0; itemsread < finalsize; )
1129 int thisread = finalsize - itemsread;
1130 thisread = (thisread > bufframes ? bufframes : thisread);
1131 #ifdef ROCKBOX
1132 nitems = read(fp, sampbuf, thisread * bytespersamp * channels) / bytespersamp;
1133 #else
1134 nitems = fread(sampbuf, channels * bytespersamp, thisread, fp);
1135 #endif
1136 if (nitems <= 0) break;
1137 soundfile_xferin(channels, argc, vecs, itemsread,
1138 (unsigned char *)sampbuf, nitems, bytespersamp, bigendian);
1139 itemsread += nitems;
1141 /* zero out remaining elements of vectors */
1143 for (i = 0; i < argc; i++)
1145 #ifdef ROCKBOX
1146 int vecsize;
1147 #else
1148 int nzero, vecsize;
1149 #endif
1150 garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
1151 for (j = itemsread; j < vecsize; j++)
1152 vecs[i][j] = 0;
1154 /* zero out vectors in excess of number of channels */
1155 for (i = channels; i < argc; i++)
1157 int vecsize;
1158 t_sample *foo;
1159 garray_getfloatarray(garrays[i], &vecsize, &foo);
1160 for (j = 0; j < vecsize; j++)
1161 foo[j] = 0;
1163 /* do all graphics updates */
1164 for (i = 0; i < argc; i++)
1165 garray_redraw(garrays[i]);
1166 #ifdef ROCKBOX
1167 close(fp);
1168 #else
1169 fclose(fp);
1170 #endif
1171 fd = -1;
1172 goto done;
1173 usage:
1174 pd_error(x, "usage: read [flags] filename tablename...");
1175 post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
1176 post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
1177 done:
1178 if (fd >= 0)
1179 close (fd);
1180 outlet_float(x->x_obj.ob_outlet, (float)itemsread);
1183 /* this is broken out from soundfiler_write below so garray_write can
1184 call it too... not done yet though. */
1186 long soundfiler_dowrite(void *obj, t_canvas *canvas,
1187 int argc, t_atom *argv)
1189 #ifdef ROCKBOX
1190 int bytespersamp, bigendian,
1191 swap, filetype, normalize, i, j, nchannels;
1192 long onset, nframes,
1193 itemswritten = 0;
1194 #else
1195 int headersize, bytespersamp, bigendian,
1196 endianness, swap, filetype, normalize, i, j, nchannels;
1197 long onset, nframes, itemsleft,
1198 maxsize = DEFMAXSIZE, itemswritten = 0;
1199 #endif
1200 t_garray *garrays[MAXSFCHANS];
1201 t_sample *vecs[MAXSFCHANS];
1202 char sampbuf[SAMPBUFSIZE];
1203 #ifdef ROCKBOX
1204 int bufframes;
1205 #else
1206 int bufframes, nitems;
1207 #endif
1208 int fd = -1;
1209 float normfactor, biggest = 0, samplerate;
1210 t_symbol *filesym;
1212 if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
1213 &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes,
1214 &samplerate))
1215 goto usage;
1216 nchannels = argc;
1217 if (nchannels < 1 || nchannels > MAXSFCHANS)
1218 goto usage;
1219 if (samplerate < 0)
1220 samplerate = sys_getsr();
1221 for (i = 0; i < nchannels; i++)
1223 int vecsize;
1224 if (argv[i].a_type != A_SYMBOL)
1225 goto usage;
1226 if (!(garrays[i] =
1227 (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
1229 pd_error(obj, "%s: no such table", argv[i].a_w.w_symbol->s_name);
1230 goto fail;
1232 else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
1233 error("%s: bad template for tabwrite",
1234 argv[i].a_w.w_symbol->s_name);
1235 if (nframes > vecsize - onset)
1236 nframes = vecsize - onset;
1238 for (j = 0; j < vecsize; j++)
1240 if (vecs[i][j] > biggest)
1241 biggest = vecs[i][j];
1242 else if (-vecs[i][j] > biggest)
1243 biggest = -vecs[i][j];
1246 if (nframes <= 0)
1248 pd_error(obj, "soundfiler_write: no samples at onset %ld", onset);
1249 goto fail;
1252 if ((fd = create_soundfile(canvas, filesym->s_name, filetype,
1253 nframes, bytespersamp, bigendian, nchannels,
1254 swap, samplerate)) < 0)
1256 #ifdef ROCKBOX
1257 post("%s: %s\n", filesym->s_name, "error");
1258 #else
1259 post("%s: %s\n", filesym->s_name, strerror(errno));
1260 #endif
1261 goto fail;
1263 if (!normalize)
1265 if ((bytespersamp != 4) && (biggest > 1))
1267 post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest);
1268 normalize = 1;
1270 else post("%s: biggest amplitude = %f", filesym->s_name, biggest);
1272 if (normalize)
1273 normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
1274 else normfactor = 1;
1276 bufframes = SAMPBUFSIZE / (nchannels * bytespersamp);
1278 for (itemswritten = 0; itemswritten < nframes; )
1280 #ifdef ROCKBOX
1281 int thiswrite = nframes - itemswritten, nbytes;
1282 #else
1283 int thiswrite = nframes - itemswritten, nitems, nbytes;
1284 #endif
1285 thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
1286 soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite,
1287 onset, bytespersamp, bigendian, normfactor);
1288 nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite);
1289 if (nbytes < nchannels * bytespersamp * thiswrite)
1291 #ifdef ROCKBOX
1292 post("%s: %s", filesym->s_name, "error");
1293 #else
1294 post("%s: %s", filesym->s_name, strerror(errno));
1295 #endif
1296 if (nbytes > 0)
1297 itemswritten += nbytes / (nchannels * bytespersamp);
1298 break;
1300 itemswritten += thiswrite;
1301 onset += thiswrite;
1303 if (fd >= 0)
1305 soundfile_finishwrite(obj, filesym->s_name, fd,
1306 filetype, nframes, itemswritten, nchannels * bytespersamp, swap);
1307 close (fd);
1309 return ((float)itemswritten);
1310 usage:
1311 pd_error(obj, "usage: write [flags] filename tablename...");
1312 post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
1313 post("-big -little -normalize");
1314 post("(defaults to a 16-bit wave file).");
1315 fail:
1316 if (fd >= 0)
1317 close (fd);
1318 return (0);
1321 static void soundfiler_write(t_soundfiler *x, t_symbol *s,
1322 int argc, t_atom *argv)
1324 #ifdef ROCKBOX
1325 (void) s;
1326 #endif
1327 long bozo = soundfiler_dowrite(x, x->x_canvas,
1328 argc, argv);
1329 outlet_float(x->x_obj.ob_outlet, (float)bozo);
1332 static void soundfiler_setup(void)
1334 soundfiler_class = class_new(gensym("soundfiler"), (t_newmethod)soundfiler_new,
1335 0, sizeof(t_soundfiler), 0, 0);
1336 class_addmethod(soundfiler_class, (t_method)soundfiler_read, gensym("read"),
1337 A_GIMME, 0);
1338 class_addmethod(soundfiler_class, (t_method)soundfiler_write,
1339 gensym("write"), A_GIMME, 0);
1343 #ifndef FIXEDPOINT
1344 /************************* readsf object ******************************/
1346 /* READSF uses the Posix threads package; for the moment we're Linux
1347 only although this should be portable to the other platforms.
1349 Each instance of readsf~ owns a "child" thread for doing the UNIX (MSW?) file
1350 reading. The parent thread signals the child each time:
1351 (1) a file wants opening or closing;
1352 (2) we've eaten another 1/16 of the shared buffer (so that the
1353 child thread should check if it's time to read some more.)
1354 The child signals the parent whenever a read has completed. Signalling
1355 is done by setting "conditions" and putting data in mutex-controlled common
1356 areas.
1359 #define MAXBYTESPERSAMPLE 4
1360 #define MAXVECSIZE 128
1362 #define READSIZE 65536
1363 #define WRITESIZE 65536
1364 #define DEFBUFPERCHAN 262144
1365 #define MINBUFSIZE (4 * READSIZE)
1366 #define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */
1368 #define REQUEST_NOTHING 0
1369 #define REQUEST_OPEN 1
1370 #define REQUEST_CLOSE 2
1371 #define REQUEST_QUIT 3
1372 #define REQUEST_BUSY 4
1374 #define STATE_IDLE 0
1375 #define STATE_STARTUP 1
1376 #define STATE_STREAM 2
1378 static t_class *readsf_class;
1380 typedef struct _readsf
1382 t_object x_obj;
1383 t_canvas *x_canvas;
1384 t_clock *x_clock;
1385 char *x_buf; /* soundfile buffer */
1386 int x_bufsize; /* buffer size in bytes */
1387 int x_noutlets; /* number of audio outlets */
1388 t_sample *(x_outvec[MAXSFCHANS]); /* audio vectors */
1389 int x_vecsize; /* vector size for transfers */
1390 t_outlet *x_bangout; /* bang-on-done outlet */
1391 int x_state; /* opened, running, or idle */
1392 float x_insamplerate; /* sample rate of input signal if known */
1393 /* parameters to communicate with subthread */
1394 int x_requestcode; /* pending request from parent to I/O thread */
1395 char *x_filename; /* file to open (string is permanently allocated) */
1396 int x_fileerror; /* slot for "errno" return */
1397 int x_skipheaderbytes; /* size of header we'll skip */
1398 int x_bytespersample; /* bytes per sample (2 or 3) */
1399 int x_bigendian; /* true if file is big-endian */
1400 int x_sfchannels; /* number of channels in soundfile */
1401 float x_samplerate; /* sample rate of soundfile */
1402 long x_onsetframes; /* number of sample frames to skip */
1403 long x_bytelimit; /* max number of data bytes to read */
1404 int x_fd; /* filedesc */
1405 int x_fifosize; /* buffer size appropriately rounded down */
1406 int x_fifohead; /* index of next byte to get from file */
1407 int x_fifotail; /* index of next byte the ugen will read */
1408 int x_eof; /* true if fifohead has stopped changing */
1409 int x_sigcountdown; /* counter for signalling child for more data */
1410 int x_sigperiod; /* number of ticks per signal */
1411 int x_filetype; /* writesf~ only; type of file to create */
1412 int x_itemswritten; /* writesf~ only; items writen */
1413 int x_swap; /* writesf~ only; true if byte swapping */
1414 float x_f; /* writesf~ only; scalar for signal inlet */
1415 pthread_mutex_t x_mutex;
1416 pthread_cond_t x_requestcondition;
1417 pthread_cond_t x_answercondition;
1418 pthread_t x_childthread;
1419 } t_readsf;
1422 /************** the child thread which performs file I/O ***********/
1424 #if 0
1425 static void pute(char *s) /* debug routine */
1427 write(2, s, strlen(s));
1429 #define DEBUG_SOUNDFILE
1430 #endif
1432 #if 1
1433 #define sfread_cond_wait pthread_cond_wait
1434 #define sfread_cond_signal pthread_cond_signal
1435 #else
1436 #include <sys/time.h> /* debugging version... */
1437 #include <sys/types.h>
1438 static void readsf_fakewait(pthread_mutex_t *b)
1440 struct timeval timout;
1441 timout.tv_sec = 0;
1442 timout.tv_usec = 1000000;
1443 pthread_mutex_unlock(b);
1444 select(0, 0, 0, 0, &timout);
1445 pthread_mutex_lock(b);
1448 #define sfread_cond_wait(a,b) readsf_fakewait(b)
1449 #define sfread_cond_signal(a)
1450 #endif
1452 static void *readsf_child_main(void *zz)
1454 t_readsf *x = zz;
1455 #ifdef DEBUG_SOUNDFILE
1456 pute("1\n");
1457 #endif
1458 pthread_mutex_lock(&x->x_mutex);
1459 while (1)
1461 int fd, fifohead;
1462 char *buf;
1463 #ifdef DEBUG_SOUNDFILE
1464 pute("0\n");
1465 #endif
1466 if (x->x_requestcode == REQUEST_NOTHING)
1468 #ifdef DEBUG_SOUNDFILE
1469 pute("wait 2\n");
1470 #endif
1471 sfread_cond_signal(&x->x_answercondition);
1472 sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
1473 #ifdef DEBUG_SOUNDFILE
1474 pute("3\n");
1475 #endif
1477 else if (x->x_requestcode == REQUEST_OPEN)
1479 char boo[80];
1480 int sysrtn, wantbytes;
1482 /* copy file stuff out of the data structure so we can
1483 relinquish the mutex while we're in open_soundfile(). */
1484 long onsetframes = x->x_onsetframes;
1485 long bytelimit = 0x7fffffff;
1486 int skipheaderbytes = x->x_skipheaderbytes;
1487 int bytespersample = x->x_bytespersample;
1488 int sfchannels = x->x_sfchannels;
1489 int bigendian = x->x_bigendian;
1490 char *filename = x->x_filename;
1491 char *dirname = canvas_getdir(x->x_canvas)->s_name;
1492 /* alter the request code so that an ensuing "open" will get
1493 noticed. */
1494 #ifdef DEBUG_SOUNDFILE
1495 pute("4\n");
1496 #endif
1497 x->x_requestcode = REQUEST_BUSY;
1498 x->x_fileerror = 0;
1500 /* if there's already a file open, close it */
1501 if (x->x_fd >= 0)
1503 fd = x->x_fd;
1504 pthread_mutex_unlock(&x->x_mutex);
1505 close (fd);
1506 pthread_mutex_lock(&x->x_mutex);
1507 x->x_fd = -1;
1508 if (x->x_requestcode != REQUEST_BUSY)
1509 goto lost;
1511 /* open the soundfile with the mutex unlocked */
1512 pthread_mutex_unlock(&x->x_mutex);
1513 fd = open_soundfile(dirname, filename,
1514 skipheaderbytes, &bytespersample, &bigendian,
1515 &sfchannels, &bytelimit, onsetframes);
1516 pthread_mutex_lock(&x->x_mutex);
1518 #ifdef DEBUG_SOUNDFILE
1519 pute("5\n");
1520 #endif
1521 /* copy back into the instance structure. */
1522 x->x_bytespersample = bytespersample;
1523 x->x_sfchannels = sfchannels;
1524 x->x_bigendian = bigendian;
1525 x->x_fd = fd;
1526 x->x_bytelimit = bytelimit;
1527 if (fd < 0)
1529 x->x_fileerror = errno;
1530 x->x_eof = 1;
1531 #ifdef DEBUG_SOUNDFILE
1532 pute("open failed\n");
1533 pute(filename);
1534 pute(dirname);
1535 #endif
1536 goto lost;
1538 /* check if another request has been made; if so, field it */
1539 if (x->x_requestcode != REQUEST_BUSY)
1540 goto lost;
1541 #ifdef DEBUG_SOUNDFILE
1542 pute("6\n");
1543 #endif
1544 x->x_fifohead = 0;
1545 /* set fifosize from bufsize. fifosize must be a
1546 multiple of the number of bytes eaten for each DSP
1547 tick. We pessimistically assume MAXVECSIZE samples
1548 per tick since that could change. There could be a
1549 problem here if the vector size increases while a
1550 soundfile is being played... */
1551 x->x_fifosize = x->x_bufsize - (x->x_bufsize %
1552 (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
1553 /* arrange for the "request" condition to be signalled 16
1554 times per buffer */
1555 #ifdef DEBUG_SOUNDFILE
1556 sprintf(boo, "fifosize %d\n",
1557 x->x_fifosize);
1558 pute(boo);
1559 #endif
1560 x->x_sigcountdown = x->x_sigperiod =
1561 (x->x_fifosize /
1562 (16 * x->x_bytespersample * x->x_sfchannels *
1563 x->x_vecsize));
1564 /* in a loop, wait for the fifo to get hungry and feed it */
1566 while (x->x_requestcode == REQUEST_BUSY)
1568 int fifosize = x->x_fifosize;
1569 #ifdef DEBUG_SOUNDFILE
1570 pute("77\n");
1571 #endif
1572 if (x->x_eof)
1573 break;
1574 if (x->x_fifohead >= x->x_fifotail)
1576 /* if the head is >= the tail, we can immediately read
1577 to the end of the fifo. Unless, that is, we would
1578 read all the way to the end of the buffer and the
1579 "tail" is zero; this would fill the buffer completely
1580 which isn't allowed because you can't tell a completely
1581 full buffer from an empty one. */
1582 if (x->x_fifotail || (fifosize - x->x_fifohead > READSIZE))
1584 wantbytes = fifosize - x->x_fifohead;
1585 if (wantbytes > READSIZE)
1586 wantbytes = READSIZE;
1587 if (wantbytes > x->x_bytelimit)
1588 wantbytes = x->x_bytelimit;
1589 #ifdef DEBUG_SOUNDFILE
1590 sprintf(boo, "head %d, tail %d, size %d\n",
1591 x->x_fifohead, x->x_fifotail, wantbytes);
1592 pute(boo);
1593 #endif
1595 else
1597 #ifdef DEBUG_SOUNDFILE
1598 pute("wait 7a ...\n");
1599 #endif
1600 sfread_cond_signal(&x->x_answercondition);
1601 #ifdef DEBUG_SOUNDFILE
1602 pute("signalled\n");
1603 #endif
1604 sfread_cond_wait(&x->x_requestcondition,
1605 &x->x_mutex);
1606 #ifdef DEBUG_SOUNDFILE
1607 pute("7a done\n");
1608 #endif
1609 continue;
1612 else
1614 /* otherwise check if there are at least READSIZE
1615 bytes to read. If not, wait and loop back. */
1616 wantbytes = x->x_fifotail - x->x_fifohead - 1;
1617 if (wantbytes < READSIZE)
1619 #ifdef DEBUG_SOUNDFILE
1620 pute("wait 7...\n");
1621 #endif
1622 sfread_cond_signal(&x->x_answercondition);
1623 sfread_cond_wait(&x->x_requestcondition,
1624 &x->x_mutex);
1625 #ifdef DEBUG_SOUNDFILE
1626 pute("7 done\n");
1627 #endif
1628 continue;
1630 else wantbytes = READSIZE;
1631 if (wantbytes > x->x_bytelimit)
1632 wantbytes = x->x_bytelimit;
1634 #ifdef DEBUG_SOUNDFILE
1635 pute("8\n");
1636 #endif
1637 fd = x->x_fd;
1638 buf = x->x_buf;
1639 fifohead = x->x_fifohead;
1640 pthread_mutex_unlock(&x->x_mutex);
1641 sysrtn = read(fd, buf + fifohead, wantbytes);
1642 pthread_mutex_lock(&x->x_mutex);
1643 if (x->x_requestcode != REQUEST_BUSY)
1644 break;
1645 if (sysrtn < 0)
1647 #ifdef DEBUG_SOUNDFILE
1648 pute("fileerror\n");
1649 #endif
1650 x->x_fileerror = errno;
1651 break;
1653 else if (sysrtn == 0)
1655 x->x_eof = 1;
1656 break;
1658 else
1660 x->x_fifohead += sysrtn;
1661 x->x_bytelimit -= sysrtn;
1662 if (x->x_bytelimit <= 0)
1664 x->x_eof = 1;
1665 break;
1667 if (x->x_fifohead == fifosize)
1668 x->x_fifohead = 0;
1670 #ifdef DEBUG_SOUNDFILE
1671 sprintf(boo, "after: head %d, tail %d\n",
1672 x->x_fifohead, x->x_fifotail);
1673 pute(boo);
1674 #endif
1675 /* signal parent in case it's waiting for data */
1676 sfread_cond_signal(&x->x_answercondition);
1678 lost:
1680 if (x->x_requestcode == REQUEST_BUSY)
1681 x->x_requestcode = REQUEST_NOTHING;
1682 /* fell out of read loop: close file if necessary,
1683 set EOF and signal once more */
1684 if (x->x_fd >= 0)
1686 fd = x->x_fd;
1687 pthread_mutex_unlock(&x->x_mutex);
1688 close (fd);
1689 pthread_mutex_lock(&x->x_mutex);
1690 x->x_fd = -1;
1692 sfread_cond_signal(&x->x_answercondition);
1695 else if (x->x_requestcode == REQUEST_CLOSE)
1697 if (x->x_fd >= 0)
1699 fd = x->x_fd;
1700 pthread_mutex_unlock(&x->x_mutex);
1701 close (fd);
1702 pthread_mutex_lock(&x->x_mutex);
1703 x->x_fd = -1;
1705 if (x->x_requestcode == REQUEST_CLOSE)
1706 x->x_requestcode = REQUEST_NOTHING;
1707 sfread_cond_signal(&x->x_answercondition);
1709 else if (x->x_requestcode == REQUEST_QUIT)
1711 if (x->x_fd >= 0)
1713 fd = x->x_fd;
1714 pthread_mutex_unlock(&x->x_mutex);
1715 close (fd);
1716 pthread_mutex_lock(&x->x_mutex);
1717 x->x_fd = -1;
1719 x->x_requestcode = REQUEST_NOTHING;
1720 sfread_cond_signal(&x->x_answercondition);
1721 break;
1723 else
1725 #ifdef DEBUG_SOUNDFILE
1726 pute("13\n");
1727 #endif
1730 #ifdef DEBUG_SOUNDFILE
1731 pute("thread exit\n");
1732 #endif
1733 pthread_mutex_unlock(&x->x_mutex);
1734 return (0);
1737 /******** the object proper runs in the calling (parent) thread ****/
1739 static void readsf_tick(t_readsf *x);
1741 static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize)
1743 t_readsf *x;
1744 int nchannels = fnchannels, bufsize = fbufsize, i;
1745 char *buf;
1747 if (nchannels < 1)
1748 nchannels = 1;
1749 else if (nchannels > MAXSFCHANS)
1750 nchannels = MAXSFCHANS;
1751 if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
1752 else if (bufsize < MINBUFSIZE)
1753 bufsize = MINBUFSIZE;
1754 else if (bufsize > MAXBUFSIZE)
1755 bufsize = MAXBUFSIZE;
1756 buf = getbytes(bufsize);
1757 if (!buf) return (0);
1759 x = (t_readsf *)pd_new(readsf_class);
1761 for (i = 0; i < nchannels; i++)
1762 outlet_new(&x->x_obj, gensym("signal"));
1763 x->x_noutlets = nchannels;
1764 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
1765 pthread_mutex_init(&x->x_mutex, 0);
1766 pthread_cond_init(&x->x_requestcondition, 0);
1767 pthread_cond_init(&x->x_answercondition, 0);
1768 x->x_vecsize = MAXVECSIZE;
1769 x->x_state = STATE_IDLE;
1770 x->x_clock = clock_new(x, (t_method)readsf_tick);
1771 x->x_canvas = canvas_getcurrent();
1772 x->x_bytespersample = 2;
1773 x->x_sfchannels = 1;
1774 x->x_fd = -1;
1775 x->x_buf = buf;
1776 x->x_bufsize = bufsize;
1777 x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
1778 pthread_create(&x->x_childthread, 0, readsf_child_main, x);
1779 return (x);
1782 static void readsf_tick(t_readsf *x)
1784 outlet_bang(x->x_bangout);
1787 static t_int *readsf_perform(t_int *w)
1789 t_readsf *x = (t_readsf *)(w[1]);
1790 int vecsize = x->x_vecsize, noutlets = x->x_noutlets, i, j,
1791 bytespersample = x->x_bytespersample,
1792 bigendian = x->x_bigendian;
1793 float *fp;
1794 if (x->x_state == STATE_STREAM)
1796 int wantbytes, nchannels, sfchannels = x->x_sfchannels;
1797 pthread_mutex_lock(&x->x_mutex);
1798 wantbytes = sfchannels * vecsize * bytespersample;
1799 while (
1800 !x->x_eof && x->x_fifohead >= x->x_fifotail &&
1801 x->x_fifohead < x->x_fifotail + wantbytes-1)
1803 #ifdef DEBUG_SOUNDFILE
1804 pute("wait...\n");
1805 #endif
1806 sfread_cond_signal(&x->x_requestcondition);
1807 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
1808 #ifdef DEBUG_SOUNDFILE
1809 pute("done\n");
1810 #endif
1812 if (x->x_eof && x->x_fifohead >= x->x_fifotail &&
1813 x->x_fifohead < x->x_fifotail + wantbytes-1)
1815 int xfersize;
1816 if (x->x_fileerror)
1818 pd_error(x, "dsp: %s: %s", x->x_filename,
1819 (x->x_fileerror == EIO ?
1820 "unknown or bad header format" :
1821 strerror(x->x_fileerror)));
1823 clock_delay(x->x_clock, 0);
1824 x->x_state = STATE_IDLE;
1826 /* if there's a partial buffer left, copy it out. */
1827 xfersize = (x->x_fifohead - x->x_fifotail + 1) /
1828 (sfchannels * bytespersample);
1829 if (xfersize)
1831 soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
1832 (unsigned char *)(x->x_buf + x->x_fifotail), xfersize,
1833 bytespersample, bigendian);
1834 vecsize -= xfersize;
1836 /* then zero out the (rest of the) output */
1837 for (i = 0; i < noutlets; i++)
1838 for (j = vecsize, fp = x->x_outvec[i] + xfersize; j--; )
1839 *fp++ = 0;
1841 sfread_cond_signal(&x->x_requestcondition);
1842 pthread_mutex_unlock(&x->x_mutex);
1843 return (w+2);
1846 soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
1847 (unsigned char *)(x->x_buf + x->x_fifotail), vecsize,
1848 bytespersample, bigendian);
1850 x->x_fifotail += wantbytes;
1851 if (x->x_fifotail >= x->x_fifosize)
1852 x->x_fifotail = 0;
1853 if ((--x->x_sigcountdown) <= 0)
1855 sfread_cond_signal(&x->x_requestcondition);
1856 x->x_sigcountdown = x->x_sigperiod;
1858 pthread_mutex_unlock(&x->x_mutex);
1860 else
1862 idle:
1863 for (i = 0; i < noutlets; i++)
1864 for (j = vecsize, fp = x->x_outvec[i]; j--; )
1865 *fp++ = 0;
1867 return (w+2);
1870 static void readsf_start(t_readsf *x)
1872 /* start making output. If we're in the "startup" state change
1873 to the "running" state. */
1874 if (x->x_state == STATE_STARTUP)
1875 x->x_state = STATE_STREAM;
1876 else pd_error(x, "readsf: start requested with no prior 'open'");
1879 static void readsf_stop(t_readsf *x)
1881 /* LATER rethink whether you need the mutex just to set a variable? */
1882 pthread_mutex_lock(&x->x_mutex);
1883 x->x_state = STATE_IDLE;
1884 x->x_requestcode = REQUEST_CLOSE;
1885 sfread_cond_signal(&x->x_requestcondition);
1886 pthread_mutex_unlock(&x->x_mutex);
1889 static void readsf_float(t_readsf *x, t_floatarg f)
1891 if (f != 0)
1892 readsf_start(x);
1893 else readsf_stop(x);
1896 /* open method. Called as:
1897 open filename [skipframes headersize channels bytespersamp endianness]
1898 (if headersize is zero, header is taken to be automatically
1899 detected; thus, use the special "-1" to mean a truly headerless file.)
1902 static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv)
1904 t_symbol *filesym = atom_getsymbolarg(0, argc, argv);
1905 t_float onsetframes = atom_getfloatarg(1, argc, argv);
1906 t_float headerbytes = atom_getfloatarg(2, argc, argv);
1907 t_float channels = atom_getfloatarg(3, argc, argv);
1908 t_float bytespersamp = atom_getfloatarg(4, argc, argv);
1909 t_symbol *endian = atom_getsymbolarg(5, argc, argv);
1910 if (!*filesym->s_name)
1911 return;
1912 pthread_mutex_lock(&x->x_mutex);
1913 x->x_requestcode = REQUEST_OPEN;
1914 x->x_filename = filesym->s_name;
1915 x->x_fifotail = 0;
1916 x->x_fifohead = 0;
1917 if (*endian->s_name == 'b')
1918 x->x_bigendian = 1;
1919 else if (*endian->s_name == 'l')
1920 x->x_bigendian = 0;
1921 else if (*endian->s_name)
1922 pd_error(x, "endianness neither 'b' nor 'l'");
1923 else x->x_bigendian = garray_ambigendian();
1924 x->x_onsetframes = (onsetframes > 0 ? onsetframes : 0);
1925 x->x_skipheaderbytes = (headerbytes > 0 ? headerbytes :
1926 (headerbytes == 0 ? -1 : 0));
1927 x->x_sfchannels = (channels >= 1 ? channels : 1);
1928 x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
1929 x->x_eof = 0;
1930 x->x_fileerror = 0;
1931 x->x_state = STATE_STARTUP;
1932 sfread_cond_signal(&x->x_requestcondition);
1933 pthread_mutex_unlock(&x->x_mutex);
1936 static void readsf_dsp(t_readsf *x, t_signal **sp)
1938 int i, noutlets = x->x_noutlets;
1939 pthread_mutex_lock(&x->x_mutex);
1940 x->x_vecsize = sp[0]->s_n;
1942 x->x_sigperiod = (x->x_fifosize /
1943 (x->x_bytespersample * x->x_sfchannels * x->x_vecsize));
1944 for (i = 0; i < noutlets; i++)
1945 x->x_outvec[i] = sp[i]->s_vec;
1946 pthread_mutex_unlock(&x->x_mutex);
1947 dsp_add(readsf_perform, 1, x);
1950 static void readsf_print(t_readsf *x)
1952 post("state %d", x->x_state);
1953 post("fifo head %d", x->x_fifohead);
1954 post("fifo tail %d", x->x_fifotail);
1955 post("fifo size %d", x->x_fifosize);
1956 post("fd %d", x->x_fd);
1957 post("eof %d", x->x_eof);
1960 static void readsf_free(t_readsf *x)
1962 /* request QUIT and wait for acknowledge */
1963 void *threadrtn;
1964 pthread_mutex_lock(&x->x_mutex);
1965 x->x_requestcode = REQUEST_QUIT;
1966 sfread_cond_signal(&x->x_requestcondition);
1967 while (x->x_requestcode != REQUEST_NOTHING)
1969 sfread_cond_signal(&x->x_requestcondition);
1970 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
1972 pthread_mutex_unlock(&x->x_mutex);
1973 if (pthread_join(x->x_childthread, &threadrtn))
1974 error("readsf_free: join failed");
1976 pthread_cond_destroy(&x->x_requestcondition);
1977 pthread_cond_destroy(&x->x_answercondition);
1978 pthread_mutex_destroy(&x->x_mutex);
1979 freebytes(x->x_buf, x->x_bufsize);
1980 clock_free(x->x_clock);
1983 static void readsf_setup(void)
1985 readsf_class = class_new(gensym("readsf~"), (t_newmethod)readsf_new,
1986 (t_method)readsf_free, sizeof(t_readsf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
1987 class_addfloat(readsf_class, (t_method)readsf_float);
1988 class_addmethod(readsf_class, (t_method)readsf_start, gensym("start"), 0);
1989 class_addmethod(readsf_class, (t_method)readsf_stop, gensym("stop"), 0);
1990 class_addmethod(readsf_class, (t_method)readsf_dsp, gensym("dsp"), 0);
1991 class_addmethod(readsf_class, (t_method)readsf_open, gensym("open"),
1992 A_GIMME, 0);
1993 class_addmethod(readsf_class, (t_method)readsf_print, gensym("print"), 0);
1996 /******************************* writesf *******************/
1998 static t_class *writesf_class;
2000 #define t_writesf t_readsf /* just re-use the structure */
2002 /************** the child thread which performs file I/O ***********/
2004 static void *writesf_child_main(void *zz)
2006 t_writesf *x = zz;
2007 #ifdef DEBUG_SOUNDFILE
2008 pute("1\n");
2009 #endif
2010 pthread_mutex_lock(&x->x_mutex);
2011 while (1)
2013 #ifdef DEBUG_SOUNDFILE
2014 pute("0\n");
2015 #endif
2016 if (x->x_requestcode == REQUEST_NOTHING)
2018 #ifdef DEBUG_SOUNDFILE
2019 pute("wait 2\n");
2020 #endif
2021 sfread_cond_signal(&x->x_answercondition);
2022 sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
2023 #ifdef DEBUG_SOUNDFILE
2024 pute("3\n");
2025 #endif
2027 else if (x->x_requestcode == REQUEST_OPEN)
2029 char boo[80];
2030 int fd, sysrtn, writebytes;
2032 /* copy file stuff out of the data structure so we can
2033 relinquish the mutex while we're in open_soundfile(). */
2034 long onsetframes = x->x_onsetframes;
2035 long bytelimit = 0x7fffffff;
2036 int skipheaderbytes = x->x_skipheaderbytes;
2037 int bytespersample = x->x_bytespersample;
2038 int sfchannels = x->x_sfchannels;
2039 int bigendian = x->x_bigendian;
2040 int filetype = x->x_filetype;
2041 char *filename = x->x_filename;
2042 t_canvas *canvas = x->x_canvas;
2043 float samplerate = x->x_samplerate;
2045 /* alter the request code so that an ensuing "open" will get
2046 noticed. */
2047 #ifdef DEBUG_SOUNDFILE
2048 pute("4\n");
2049 #endif
2050 x->x_requestcode = REQUEST_BUSY;
2051 x->x_fileerror = 0;
2053 /* if there's already a file open, close it */
2054 if (x->x_fd >= 0)
2056 pthread_mutex_unlock(&x->x_mutex);
2057 close (x->x_fd);
2058 pthread_mutex_lock(&x->x_mutex);
2059 x->x_fd = -1;
2060 if (x->x_requestcode != REQUEST_BUSY)
2061 continue;
2063 /* open the soundfile with the mutex unlocked */
2064 pthread_mutex_unlock(&x->x_mutex);
2065 fd = create_soundfile(canvas, filename, filetype, 0,
2066 bytespersample, bigendian, sfchannels,
2067 garray_ambigendian() != bigendian, samplerate);
2068 pthread_mutex_lock(&x->x_mutex);
2069 #ifdef DEBUG_SOUNDFILE
2070 pute("5\n");
2071 #endif
2073 if (fd < 0)
2075 x->x_fd = -1;
2076 x->x_eof = 1;
2077 x->x_fileerror = errno;
2078 #ifdef DEBUG_SOUNDFILE
2079 pute("open failed\n");
2080 pute(filename);
2081 #endif
2082 x->x_requestcode = REQUEST_NOTHING;
2083 continue;
2085 /* check if another request has been made; if so, field it */
2086 if (x->x_requestcode != REQUEST_BUSY)
2087 continue;
2088 #ifdef DEBUG_SOUNDFILE
2089 pute("6\n");
2090 #endif
2091 x->x_fd = fd;
2092 x->x_fifotail = 0;
2093 x->x_itemswritten = 0;
2094 x->x_swap = garray_ambigendian() != bigendian;
2095 /* in a loop, wait for the fifo to have data and write it
2096 to disk */
2097 while (x->x_requestcode == REQUEST_BUSY ||
2098 (x->x_requestcode == REQUEST_CLOSE &&
2099 x->x_fifohead != x->x_fifotail))
2101 int fifosize = x->x_fifosize, fifotail;
2102 char *buf = x->x_buf;
2103 #ifdef DEBUG_SOUNDFILE
2104 pute("77\n");
2105 #endif
2107 /* if the head is < the tail, we can immediately write
2108 from tail to end of fifo to disk; otherwise we hold off
2109 writing until there are at least WRITESIZE bytes in the
2110 buffer */
2111 if (x->x_fifohead < x->x_fifotail ||
2112 x->x_fifohead >= x->x_fifotail + WRITESIZE
2113 || (x->x_requestcode == REQUEST_CLOSE &&
2114 x->x_fifohead != x->x_fifotail))
2116 writebytes = (x->x_fifohead < x->x_fifotail ?
2117 fifosize : x->x_fifohead) - x->x_fifotail;
2118 if (writebytes > READSIZE)
2119 writebytes = READSIZE;
2121 else
2123 #ifdef DEBUG_SOUNDFILE
2124 pute("wait 7a ...\n");
2125 #endif
2126 sfread_cond_signal(&x->x_answercondition);
2127 #ifdef DEBUG_SOUNDFILE
2128 pute("signalled\n");
2129 #endif
2130 sfread_cond_wait(&x->x_requestcondition,
2131 &x->x_mutex);
2132 #ifdef DEBUG_SOUNDFILE
2133 pute("7a done\n");
2134 #endif
2135 continue;
2137 #ifdef DEBUG_SOUNDFILE
2138 pute("8\n");
2139 #endif
2140 fifotail = x->x_fifotail;
2141 fd = x->x_fd;
2142 pthread_mutex_unlock(&x->x_mutex);
2143 sysrtn = write(fd, buf + fifotail, writebytes);
2144 pthread_mutex_lock(&x->x_mutex);
2145 if (x->x_requestcode != REQUEST_BUSY &&
2146 x->x_requestcode != REQUEST_CLOSE)
2147 break;
2148 if (sysrtn < writebytes)
2150 #ifdef DEBUG_SOUNDFILE
2151 pute("fileerror\n");
2152 #endif
2153 x->x_fileerror = errno;
2154 break;
2156 else
2158 x->x_fifotail += sysrtn;
2159 if (x->x_fifotail == fifosize)
2160 x->x_fifotail = 0;
2162 x->x_itemswritten +=
2163 sysrtn / (x->x_bytespersample * x->x_sfchannels);
2164 sprintf(boo, "after: head %d, tail %d\n",
2165 x->x_fifohead, x->x_fifotail);
2166 #ifdef DEBUG_SOUNDFILE
2167 pute(boo);
2168 #endif
2169 /* signal parent in case it's waiting for data */
2170 sfread_cond_signal(&x->x_answercondition);
2173 else if (x->x_requestcode == REQUEST_CLOSE ||
2174 x->x_requestcode == REQUEST_QUIT)
2176 int quit = (x->x_requestcode == REQUEST_QUIT);
2177 if (x->x_fd >= 0)
2179 int bytesperframe = x->x_bytespersample * x->x_sfchannels;
2180 int bigendian = x->x_bigendian;
2181 char *filename = x->x_filename;
2182 int fd = x->x_fd;
2183 int filetype = x->x_filetype;
2184 int itemswritten = x->x_itemswritten;
2185 int swap = x->x_swap;
2186 pthread_mutex_unlock(&x->x_mutex);
2188 soundfile_finishwrite(x, filename, fd,
2189 filetype, 0x7fffffff, itemswritten,
2190 bytesperframe, swap);
2191 close (fd);
2193 pthread_mutex_lock(&x->x_mutex);
2194 x->x_fd = -1;
2196 x->x_requestcode = REQUEST_NOTHING;
2197 sfread_cond_signal(&x->x_answercondition);
2198 if (quit)
2199 break;
2201 else
2203 #ifdef DEBUG_SOUNDFILE
2204 pute("13\n");
2205 #endif
2208 #ifdef DEBUG_SOUNDFILE
2209 pute("thread exit\n");
2210 #endif
2211 pthread_mutex_unlock(&x->x_mutex);
2212 return (0);
2215 /******** the object proper runs in the calling (parent) thread ****/
2217 static void writesf_tick(t_writesf *x);
2219 static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize)
2221 t_writesf *x;
2222 int nchannels = fnchannels, bufsize = fbufsize, i;
2223 char *buf;
2225 if (nchannels < 1)
2226 nchannels = 1;
2227 else if (nchannels > MAXSFCHANS)
2228 nchannels = MAXSFCHANS;
2229 if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
2230 else if (bufsize < MINBUFSIZE)
2231 bufsize = MINBUFSIZE;
2232 else if (bufsize > MAXBUFSIZE)
2233 bufsize = MAXBUFSIZE;
2234 buf = getbytes(bufsize);
2235 if (!buf) return (0);
2237 x = (t_writesf *)pd_new(writesf_class);
2239 for (i = 1; i < nchannels; i++)
2240 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
2242 x->x_f = 0;
2243 x->x_sfchannels = nchannels;
2244 pthread_mutex_init(&x->x_mutex, 0);
2245 pthread_cond_init(&x->x_requestcondition, 0);
2246 pthread_cond_init(&x->x_answercondition, 0);
2247 x->x_vecsize = MAXVECSIZE;
2248 x->x_insamplerate = x->x_samplerate = 0;
2249 x->x_state = STATE_IDLE;
2250 x->x_clock = 0; /* no callback needed here */
2251 x->x_canvas = canvas_getcurrent();
2252 x->x_bytespersample = 2;
2253 x->x_fd = -1;
2254 x->x_buf = buf;
2255 x->x_bufsize = bufsize;
2256 x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
2257 pthread_create(&x->x_childthread, 0, writesf_child_main, x);
2258 return (x);
2261 static t_int *writesf_perform(t_int *w)
2263 t_writesf *x = (t_writesf *)(w[1]);
2264 int vecsize = x->x_vecsize, sfchannels = x->x_sfchannels, i, j,
2265 bytespersample = x->x_bytespersample,
2266 bigendian = x->x_bigendian;
2267 float *fp;
2268 if (x->x_state == STATE_STREAM)
2270 int wantbytes;
2271 pthread_mutex_lock(&x->x_mutex);
2272 wantbytes = sfchannels * vecsize * bytespersample;
2273 while (x->x_fifotail > x->x_fifohead &&
2274 x->x_fifotail < x->x_fifohead + wantbytes + 1)
2276 #ifdef DEBUG_SOUNDFILE
2277 pute("wait...\n");
2278 #endif
2279 sfread_cond_signal(&x->x_requestcondition);
2280 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
2281 #ifdef DEBUG_SOUNDFILE
2282 pute("done\n");
2283 #endif
2286 soundfile_xferout(sfchannels, x->x_outvec,
2287 (unsigned char *)(x->x_buf + x->x_fifohead), vecsize, 0,
2288 bytespersample, bigendian, 1.);
2290 x->x_fifohead += wantbytes;
2291 if (x->x_fifohead >= x->x_fifosize)
2292 x->x_fifohead = 0;
2293 if ((--x->x_sigcountdown) <= 0)
2295 #ifdef DEBUG_SOUNDFILE
2296 pute("signal 1\n");
2297 #endif
2298 sfread_cond_signal(&x->x_requestcondition);
2299 x->x_sigcountdown = x->x_sigperiod;
2301 pthread_mutex_unlock(&x->x_mutex);
2303 return (w+2);
2306 static void writesf_start(t_writesf *x)
2308 /* start making output. If we're in the "startup" state change
2309 to the "running" state. */
2310 if (x->x_state == STATE_STARTUP)
2311 x->x_state = STATE_STREAM;
2312 else
2313 pd_error(x, "writesf: start requested with no prior 'open'");
2316 static void writesf_stop(t_writesf *x)
2318 /* LATER rethink whether you need the mutex just to set a Svariable? */
2319 pthread_mutex_lock(&x->x_mutex);
2320 x->x_state = STATE_IDLE;
2321 x->x_requestcode = REQUEST_CLOSE;
2322 #ifdef DEBUG_SOUNDFILE
2323 pute("signal 2\n");
2324 #endif
2325 sfread_cond_signal(&x->x_requestcondition);
2326 pthread_mutex_unlock(&x->x_mutex);
2330 /* open method. Called as: open [args] filename with args as in
2331 soundfiler_writeargparse().
2334 static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv)
2336 t_symbol *filesym;
2337 int filetype, bytespersamp, swap, bigendian, normalize;
2338 long onset, nframes;
2339 float samplerate;
2340 if (soundfiler_writeargparse(x, &argc,
2341 &argv, &filesym, &filetype, &bytespersamp, &swap, &bigendian,
2342 &normalize, &onset, &nframes, &samplerate))
2344 pd_error(x,
2345 "writesf~: usage: open [-bytes [234]] [-wave,-nextstep,-aiff] ...");
2346 post("... [-big,-little] [-rate ####] filename");
2348 if (normalize || onset || (nframes != 0x7fffffff))
2349 pd_error(x, "normalize/onset/nframes argument to writesf~: ignored");
2350 if (argc)
2351 pd_error(x, "extra argument(s) to writesf~: ignored");
2352 pthread_mutex_lock(&x->x_mutex);
2353 x->x_bytespersample = bytespersamp;
2354 x->x_swap = swap;
2355 x->x_bigendian = bigendian;
2356 x->x_filename = filesym->s_name;
2357 x->x_filetype = filetype;
2358 x->x_itemswritten = 0;
2359 x->x_requestcode = REQUEST_OPEN;
2360 x->x_fifotail = 0;
2361 x->x_fifohead = 0;
2362 x->x_eof = 0;
2363 x->x_fileerror = 0;
2364 x->x_state = STATE_STARTUP;
2365 x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
2366 if (samplerate > 0)
2367 x->x_samplerate = samplerate;
2368 else if (x->x_insamplerate > 0)
2369 x->x_samplerate = x->x_insamplerate;
2370 else x->x_samplerate = sys_getsr();
2371 /* set fifosize from bufsize. fifosize must be a
2372 multiple of the number of bytes eaten for each DSP
2373 tick. */
2374 x->x_fifosize = x->x_bufsize - (x->x_bufsize %
2375 (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
2376 /* arrange for the "request" condition to be signalled 16
2377 times per buffer */
2378 x->x_sigcountdown = x->x_sigperiod =
2379 (x->x_fifosize /
2380 (16 * x->x_bytespersample * x->x_sfchannels *
2381 x->x_vecsize));
2382 sfread_cond_signal(&x->x_requestcondition);
2383 pthread_mutex_unlock(&x->x_mutex);
2386 static void writesf_dsp(t_writesf *x, t_signal **sp)
2388 int i, ninlets = x->x_sfchannels;
2389 pthread_mutex_lock(&x->x_mutex);
2390 x->x_vecsize = sp[0]->s_n;
2392 x->x_sigperiod = (x->x_fifosize /
2393 (x->x_bytespersample * ninlets * x->x_vecsize));
2394 for (i = 0; i < ninlets; i++)
2395 x->x_outvec[i] = sp[i]->s_vec;
2396 x->x_insamplerate = sp[0]->s_sr;
2397 pthread_mutex_unlock(&x->x_mutex);
2398 dsp_add(writesf_perform, 1, x);
2401 static void writesf_print(t_writesf *x)
2403 post("state %d", x->x_state);
2404 post("fifo head %d", x->x_fifohead);
2405 post("fifo tail %d", x->x_fifotail);
2406 post("fifo size %d", x->x_fifosize);
2407 post("fd %d", x->x_fd);
2408 post("eof %d", x->x_eof);
2411 static void writesf_free(t_writesf *x)
2413 /* request QUIT and wait for acknowledge */
2414 void *threadrtn;
2415 pthread_mutex_lock(&x->x_mutex);
2416 x->x_requestcode = REQUEST_QUIT;
2417 /* post("stopping writesf thread..."); */
2418 sfread_cond_signal(&x->x_requestcondition);
2419 while (x->x_requestcode != REQUEST_NOTHING)
2421 /* post("signalling..."); */
2422 sfread_cond_signal(&x->x_requestcondition);
2423 sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
2425 pthread_mutex_unlock(&x->x_mutex);
2426 if (pthread_join(x->x_childthread, &threadrtn))
2427 error("writesf_free: join failed");
2428 /* post("... done."); */
2430 pthread_cond_destroy(&x->x_requestcondition);
2431 pthread_cond_destroy(&x->x_answercondition);
2432 pthread_mutex_destroy(&x->x_mutex);
2433 freebytes(x->x_buf, x->x_bufsize);
2436 static void writesf_setup(void)
2438 writesf_class = class_new(gensym("writesf~"), (t_newmethod)writesf_new,
2439 (t_method)writesf_free, sizeof(t_writesf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
2440 class_addmethod(writesf_class, (t_method)writesf_start, gensym("start"), 0);
2441 class_addmethod(writesf_class, (t_method)writesf_stop, gensym("stop"), 0);
2442 class_addmethod(writesf_class, (t_method)writesf_dsp, gensym("dsp"), 0);
2443 class_addmethod(writesf_class, (t_method)writesf_open, gensym("open"),
2444 A_GIMME, 0);
2445 class_addmethod(writesf_class, (t_method)writesf_print, gensym("print"), 0);
2446 CLASS_MAINSIGNALIN(writesf_class, t_writesf, x_f);
2449 #endif
2451 /* ------------------------ global setup routine ------------------------- */
2453 void d_soundfile_setup(void)
2455 soundfiler_setup();
2456 #ifndef FIXEDPOINT
2457 readsf_setup();
2458 writesf_setup();
2459 #endif