Commit 6ceeb809 authored by Jonathan Wilkes's avatar Jonathan Wilkes
Browse files

Merge branch 'soundfiler-facelift-rev1'

parents c8418a58 807068ce
......@@ -117,7 +117,7 @@ ifneq ($(LIGHT),yes)
# For other external libs
install -p $(bin_src)/lua53.dll $(DESTDIR)$(bindir)/
#install -p $(bin_src)/pthreadGC2.dll $(DESTDIR)$(bindir)/
install -p $(bin_src)/libdl.dll $(DESTDIR)$(bindir)/
#install -p $(bin_src)/libdl.dll $(DESTDIR)$(bindir)/
install -p $(bin_src)/libportaudio-2.dll $(DESTDIR)$(bindir)/
install -p $(bin_src)/libFLAC-8.dll $(DESTDIR)$(bindir)/
install -p $(bin_src)/libspeex-1.dll $(DESTDIR)$(bindir)/
......
#N canvas 429 34 555 619 10;
#N canvas 75 64 555 619 10;
#X obj 0 595 cnv 15 552 21 empty \$0-pddp.cnv.footer empty 20 12 0
14 -228856 -66577 0;
14 #dcdcdc #404040 0;
#X obj 0 0 cnv 15 552 40 empty \$0-pddp.cnv.header soundfiler 3 12
0 18 -204280 -1 0;
#X obj 0 387 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13
-228856 -1 0;
0 18 #c4dcdc #000000 0;
#X obj 0 352 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13
#dcdcdc #000000 0;
#N canvas 490 283 494 344 META 0;
#X text 12 105 LIBRARY internal;
#X text 12 145 WEBSITE http://crca.ucsd.edu/~msp/;
......@@ -19,16 +19,16 @@ Wilkes revised the patch to conform to the PDDP template for Pd version
#X text 12 5 KEYWORDS control array filesystem;
#X text 12 165 RELEASE_DATE 1997;
#X restore 500 597 pd META;
#X obj 0 487 cnv 3 550 3 empty \$0-pddp.cnv.outlets outlets 8 12 0
13 -228856 -1 0;
#X obj 0 452 cnv 3 550 3 empty \$0-pddp.cnv.outlets outlets 8 12 0
13 #dcdcdc #000000 0;
#X obj 0 529 cnv 3 550 3 empty \$0-pddp.cnv.argument arguments 8 12
0 13 -228856 -1 0;
0 13 #dcdcdc #000000 0;
#X obj 0 554 cnv 3 550 3 empty \$0-pddp.cnv.more_info more_info 8 12
0 13 -228856 -1 0;
0 13 #dcdcdc #000000 0;
#X text 98 533 (none);
#N canvas 217 519 428 106 Related_objects 0;
#X obj 0 1 cnv 15 425 20 empty \$0-pddp.cnv.subheading empty 3 12 0
14 -204280 -1 0;
14 #c4dcdc #000000 0;
#X text 7 2 [soundfiler] Related Objects;
#X obj 22 43 tabwrite~;
#X obj 22 69 tabread4~;
......@@ -36,16 +36,16 @@ Wilkes revised the patch to conform to the PDDP template for Pd version
#X obj 143 69 writesf~;
#X obj 87 69 readsf~;
#X restore 102 597 pd Related_objects;
#X obj 78 396 cnv 17 3 80 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
-162280 0;
#X text 98 495 float;
#X obj 78 496 cnv 17 3 17 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
-162280 0;
#X obj 78 361 cnv 17 3 80 empty \$0-pddp.cnv.let.0 0 5 9 0 16 #dcdcdc
#9c9c9c 0;
#X text 98 460 float;
#X obj 78 461 cnv 17 3 17 empty \$0-pddp.cnv.let.0 0 5 9 0 16 #dcdcdc
#9c9c9c 0;
#X obj 477 10 soundfiler;
#X text 11 23 read and write soundfiles to arrays;
#X text 98 395 read;
#X text 98 412 write;
#X text 168 495 - the output specifies the total number of samples
#X text 98 360 read;
#X text 98 377 write;
#X text 168 460 - the output specifies the total number of samples
that have been read or written.;
#X obj 20 293 soundfiler;
#X floatatom 20 317 0 0 0 0 - - -;
......@@ -54,16 +54,16 @@ that have been read or written.;
#X text 322 224 write a file;
#X text 358 268 write stereo;
#N canvas 0 0 450 300 (subpatch) 0;
#X array sf-array1 77971 float 0;
#X coords 0 1 77971 -1 130 70 1;
#X restore 135 306 graph;
#X array sf-array1 77971 float 0 black black;
#X coords 0 1 77970 -1 130 50 1;
#X restore 185 296 graph;
#N canvas 0 0 450 300 (subpatch) 0;
#X array sf-array2 77971 float 0;
#X coords 0 1 77971 -1 130 70 1;
#X restore 288 306 graph;
#X array sf-array2 77971 float 0 black black;
#X coords 0 1 77970 -1 130 50 1;
#X restore 338 296 graph;
#N canvas 110 93 428 434 flags 0;
#X obj 0 0 cnv 15 425 20 empty \$0-pddp.cnv.subheading empty 3 12 0
14 -204280 -1 0;
14 #c4dcdc #000000 0;
#X text 19 37 When reading you can leave soundfiler to figure out which
of the three known soundfile formats the file belongs to or override
all header information using the "-raw" flag.;
......@@ -88,9 +88,9 @@ prefers.;
#X text 17 400 The number of channels is limited to 64;
#X text 37 371 -rate <sample rate>;
#X text 7 1 [soundfiler] Flags;
#X restore 172 459 pd flags;
#X text 168 412 - write a soundfile.;
#X text 169 428 The "read" and "write" messages accept flags. See the
#X restore 172 424 pd flags;
#X text 168 377 - write a soundfile.;
#X text 169 393 The "read" and "write" messages accept flags. See the
subpatch below for details:;
#X msg 20 138 read ../sound/bell.aiff sf-array2;
#X msg 20 161 read -resize ../sound/bell.aiff sf-array2;
......@@ -102,7 +102,7 @@ subpatch below for details:;
;
#X text 399 197 overriding everything;
#X text 398 183 ...or even;
#X text 168 395 - read a soundfile.;
#X text 168 360 - read a soundfile.;
#X text 17 41 The [soundfiler] object reads and writes floating point
arrays to binary soundfiles which may contain 2 or 3 byte fixed point
or 4 byte floating point samples in wave \, aiff \, or next formats
......@@ -113,7 +113,14 @@ and unsupplied channels are zeroed out).;
#X obj 4 597 pddp/pddplink all_about_help_patches.pd -text Usage Guide
;
#X obj 98 575 pddp/pddplink all_about_arrays.pd;
#X obj 78 497 cnv 17 3 17 empty \$0-pddp.cnv.let.0 0 5 9 0 16 #dcdcdc
#9c9c9c 0;
#X text 98 496 list;
#X obj 77 318 print sf_stats;
#X text 168 496 - stats for the file being read or written: <samplerate>
<headersize> <nchannels> <bytespersample> <endianness>;
#X connect 17 0 18 0;
#X connect 17 1 43 0;
#X connect 28 0 17 0;
#X connect 29 0 17 0;
#X connect 30 0 17 0;
......
......@@ -30,6 +30,7 @@ objects use Posix-like threads. */
#include <string.h>
#include <errno.h>
#include <math.h>
#include <limits.h>
#include "m_pd.h"
......@@ -207,6 +208,25 @@ static void swapstring(char *foo, int doit)
}
}
/* read sample rate from an 80-bit AIFF-compatible number */
static double readaiffsamprate(char *shit, int swap)
{
unsigned long mantissa, last = 0;
unsigned char exp;
swapstring(shit+2, swap);
mantissa = (unsigned long) *((unsigned long *)(shit+2));
exp = 30 - *(shit+1);
while (exp--)
{
last = mantissa;
mantissa >>= 1;
}
if (last & 0x00000001) mantissa++;
return mantissa;
}
/* write a sample rate as an 80-bit AIFF-compatible number */
static void makeaiffsamprate(double sr, unsigned char *shit)
{
......@@ -224,6 +244,28 @@ static void makeaiffsamprate(double sr, unsigned char *shit)
/******************** soundfile access routines **********************/
typedef struct _soundfile_info
{
int samplerate;
int channels;
int bytespersample;
int headersize;
int bigendian;
long bytelimit;
} t_soundfile_info;
static void outlet_soundfile_info(t_outlet *out, t_soundfile_info *info)
{
t_atom info_list[5];
SETFLOAT((t_atom *)info_list, (t_float)info->samplerate);
SETFLOAT((t_atom *)info_list+1,
(t_float)(info->headersize < 0 ? 0 : info->headersize));
SETFLOAT((t_atom *)info_list+2, (t_float)info->channels);
SETFLOAT((t_atom *)info_list+3, (t_float)info->bytespersample);
SETSYMBOL((t_atom *)info_list+4, gensym((info->bigendian ? "b" : "l")));
outlet_list(out, &s_list, 5, (t_atom *)info_list);
}
/* This routine opens a file, looks for either a nextstep or "wave" header,
* seeks to end of it, and fills in bytes per sample and number of channels.
* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
......@@ -233,19 +275,20 @@ static void makeaiffsamprate(double sr, unsigned char *shit)
* header and fill in the properties.
*/
int open_soundfile_via_fd(int fd, int headersize,
int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
long skipframes)
int open_soundfile_via_fd(int fd, t_soundfile_info *p_info, long skipframes)
{
int nchannels, bigendian, bytespersamp, swap, sysrtn;
long bytelimit = 0x7fffffff;
int nchannels, bigendian, bytespersamp, samprate, swap;
int headersize = 0;
long sysrtn, bytelimit = 0x7fffffff;
errno = 0;
if (headersize >= 0) /* header detection overridden */
if (p_info->headersize >= 0) /* header detection overridden */
{
bigendian = *p_bigendian;
nchannels = *p_nchannels;
bytespersamp = *p_bytespersamp;
bytelimit = *p_bytelimit;
headersize = p_info->headersize;
bigendian = p_info->bigendian;
nchannels = p_info->channels;
bytespersamp = p_info->bytespersample;
bytelimit = p_info->samplerate;
samprate = p_info->samplerate;
}
else
{
......@@ -288,6 +331,7 @@ int open_soundfile_via_fd(int fd, int headersize,
bytespersamp = 4;
else goto badheader;
bytelimit = 0x7fffffff;
samprate = swap4(((t_nextstep *)buf)->ns_sr, swap);
}
else if (format == FORMAT_WAVE) /* wave header */
{
......@@ -302,6 +346,7 @@ int open_soundfile_via_fd(int fd, int headersize,
no "fmt" chunk to follow. */
nchannels = 1;
bytespersamp = 2;
samprate = 44100;
/* copy the first chunk header to beginnning of buffer. */
memcpy(buf, buf + headersize, sizeof(t_wavechunk));
/* post("chunk %c %c %c %c",
......@@ -333,8 +378,10 @@ int open_soundfile_via_fd(int fd, int headersize,
else if (format == 32)
bytespersamp = 4;
else goto badheader;
samprate = swap4(
((t_fmt *)buf)->f_samplespersec, swap);
}
seekout = lseek(fd, seekto, SEEK_SET);
seekout = (long)lseek(fd, seekto, SEEK_SET);
if (seekout != seekto)
goto badheader;
if (read(fd, buf, sizeof(t_wavechunk)) <
......@@ -345,7 +392,7 @@ int open_soundfile_via_fd(int fd, int headersize,
((t_wavechunk *)buf)->wc_id[1],
((t_wavechunk *)buf)->wc_id[2],
((t_wavechunk *)buf)->wc_id[3], seekto); */
headersize = seekto;
headersize = (int)seekto;
}
bytelimit = swap4(((t_wavechunk *)buf)->wc_size, swap);
headersize += 8;
......@@ -360,6 +407,7 @@ int open_soundfile_via_fd(int fd, int headersize,
no COMM block to follow. */
nchannels = 1;
bytespersamp = 2;
samprate = 44100;
/* copy the first chunk header to beginnning of buffer. */
memcpy(buf, buf + headersize, sizeof(t_datachunk));
/* read chunks in loop until we get to the data chunk */
......@@ -390,21 +438,23 @@ int open_soundfile_via_fd(int fd, int headersize,
else if (format == 24)
bytespersamp = 3;
else goto badheader;
samprate = readaiffsamprate(
(char *)((t_comm *)buf)->c_samprate, swap);
}
seekout = lseek(fd, seekto, SEEK_SET);
seekout = (long)lseek(fd, seekto, SEEK_SET);
if (seekout != seekto)
goto badheader;
if (read(fd, buf, sizeof(t_datachunk)) <
(int) sizeof(t_datachunk))
goto badheader;
headersize = seekto;
headersize = (int)seekto;
}
bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap) - 8;
headersize += sizeof(t_datachunk);
}
}
/* seek past header and any sample frames to skip */
sysrtn = lseek(fd,
sysrtn = (long)lseek(fd,
((off_t)nchannels) * bytespersamp * skipframes + headersize, 0);
if (sysrtn != nchannels * bytespersamp * skipframes + headersize)
return (-1);
......@@ -412,10 +462,12 @@ int open_soundfile_via_fd(int fd, int headersize,
if (bytelimit < 0)
bytelimit = 0;
/* copy sample format back to caller */
*p_bigendian = bigendian;
*p_nchannels = nchannels;
*p_bytespersamp = bytespersamp;
*p_bytelimit = bytelimit;
p_info->headersize = headersize;
p_info->bigendian = bigendian;
p_info->channels = nchannels;
p_info->bytespersample = bytespersamp;
p_info->bytelimit = bytelimit;
p_info->samplerate = samprate;
return (fd);
badheader:
/* the header wasn't recognized. We're threadable here so let's not
......@@ -427,17 +479,15 @@ badheader:
/* open a soundfile, using open_via_path(). This is used by readsf~ in
a not-perfectly-threadsafe way. LATER replace with a thread-hardened
version of open_soundfile_via_canvas() */
int open_soundfile(const char *dirname, const char *filename, int headersize,
int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
long skipframes)
int open_soundfile(const char *dirname, const char *filename,
t_soundfile_info *p_info, long skipframes)
{
char buf[FILENAME_MAX], *bufptr;
int fd, sf_fd;
fd = open_via_path(dirname, filename, "", buf, &bufptr, FILENAME_MAX, 1);
if (fd < 0)
return (-1);
sf_fd = open_soundfile_via_fd(fd, headersize, p_bytespersamp,
p_bigendian, p_nchannels, p_bytelimit, skipframes);
sf_fd = open_soundfile_via_fd(fd, p_info, skipframes);
if (sf_fd < 0)
sys_close(fd);
return (sf_fd);
......@@ -446,17 +496,15 @@ int open_soundfile(const char *dirname, const char *filename, int headersize,
/* open a soundfile, using open_via_canvas(). This is used by readsf~ in
a not-perfectly-threadsafe way. LATER replace with a thread-hardened
version of open_soundfile_via_canvas() */
int open_soundfile_via_canvas(t_canvas *canvas, const char *filename, int headersize,
int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
long skipframes)
int open_soundfile_via_canvas(t_canvas *canvas, const char *filename,
t_soundfile_info *p_info, long skipframes)
{
char buf[FILENAME_MAX], *bufptr;
int fd, sf_fd;
fd = canvas_open(canvas, filename, "", buf, &bufptr, FILENAME_MAX, 1);
if (fd < 0)
return (-1);
sf_fd = open_soundfile_via_fd(fd, headersize, p_bytespersamp,
p_bigendian, p_nchannels, p_bytelimit, skipframes);
sf_fd = open_soundfile_via_fd(fd, p_info, skipframes);
if (sf_fd < 0)
sys_close(fd);
return (sf_fd);
......@@ -464,7 +512,7 @@ int open_soundfile_via_canvas(t_canvas *canvas, const char *filename, int header
static void soundfile_xferin_sample(int sfchannels, int nvecs, t_sample **vecs,
long itemsread, unsigned char *buf, int nitems, int bytespersamp,
int bigendian, int spread)
int bigendian)
{
int i, j;
unsigned char *sp, *sp2;
......@@ -478,14 +526,14 @@ static void soundfile_xferin_sample(int sfchannels, int nvecs, t_sample **vecs,
{
if (bigendian)
{
for (j = 0, sp2 = sp, fp=vecs[i] + spread * itemsread;
j < nitems; j++, sp2 += bytesperframe, fp += spread)
for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
j < nitems; j++, sp2 += bytesperframe, fp++)
*fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
}
else
{
for (j = 0, sp2 = sp, fp=vecs[i] + spread * itemsread;
j < nitems; j++, sp2 += bytesperframe, fp += spread)
for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
j < nitems; j++, sp2 += bytesperframe, fp ++)
*fp = SCALE * ((sp2[1] << 24) | (sp2[0] << 16));
}
}
......@@ -493,15 +541,15 @@ static void soundfile_xferin_sample(int sfchannels, int nvecs, t_sample **vecs,
{
if (bigendian)
{
for (j = 0, sp2 = sp, fp=vecs[i] + spread * itemsread;
j < nitems; j++, sp2 += bytesperframe, fp += spread)
for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
j < nitems; j++, sp2 += bytesperframe, fp++)
*fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
| (sp2[2] << 8));
}
else
{
for (j = 0, sp2 = sp, fp=vecs[i] + spread * itemsread;
j < nitems; j++, sp2 += bytesperframe, fp += spread)
for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
j < nitems; j++, sp2 += bytesperframe, fp ++)
*fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
| (sp2[0] << 8));
}
......@@ -510,8 +558,8 @@ static void soundfile_xferin_sample(int sfchannels, int nvecs, t_sample **vecs,
{
if (bigendian)
{
for (j = 0, sp2 = sp, fp=vecs[i] + spread * itemsread;
j < nitems; j++, sp2 += bytesperframe, fp += spread)
for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
j < nitems; j++, sp2 += bytesperframe, fp++)
{
alias.ui = ((sp2[0] << 24) | (sp2[1] << 16)
| (sp2[2] << 8) | sp2[3]);
......@@ -520,8 +568,8 @@ static void soundfile_xferin_sample(int sfchannels, int nvecs, t_sample **vecs,
}
else
{
for (j = 0, sp2 = sp, fp=vecs[i] + spread * itemsread;
j < nitems; j++, sp2 += bytesperframe, fp += spread)
for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
j < nitems; j++, sp2 += bytesperframe, fp++)
{
alias.ui = ((sp2[3] << 24) | (sp2[2] << 16)
| (sp2[1] << 8) | sp2[0]);
......@@ -626,115 +674,294 @@ static void soundfile_xferin_float(int sfchannels, int nvecs, t_float **vecs,
-little
*/
static void argerror(void *obj, t_symbol *s, int argc, t_atom *argv,
const char *fmt, ...)
{
char error_str[MAXPDSTRING];
char *user_msg; /* message from user that triggered the error */
int len;
char *classname = class_getname(pd_class((t_pd *)obj));
va_list ap;
t_binbuf *b = binbuf_new();
va_start(ap, fmt);
vsnprintf(error_str, MAXPDSTRING-1, fmt, ap);
va_end(ap);
binbuf_addv(b, "s", s);
binbuf_add(b, argc, argv);
binbuf_gettext(b, &user_msg, &len); /* not null-terminated! */
pd_error(obj, "%s: '%.*s': %s",
classname,
len < MAXPDSTRING ? len : MAXPDSTRING,
user_msg,
error_str);
}
static int flag_missing_floatarg(void *obj, t_symbol *s, int argc,
t_atom *argv, char *flag, int flagc, t_atom *flagv)
{
/* First check if our flag has an arg at all. If not, error out.
(flagc includes the flag itself.) */
if (flagc < 2)
{
argerror(obj, s, argc, argv,
"'%s' flag expects a float argument", flag);
return 1;
}
if (flagv[1].a_type != A_FLOAT)
{
argerror(obj, s, argc, argv, "'%s' flag expects a float but got '%s'",
flag,
flagv[1].a_type == A_SYMBOL ?
flagv[1].a_w.w_symbol->s_name :
"unexpected arg type");
return 1;
}
return 0;
}
static int flag_has_unexpected_floatarg(void *obj, t_symbol *s,
int argc, t_atom *argv, char *flag, int flagc, t_atom *flagv)
{
if (flagc < 2) return 0;
if (flagv[1].a_type == A_FLOAT)
{
argerror(obj, s, argc, argv,
"'%s' flag does not accept a float argument", flag);
return 1;
}
return 0;
}
/* catch filenames that are flags, with and without pre-fixed '-' */
static int file_is_a_flag_name(t_symbol *sym, int *nodash)
{
char *s = sym->s_name;
if (s[0] == '-')
{
s++;
*nodash = 1;
}
else
*nodash = 0;
if (!strcmp(s, "skip")
|| !strcmp(s, "nframes")
|| !strcmp(s, "bytes")
|| !strcmp(s, "normalize")
|| !strcmp(s, "wave")
|| !strcmp(s, "nextstep")
|| !strcmp(s, "aiff")
|| !strcmp(s, "big")
|| !strcmp(s, "little")
|| !strcmp(s, "r")
|| !strcmp(s, "rate"))
{
return 1;
}
else
return 0;
}
/* the routine which actually does the work should LATER also be called
from garray_write16. */
/* Parse arguments for writing. The "obj" argument is only for flagging
errors. For streaming to a file the "normalize", "onset" and "nframes"
errors. For streaming to a file the "normalize", "skip" and "nframes"
arguments shouldn't be set but the calling routine flags this. */
static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
/* Also note that streaming objects like writesf~ don't take args after
the filename, while soundfiler does to specify the source tables */
static int soundfiler_writeargparse(void *obj, t_symbol *s,
int *p_argc, t_atom **p_argv,
t_symbol **p_filesym,
int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
int *p_normalize, long *p_onset, long *p_nframes, t_float *p_rate)
{
/* copies for convenience, and for the ruthless mutation below. :) */
int argc = *p_argc;
int ac = argc;
t_atom *argv = *p_argv;
t_atom *av = argv;
int bytespersamp = 2, bigendian = 0,
endianness = -1, swap, filetype = -1, normalize = 0;
long onset = 0, nframes = 0x7fffffff;
t_symbol *filesym;
t_float rate = -1;
while (argc > 0 && argv->a_type == A_SYMBOL &&
*argv->a_w.w_symbol->s_name == '-')
while (ac > 0 && atom_getsymbol(av)->s_name[0] == '-')
{
char *flag = argv->a_w.w_symbol->s_name + 1;
if (!strcmp(flag, "skip"))
char *flag = av->a_w.w_symbol->s_name;
if (!strcmp(flag, "-skip"))
{
if (argc < 2 || argv[1].a_type != A_FLOAT ||
((onset = argv[1].a_w.w_float) < 0))
goto usage;
argc -= 2; argv += 2;
if (flag_missing_floatarg(obj, s, argc, argv, flag, ac, av))
goto usage;
if ((onset = av[1].a_w.w_float) < 0)
{
argerror(obj, s, argc, argv,
"'-skip' flag does not allow a negative number");
goto usage;
}
ac -= 2; av += 2;
}
else if (!strcmp(flag, "nframes"))
else if (!strcmp(flag, "-nframes"))
{
if (argc < 2 || argv[1].a_type != A_FLOAT ||
((nframes = argv[1].a_w.w_float) < 0))
goto usage;
argc -= 2; argv += 2;
if (flag_missing_floatarg(obj, s, argc, argv, flag, ac, av))
goto usage;
if ((nframes = av[1].a_w.w_float) < 0)
{
argerror(obj, s, argc, argv,
"'-nframes' flag does not allow a negative number");
goto usage;
}
ac -= 2; av += 2;
}
else if (!strcmp(flag, "bytes"))
else if (!strcmp(flag, "-bytes"))
{
if (argc < 2 || argv[1].a_type != A_FLOAT ||
((bytespersamp = argv[1].a_w.w_float) < 2) ||
bytespersamp > 4)
goto usage;
argc -= 2; argv += 2;
if (flag_missing_floatarg(obj, s, argc, argv, flag, ac, av))
goto usage;
if ((bytespersamp = av[1].a_w.w_float) < 2 ||
bytespersamp > 4)
{
argerror(obj, s, argc, argv,
"'-bytes' flag requires a number between 2 and 4");
goto usage;
}
ac -= 2; av += 2;
}
else if (!strcmp(flag, "normalize"))
else if (!strcmp(flag, "-normalize"))
{
if (flag_has_