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. */
16 #include "../../pdbox.h"
35 /***************** soundfile header structures ************************/
37 typedef unsigned short uint16
;
38 typedef unsigned long uint32
;
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 */
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
;
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 */
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 */
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 */
105 /* the AIFF header. I'm assuming AIFC is compatible but don't really know
108 typedef struct _datachunk
110 char dc_id
[4]; /* data chunk id 'SSND' */
111 uint32 dc_size
; /* length of data chunk */
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! */
123 /* this version is more convenient for writing them out: */
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! */
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 */
153 #define BINCREATE _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY
155 #define BINCREATE O_WRONLY | O_CREAT | O_TRUNC
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,
162 extern int garray_ambigendian(void);
166 static uint32
swap4(uint32 n
, int doit
)
169 return (((n
& 0xff) << 24) | ((n
& 0xff00) << 8) |
170 ((n
& 0xff0000) >> 8) | ((n
& 0xff000000) >> 24));
174 static uint16
swap2(uint32 n
, int doit
)
177 return (((n
& 0xff) << 8) | ((n
& 0xff00) >> 8));
181 static void swapstring(char *foo
, int 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
,
205 char buf
[OBUFSIZE
], *bufptr
;
207 int fd
, nchannels
, bigendian
, bytespersamp
, swap
, sysrtn
;
209 int fd
, format
, nchannels
, bigendian
, bytespersamp
, swap
, sysrtn
;
211 long bytelimit
= 0x7fffffff;
215 fd
= open_via_path(dirname
, filename
,
216 "", buf
, &bufptr
, MAXPDSTRING
, 1);
219 if (headersize
>= 0) /* header detection overridden */
221 bigendian
= *p_bigendian
;
222 nchannels
= *p_nchannels
;
223 bytespersamp
= *p_bytespersamp
;
224 bytelimit
= *p_bytelimit
;
228 int bytesread
= read(fd
, buf
, READHDRSIZE
);
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))
240 format
= FORMAT_WAVE
, bigendian
= 0;
242 else if (!strncmp(buf
, "FORM", 4))
244 if (bytesread
< 12 || strncmp(buf
+ 8, "AIFF", 4))
246 format
= FORMAT_AIFF
, bigendian
= 1;
250 swap
= (bigendian
!= garray_ambigendian());
251 if (format
== FORMAT_NEXT
) /* nextstep header */
256 if (bytesread
< (int)sizeof(t_nextstep
))
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
)
263 else if (format
== NS_FORMAT_LINEAR_24
)
265 else if (format
== NS_FORMAT_FLOAT
)
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. */
279 /* First we guess a number of channels, etc., in case there's
280 no "fmt" chunk to follow. */
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
)
302 if (read(fd
, buf
, sizeof(t_fmt
)) < (int) sizeof(t_fmt
))
304 nchannels
= swap2(((t_fmt
*)buf
)->f_nchannels
, swap
);
305 format
= swap2(((t_fmt
*)buf
)->f_nbitspersample
, swap
);
308 else if (format
== 24)
310 else if (format
== 32)
314 seekout
= lseek(fd
, seekto
, SEEK_SET
);
315 if (seekout
!= seekto
)
317 if (read(fd
, buf
, sizeof(t_wavechunk
)) <
318 (int) sizeof(t_wavechunk
))
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); */
327 bytelimit
= swap4(((t_wavechunk
*)buf
)->wc_size
, swap
);
332 /* AIFF. same as WAVE; actually predates it. Disgusting. */
336 /* First we guess a number of channels, etc., in case there's
337 no COMM block to follow. */
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
)
358 if (read(fd
, buf
, sizeof(t_comm
)) <
359 (int) sizeof(t_comm
))
361 nchannels
= swap2(((t_comm
*)buf
)->c_nchannels
, swap
);
362 format
= swap2(((t_comm
*)buf
)->c_bitspersamp
, swap
);
365 else if (format
== 24)
369 seekout
= lseek(fd
, seekto
, SEEK_SET
);
370 if (seekout
!= seekto
)
372 if (read(fd
, buf
, sizeof(t_datachunk
)) <
373 (int) sizeof(t_datachunk
))
377 bytelimit
= swap4(((t_datachunk
*)buf
)->dc_size
, swap
);
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
)
385 bytelimit
-= nchannels
* bytespersamp
* skipframes
;
388 /* copy sample format back to caller */
389 *p_bigendian
= bigendian
;
390 *p_nchannels
= nchannels
;
391 *p_bytespersamp
= bytespersamp
;
392 *p_bytelimit
= bytelimit
;
395 /* the header wasn't recognized. We're threadable here so let's not
396 print out the error... */
403 static void soundfile_xferin(int sfchannels
, int nvecs
, t_sample
**vecs
,
404 long itemsread
, unsigned char *buf
, int nitems
, int bytespersamp
,
408 unsigned char *sp
, *sp2
;
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)
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));
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)
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)
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)
446 else if (bytespersamp
== 4)
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]);
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
--; )
471 /* soundfiler_write ...
473 usage: write [flags] filename table ...
477 -bytes <bytes per sample>
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
)
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;
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))
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))
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) ||
530 argc
-= 2; argv
+= 2;
532 else if (!strcmp(flag
, "normalize"))
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"))
555 argc
-= 1; argv
+= 1;
557 else if (!strcmp(flag
, "little"))
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))
567 argc
-= 2; argv
+= 2;
571 if (!argc
|| argv
->a_type
!= A_SYMBOL
)
573 filesym
= argv
->a_w
.w_symbol
;
575 /* check if format not specified and fill in */
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
;
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");
606 /* for WAVE force little endian; for nextstep use machine native */
607 if (filetype
== FORMAT_WAVE
)
611 pd_error(obj
, "WAVE file forced to little endian");
613 else if (filetype
== FORMAT_AIFF
)
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());
630 *p_filesym
= filesym
;
631 *p_filetype
= filetype
;
632 *p_bytespersamp
= bytespersamp
;
634 *p_normalize
= normalize
;
636 *p_nframes
= nframes
;
637 *p_bigendian
= bigendian
;
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");
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
;
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
);
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
);
724 if ((fd
= open(buf2
, BINCREATE
)) < 0)
726 if ((fd
= open(buf2
, BINCREATE
, 0666)) < 0)
730 if (write(fd
, headerbuf
, headersize
) < headersize
)
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
;
752 ((char *)(&((t_wave
*)0)->w_chunksize
)) - (char *)0,
755 mofo
= swap4(datasize
+ sizeof(t_wave
) - 8, swap
);
756 if (write(fd
, (char *)(&mofo
), 4) < 4)
759 ((char *)(&((t_wave
*)0)->w_datachunksize
)) - (char *)0,
762 mofo
= swap4(datasize
, swap
);
763 if (write(fd
, (char *)(&mofo
), 4) < 4)
766 if (filetype
== FORMAT_AIFF
)
770 ((char *)(&((t_aiff
*)0)->a_nframeshi
)) - (char *)0,
773 mofo
= swap4(nframes
, swap
);
774 if (write(fd
, (char *)(&mofo
), 4) < 4)
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)
785 if (write(fd
, &nextsize
, 4) < 4)
794 post("%s: error", filename
);
796 post("%s: %s", filename
, strerror(errno
));
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
)
805 unsigned char *sp
, *sp2
;
807 int bytesperframe
= bytespersamp
* nchannels
;
809 for (i
= 0, sp
= buf
; i
< nchannels
; i
++, sp
+= bytespersamp
)
811 if (bytespersamp
== 2)
813 float ff
= normalfactor
* 32768.;
816 for (j
= 0, sp2
= sp
, fp
= vecs
[i
] + onset
;
817 j
< nitems
; j
++, sp2
+= bytesperframe
, fp
++)
819 int xx
= 32768. + (*fp
* ff
);
831 for (j
= 0, sp2
= sp
, fp
=vecs
[i
] + onset
;
832 j
< nitems
; j
++, sp2
+= bytesperframe
, fp
++)
834 int xx
= 32768. + (*fp
* ff
);
845 else if (bytespersamp
== 3)
847 float ff
= normalfactor
* 8388608.;
850 for (j
= 0, sp2
= sp
, fp
=vecs
[i
] + onset
;
851 j
< nitems
; j
++, sp2
+= bytesperframe
, fp
++)
853 int xx
= 8388608. + (*fp
* ff
);
866 for (j
= 0, sp2
= sp
, fp
=vecs
[i
] + onset
;
867 j
< nitems
; j
++, sp2
+= bytesperframe
, fp
++)
869 int xx
= 8388608. + (*fp
* ff
);
881 else if (bytespersamp
== 4)
885 for (j
= 0, sp2
= sp
, fp
=vecs
[i
] + onset
;
886 j
< nitems
; j
++, sp2
+= bytesperframe
, fp
++)
890 f2i
.f
= *fp
* normalfactor
;
893 float f2
= *fp
* normalfactor
;
896 sp2
[0] = (xx
>> 24); sp2
[1] = (xx
>> 16);
897 sp2
[2] = (xx
>> 8); sp2
[3] = xx
;
902 for (j
= 0, sp2
= sp
, fp
=vecs
[i
] + onset
;
903 j
< nitems
; j
++, sp2
+= bytesperframe
, fp
++)
907 f2i
.f
= *fp
* normalfactor
;
910 float f2
= *fp
* normalfactor
;
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
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
);
943 /* soundfiler_read ...
945 usage: read [flags] filename table ...
947 -skip <frames> ... frames to skip in file
949 -onset <frames> ... onset in table to read into (NOT DONE YET)
950 -raw <headersize channels bytes endian>
955 static void soundfiler_read(t_soundfiler
*x
, t_symbol
*s
,
956 int argc
, t_atom
*argv
)
961 int headersize
= -1, channels
= 0, bytespersamp
= 0, bigendian
= 0,
964 long skipframes
= 0, nframes
= 0, finalsize
= 0,
966 long skipframes
= 0, nframes
= 0, finalsize
= 0, itemsleft
,
968 maxsize
= DEFMAXSIZE
, itemsread
= 0, bytelimit
= 0x7fffffff;
970 char endianness
, *filename
;
971 t_garray
*garrays
[MAXSFCHANS
];
972 t_sample
*vecs
[MAXSFCHANS
];
973 char sampbuf
[SAMPBUFSIZE
];
974 int bufframes
, nitems
;
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))
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))
996 argc
-= 2; argv
+= 2;
998 else if (!strcmp(flag
, "raw"))
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'))
1013 if (endianness
== 'b')
1015 else if (endianness
== 'l')
1018 bigendian
= garray_ambigendian();
1019 argc
-= 5; argv
+= 5;
1021 else if (!strcmp(flag
, "resize"))
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))
1031 resize
= 1; /* maxsize implies resize. */
1032 argc
-= 2; argv
+= 2;
1036 if (argc
< 2 || argc
> MAXSFCHANS
+ 1 || argv
[0].a_type
!= A_SYMBOL
)
1038 filename
= argv
[0].a_w
.w_symbol
->s_name
;
1041 for (i
= 0; i
< argc
; i
++)
1044 if (argv
[i
].a_type
!= A_SYMBOL
)
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
);
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...");
1060 finalsize
= vecsize
;
1062 fd
= open_soundfile(canvas_getdir(x
->x_canvas
)->s_name
, filename
,
1063 headersize
, &bytespersamp
, &bigendian
, &channels
, &bytelimit
,
1069 pd_error(x
, "soundfiler_read: %s: %s",
1071 "unknown or bad header format");
1073 pd_error(x
, "soundfiler_read: %s: %s", filename
, (errno
== EIO
?
1074 "unknown or bad header format" : strerror(errno
)));
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");
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
++)
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");
1117 if (!finalsize
) finalsize
= 0x7fffffff;
1118 if (finalsize
> bytelimit
/ (channels
* bytespersamp
))
1119 finalsize
= bytelimit
/ (channels
* bytespersamp
);
1123 fp
= fdopen(fd
, "rb");
1125 bufframes
= SAMPBUFSIZE
/ (channels
* bytespersamp
);
1127 for (itemsread
= 0; itemsread
< finalsize
; )
1129 int thisread
= finalsize
- itemsread
;
1130 thisread
= (thisread
> bufframes
? bufframes
: thisread
);
1132 nitems
= read(fp
, sampbuf
, thisread
* bytespersamp
* channels
) / bytespersamp
;
1134 nitems
= fread(sampbuf
, channels
* bytespersamp
, thisread
, fp
);
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
++)
1150 garray_getfloatarray(garrays
[i
], &vecsize
, &vecs
[i
]);
1151 for (j
= itemsread
; j
< vecsize
; j
++)
1154 /* zero out vectors in excess of number of channels */
1155 for (i
= channels
; i
< argc
; i
++)
1159 garray_getfloatarray(garrays
[i
], &vecsize
, &foo
);
1160 for (j
= 0; j
< vecsize
; j
++)
1163 /* do all graphics updates */
1164 for (i
= 0; i
< argc
; i
++)
1165 garray_redraw(garrays
[i
]);
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)>.");
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
)
1190 int bytespersamp
, bigendian
,
1191 swap
, filetype
, normalize
, i
, j
, nchannels
;
1192 long onset
, nframes
,
1195 int headersize
, bytespersamp
, bigendian
,
1196 endianness
, swap
, filetype
, normalize
, i
, j
, nchannels
;
1197 long onset
, nframes
, itemsleft
,
1198 maxsize
= DEFMAXSIZE
, itemswritten
= 0;
1200 t_garray
*garrays
[MAXSFCHANS
];
1201 t_sample
*vecs
[MAXSFCHANS
];
1202 char sampbuf
[SAMPBUFSIZE
];
1206 int bufframes
, nitems
;
1209 float normfactor
, biggest
= 0, samplerate
;
1212 if (soundfiler_writeargparse(obj
, &argc
, &argv
, &filesym
, &filetype
,
1213 &bytespersamp
, &swap
, &bigendian
, &normalize
, &onset
, &nframes
,
1217 if (nchannels
< 1 || nchannels
> MAXSFCHANS
)
1220 samplerate
= sys_getsr();
1221 for (i
= 0; i
< nchannels
; i
++)
1224 if (argv
[i
].a_type
!= A_SYMBOL
)
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
);
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
];
1248 pd_error(obj
, "soundfiler_write: no samples at onset %ld", onset
);
1252 if ((fd
= create_soundfile(canvas
, filesym
->s_name
, filetype
,
1253 nframes
, bytespersamp
, bigendian
, nchannels
,
1254 swap
, samplerate
)) < 0)
1257 post("%s: %s\n", filesym
->s_name
, "error");
1259 post("%s: %s\n", filesym
->s_name
, strerror(errno
));
1265 if ((bytespersamp
!= 4) && (biggest
> 1))
1267 post("%s: normalizing max amplitude %f to 1", filesym
->s_name
, biggest
);
1270 else post("%s: biggest amplitude = %f", filesym
->s_name
, biggest
);
1273 normfactor
= (biggest
> 0 ? 32767./(32768. * biggest
) : 1);
1274 else normfactor
= 1;
1276 bufframes
= SAMPBUFSIZE
/ (nchannels
* bytespersamp
);
1278 for (itemswritten
= 0; itemswritten
< nframes
; )
1281 int thiswrite
= nframes
- itemswritten
, nbytes
;
1283 int thiswrite
= nframes
- itemswritten
, nitems
, nbytes
;
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
)
1292 post("%s: %s", filesym
->s_name
, "error");
1294 post("%s: %s", filesym
->s_name
, strerror(errno
));
1297 itemswritten
+= nbytes
/ (nchannels
* bytespersamp
);
1300 itemswritten
+= thiswrite
;
1305 soundfile_finishwrite(obj
, filesym
->s_name
, fd
,
1306 filetype
, nframes
, itemswritten
, nchannels
* bytespersamp
, swap
);
1309 return ((float)itemswritten
);
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).");
1321 static void soundfiler_write(t_soundfiler
*x
, t_symbol
*s
,
1322 int argc
, t_atom
*argv
)
1327 long bozo
= soundfiler_dowrite(x
, x
->x_canvas
,
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"),
1338 class_addmethod(soundfiler_class
, (t_method
)soundfiler_write
,
1339 gensym("write"), A_GIMME
, 0);
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
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
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
;
1422 /************** the child thread which performs file I/O ***********/
1425 static void pute(char *s
) /* debug routine */
1427 write(2, s
, strlen(s
));
1429 #define DEBUG_SOUNDFILE
1433 #define sfread_cond_wait pthread_cond_wait
1434 #define sfread_cond_signal pthread_cond_signal
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
;
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)
1452 static void *readsf_child_main(void *zz
)
1455 #ifdef DEBUG_SOUNDFILE
1458 pthread_mutex_lock(&x
->x_mutex
);
1463 #ifdef DEBUG_SOUNDFILE
1466 if (x
->x_requestcode
== REQUEST_NOTHING
)
1468 #ifdef DEBUG_SOUNDFILE
1471 sfread_cond_signal(&x
->x_answercondition
);
1472 sfread_cond_wait(&x
->x_requestcondition
, &x
->x_mutex
);
1473 #ifdef DEBUG_SOUNDFILE
1477 else if (x
->x_requestcode
== REQUEST_OPEN
)
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
1494 #ifdef DEBUG_SOUNDFILE
1497 x
->x_requestcode
= REQUEST_BUSY
;
1500 /* if there's already a file open, close it */
1504 pthread_mutex_unlock(&x
->x_mutex
);
1506 pthread_mutex_lock(&x
->x_mutex
);
1508 if (x
->x_requestcode
!= REQUEST_BUSY
)
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
1521 /* copy back into the instance structure. */
1522 x
->x_bytespersample
= bytespersample
;
1523 x
->x_sfchannels
= sfchannels
;
1524 x
->x_bigendian
= bigendian
;
1526 x
->x_bytelimit
= bytelimit
;
1529 x
->x_fileerror
= errno
;
1531 #ifdef DEBUG_SOUNDFILE
1532 pute("open failed\n");
1538 /* check if another request has been made; if so, field it */
1539 if (x
->x_requestcode
!= REQUEST_BUSY
)
1541 #ifdef DEBUG_SOUNDFILE
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
1555 #ifdef DEBUG_SOUNDFILE
1556 sprintf(boo
, "fifosize %d\n",
1560 x
->x_sigcountdown
= x
->x_sigperiod
=
1562 (16 * x
->x_bytespersample
* x
->x_sfchannels
*
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
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
);
1597 #ifdef DEBUG_SOUNDFILE
1598 pute("wait 7a ...\n");
1600 sfread_cond_signal(&x
->x_answercondition
);
1601 #ifdef DEBUG_SOUNDFILE
1602 pute("signalled\n");
1604 sfread_cond_wait(&x
->x_requestcondition
,
1606 #ifdef DEBUG_SOUNDFILE
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");
1622 sfread_cond_signal(&x
->x_answercondition
);
1623 sfread_cond_wait(&x
->x_requestcondition
,
1625 #ifdef DEBUG_SOUNDFILE
1630 else wantbytes
= READSIZE
;
1631 if (wantbytes
> x
->x_bytelimit
)
1632 wantbytes
= x
->x_bytelimit
;
1634 #ifdef DEBUG_SOUNDFILE
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
)
1647 #ifdef DEBUG_SOUNDFILE
1648 pute("fileerror\n");
1650 x
->x_fileerror
= errno
;
1653 else if (sysrtn
== 0)
1660 x
->x_fifohead
+= sysrtn
;
1661 x
->x_bytelimit
-= sysrtn
;
1662 if (x
->x_bytelimit
<= 0)
1667 if (x
->x_fifohead
== fifosize
)
1670 #ifdef DEBUG_SOUNDFILE
1671 sprintf(boo
, "after: head %d, tail %d\n",
1672 x
->x_fifohead
, x
->x_fifotail
);
1675 /* signal parent in case it's waiting for data */
1676 sfread_cond_signal(&x
->x_answercondition
);
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 */
1687 pthread_mutex_unlock(&x
->x_mutex
);
1689 pthread_mutex_lock(&x
->x_mutex
);
1692 sfread_cond_signal(&x
->x_answercondition
);
1695 else if (x
->x_requestcode
== REQUEST_CLOSE
)
1700 pthread_mutex_unlock(&x
->x_mutex
);
1702 pthread_mutex_lock(&x
->x_mutex
);
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
)
1714 pthread_mutex_unlock(&x
->x_mutex
);
1716 pthread_mutex_lock(&x
->x_mutex
);
1719 x
->x_requestcode
= REQUEST_NOTHING
;
1720 sfread_cond_signal(&x
->x_answercondition
);
1725 #ifdef DEBUG_SOUNDFILE
1730 #ifdef DEBUG_SOUNDFILE
1731 pute("thread exit\n");
1733 pthread_mutex_unlock(&x
->x_mutex
);
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
)
1744 int nchannels
= fnchannels
, bufsize
= fbufsize
, i
;
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;
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
);
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
;
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
;
1800 !x
->x_eof
&& x
->x_fifohead
>= x
->x_fifotail
&&
1801 x
->x_fifohead
< x
->x_fifotail
+ wantbytes
-1)
1803 #ifdef DEBUG_SOUNDFILE
1806 sfread_cond_signal(&x
->x_requestcondition
);
1807 sfread_cond_wait(&x
->x_answercondition
, &x
->x_mutex
);
1808 #ifdef DEBUG_SOUNDFILE
1812 if (x
->x_eof
&& x
->x_fifohead
>= x
->x_fifotail
&&
1813 x
->x_fifohead
< x
->x_fifotail
+ wantbytes
-1)
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
);
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
--; )
1841 sfread_cond_signal(&x
->x_requestcondition
);
1842 pthread_mutex_unlock(&x
->x_mutex
);
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
)
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
);
1863 for (i
= 0; i
< noutlets
; i
++)
1864 for (j
= vecsize
, fp
= x
->x_outvec
[i
]; j
--; )
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
)
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
)
1912 pthread_mutex_lock(&x
->x_mutex
);
1913 x
->x_requestcode
= REQUEST_OPEN
;
1914 x
->x_filename
= filesym
->s_name
;
1917 if (*endian
->s_name
== 'b')
1919 else if (*endian
->s_name
== 'l')
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);
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 */
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"),
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
)
2007 #ifdef DEBUG_SOUNDFILE
2010 pthread_mutex_lock(&x
->x_mutex
);
2013 #ifdef DEBUG_SOUNDFILE
2016 if (x
->x_requestcode
== REQUEST_NOTHING
)
2018 #ifdef DEBUG_SOUNDFILE
2021 sfread_cond_signal(&x
->x_answercondition
);
2022 sfread_cond_wait(&x
->x_requestcondition
, &x
->x_mutex
);
2023 #ifdef DEBUG_SOUNDFILE
2027 else if (x
->x_requestcode
== REQUEST_OPEN
)
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
2047 #ifdef DEBUG_SOUNDFILE
2050 x
->x_requestcode
= REQUEST_BUSY
;
2053 /* if there's already a file open, close it */
2056 pthread_mutex_unlock(&x
->x_mutex
);
2058 pthread_mutex_lock(&x
->x_mutex
);
2060 if (x
->x_requestcode
!= REQUEST_BUSY
)
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
2077 x
->x_fileerror
= errno
;
2078 #ifdef DEBUG_SOUNDFILE
2079 pute("open failed\n");
2082 x
->x_requestcode
= REQUEST_NOTHING
;
2085 /* check if another request has been made; if so, field it */
2086 if (x
->x_requestcode
!= REQUEST_BUSY
)
2088 #ifdef DEBUG_SOUNDFILE
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
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
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
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
;
2123 #ifdef DEBUG_SOUNDFILE
2124 pute("wait 7a ...\n");
2126 sfread_cond_signal(&x
->x_answercondition
);
2127 #ifdef DEBUG_SOUNDFILE
2128 pute("signalled\n");
2130 sfread_cond_wait(&x
->x_requestcondition
,
2132 #ifdef DEBUG_SOUNDFILE
2137 #ifdef DEBUG_SOUNDFILE
2140 fifotail
= x
->x_fifotail
;
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
)
2148 if (sysrtn
< writebytes
)
2150 #ifdef DEBUG_SOUNDFILE
2151 pute("fileerror\n");
2153 x
->x_fileerror
= errno
;
2158 x
->x_fifotail
+= sysrtn
;
2159 if (x
->x_fifotail
== fifosize
)
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
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
);
2179 int bytesperframe
= x
->x_bytespersample
* x
->x_sfchannels
;
2180 int bigendian
= x
->x_bigendian
;
2181 char *filename
= x
->x_filename
;
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
);
2193 pthread_mutex_lock(&x
->x_mutex
);
2196 x
->x_requestcode
= REQUEST_NOTHING
;
2197 sfread_cond_signal(&x
->x_answercondition
);
2203 #ifdef DEBUG_SOUNDFILE
2208 #ifdef DEBUG_SOUNDFILE
2209 pute("thread exit\n");
2211 pthread_mutex_unlock(&x
->x_mutex
);
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
)
2222 int nchannels
= fnchannels
, bufsize
= fbufsize
, i
;
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
);
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;
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
);
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
;
2268 if (x
->x_state
== STATE_STREAM
)
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
2279 sfread_cond_signal(&x
->x_requestcondition
);
2280 sfread_cond_wait(&x
->x_answercondition
, &x
->x_mutex
);
2281 #ifdef DEBUG_SOUNDFILE
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
)
2293 if ((--x
->x_sigcountdown
) <= 0)
2295 #ifdef DEBUG_SOUNDFILE
2298 sfread_cond_signal(&x
->x_requestcondition
);
2299 x
->x_sigcountdown
= x
->x_sigperiod
;
2301 pthread_mutex_unlock(&x
->x_mutex
);
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
;
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
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
)
2337 int filetype
, bytespersamp
, swap
, bigendian
, normalize
;
2338 long onset
, nframes
;
2340 if (soundfiler_writeargparse(x
, &argc
,
2341 &argv
, &filesym
, &filetype
, &bytespersamp
, &swap
, &bigendian
,
2342 &normalize
, &onset
, &nframes
, &samplerate
))
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");
2351 pd_error(x
, "extra argument(s) to writesf~: ignored");
2352 pthread_mutex_lock(&x
->x_mutex
);
2353 x
->x_bytespersample
= bytespersamp
;
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
;
2364 x
->x_state
= STATE_STARTUP
;
2365 x
->x_bytespersample
= (bytespersamp
> 2 ? bytespersamp
: 2);
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
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
2378 x
->x_sigcountdown
= x
->x_sigperiod
=
2380 (16 * x
->x_bytespersample
* x
->x_sfchannels
*
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 */
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"),
2445 class_addmethod(writesf_class
, (t_method
)writesf_print
, gensym("print"), 0);
2446 CLASS_MAINSIGNALIN(writesf_class
, t_writesf
, x_f
);
2451 /* ------------------------ global setup routine ------------------------- */
2453 void d_soundfile_setup(void)