This is sndio.c in view mode; [Download] [Up]
#import "sndio.h"
int main(int argc, char *argv[])
{
char *filename, // input soundfile name
*cbegi, // for begin frame input char
*cendi, // for end frame input char
*cfmati, // input format string (if headless)
*cchani, // input # channels string (if headless)
*csrate, // desired output sample rate as string
*info, // for output header info string
*new_info, // new info for output header
*cbego, // for begin frame input char
*cendo, // for end frame input char
*cfmato; // output format char
int pipe_in, // is input a pipe flag
otty, // is output tty flag
overwrite, // overwrite/pad output file
headi, // no input header flag
heado, // write header to output flag
begi; // first sample to copy
unsigned int endi; // last sample to copy
int fmati, // input format value
chani, // # of input channel (if headless)
srate, // output sample rate
dataSize, // size of sample data
infoSize, // size of header info
bego, // first sample to overwrite
endo, // last sample to overwrite
chano, // # of output channels
fmato; // output format value
char efmati, // end sample input format char
efmato, // end sample output format char
infotype, // header info field type
ch; // tmp used with crack()
FILE *infofp = NULL; // header info file pointer
SNDSoundStruct *sndin,*sndout; // input and output soundfile pointers
short *s_top; // pointers to input samples
float *f_top;
struct stat buf_size; // size of headless input file
int clip, // ftos() clipped flag
err; // snd errors
short s_pad = 0; // output padding values
float f_pad = 0.0;
cbegi = NULL; // set up default values and flags
cendi = NULL;
cfmati = NULL;
cchani = NULL;
chanspec = NULL;
csrate = NULL;
info = NULL;
new_info = NULL;
cbego = NULL;
cendo = NULL;
cfmato = NULL;
in_index = 'x'; // x is filler
out_index = 'x'; // x is filler
clip = NO;
overwrite = NO;
sndin = NULL;
sndout = NULL;
heado = YES;
headi = YES;
begi = 0;
fmati = SND_FORMAT_LINEAR_16;
chani = 1;
srate = SND_RATE_HIGH;
infoSize = 4;
ascii_in = NO;
ascii_out = NOTSET;
// set up user defined variables
itty = isatty(0); // 0 == stdin
otty = isatty(1); // 1 == stdout
// was != NULL
while((ch = crack(argc,argv,"b|e|d|f|c|r|I|i|a|B|E|D|F|C|A|Hu",0)) != 0) {
switch(ch) {
case 'b': cbegi = arg_option; break;
case 'e': efmati = ch; cendi = arg_option; break;
case 'd': efmati = ch; cendi = arg_option; break;
case 'f': cfmati = arg_option; break; // no input header input format
case 'c': cchani = arg_option; break; // no input header input chan #
case 'r': csrate = arg_option; break; // no input header input srate
case 'a': ascii_in = YES;
in_index = *arg_option; break; // arabic input
case 'I': infotype = ch; new_info = arg_option; break;
case 'i': infotype = ch; new_info = arg_option; break;
case 'B': cbego = arg_option;
overwrite = YES; break;
case 'E': efmato = ch; cendo = arg_option;
overwrite = YES; break;
case 'D': efmato = ch; cendo = arg_option;
overwrite = YES; break;
case 'F': cfmato = arg_option; break;
case 'C': chanspec = arg_option; break;
case 'A': ascii_out = YES; // force arabic output
out_index = *arg_option; break;
case 'H': heado = NO; break; // no output header
case 'u': usage(0); // help (usage)
default: usage(1);
}
}
if(itty) { // input is a file (i.e. not a pipe)
pipe_in = NO;
if(argc == arg_index) { // no file on commandline
fprintf(stderr,"sndio error: No input file.\n");
exit(2);
}
filename = argv[arg_index];
if((err = SNDReadSoundfile(filename,&sndin)) == SND_ERR_NONE) ifp = NULL;
else if(err == SND_ERR_NOT_SOUND) { // no sndheader input file
if((ifp = fopen(filename,"r")) == NULL) {
fprintf(stderr,"sndio error: Can't open `%s'.\n",filename);
exit(3);
}
headi = NO;
}
else check_error(err); // snd exit mode
ofp = stdout; // output cannot be a file
}
else { // input is a pipe
pipe_in = YES;
ifp = stdin;
err = SNDReadHeaderFromStream(&sndin,ifp);
if(err == SND_ERR_NOT_SOUND) headi = NO; // no sndheader
else if(err != SND_ERR_NONE) check_error(err); // sndheader bad
if(argc != arg_index) { // output file found on commandline
if(ascii_out == NOTSET) ascii_out = NO; // not ascii unless user says it is
filename = argv[arg_index];
if((ofp = fopen(filename,"r+")) == NULL) { // does file exist (overwrite)
if((ofp = fopen(filename,"w")) == NULL) { // create new file
fprintf(stderr,"sndio error: Can't open `%s'.\n",filename);
exit(4);
}
}
}
else ofp = stdout;
}
if(ascii_out == NOTSET) {
if(otty) ascii_out = YES;
else ascii_out = NO;
}
if(ascii_out == YES) heado = NO; // if output is tty (ascii)
if(new_info != NULL) { // new sndheader "info" from user
if(infotype == 'I') {
infoSize = (strlen(new_info)) + 1;
if(infoSize < 4) infoSize = 4;
info = (char *) malloc(sizeof(char) * infoSize);
strncpy(info,new_info,infoSize - 1);
}
else if(infotype == 'i') {
if((infofp = fopen(new_info,"r")) == NULL) {
fprintf(stderr,"sndio error: Can't open `%s'.\n",new_info);
exit(5);
}
stat(new_info,&buf_size);
infoSize = buf_size.st_size + 1;
if(infoSize < 4) infoSize = 4;
info = (char *) malloc(sizeof(char) * infoSize);
fread(info,sizeof(char),infoSize,infofp);
fclose(infofp);
}
}
if(headi == YES) { // get input header info
fmati = sndin->dataFormat; // is format supported?
if(fmati != SND_FORMAT_LINEAR_16 &&
fmati != SND_FORMAT_FLOAT ) check_error(SND_ERR_BAD_FORMAT);
chani = sndin->channelCount;
srate = sndin->samplingRate;
dataSize = sndin->dataSize;
if(info == NULL) {
infoSize = sndin->dataLocation - (sizeof(int) * HEADNOINFO);
if(infoSize < 4) infoSize = 4;
info = (char *) malloc(sizeof(char) * infoSize);
strncpy(info,sndin->info,infoSize - 1);
}
}
else { // create input header info
if(cfmati != NULL) {
if(*cfmati == SND16BITSHORT) fmati = SND_FORMAT_LINEAR_16;
else if(*cfmati == SND32BITFLOAT) fmati = SND_FORMAT_FLOAT;
else check_error(SND_ERR_BAD_FORMAT);
}
if(cchani != NULL) chani = sfexpr(cchani,1.0);
if(csrate != NULL) srate = sfexpr(csrate,1.0);
if(pipe_in == NO && ascii_in == NO) {
stat(filename,&buf_size); // get ->dataSize from binary file
dataSize = buf_size.st_size;
}
else dataSize = 0; // dataSize should not be used but want to be safe
}
if(cfmato == NULL) fmato = fmati; // set data format for output
else {
if(*cfmato == SND16BITSHORT) fmato = SND_FORMAT_LINEAR_16;
else if(*cfmato == SND32BITFLOAT) fmato = SND_FORMAT_FLOAT;
else check_error(SND_ERR_BAD_FORMAT);
}
if(cbegi != NULL) { // do boundary calculations on sample frames
begi = (sfexpr(cbegi,(float) srate)) * chani;
if (begi < 0) begi = 0;
}
if(cendi != NULL) {
if(efmati == 'e') endi = (sfexpr(cendi,(float) srate)) * chani;
else /* == 'd' */ endi = (begi + sfexpr(cendi,(float) srate)) * chani;
if(pipe_in == NO && ascii_in == NO) { // can't be larger than input data
if(fmati == SND_FORMAT_LINEAR_16 && endi > (dataSize >> 1)) endi = dataSize >> 1;
else if(fmati == SND_FORMAT_FLOAT && endi > (dataSize >> 2)) endi = dataSize >> 2;
}
else if(endi < 0) endi = 0; // just because its there
}
else if(pipe_in == NO && ascii_in == NO) { // set to end of file
if(fmati == SND_FORMAT_LINEAR_16) endi = dataSize >> 1;
else if(fmati == SND_FORMAT_FLOAT) endi = dataSize >> 2;
}
else endi = MAXFILESIZE; // set to monster size
chano = setchan(chanspec,chani); // set output channels
if(chano == NO) check_error(SND_ERR_BAD_CHANNEL); // no channels remain!
if(cbego != NULL) bego = (sfexpr(cbego,(float) srate)) * chano;
else bego = 0;
if(cendo != NULL) {
if(efmato == 'E') endo = (sfexpr(cendo,(float) srate)) * chani;
else /* == 'D' */ endo = (bego + sfexpr(cendo,(float) srate)) * chani;
}
else endo = endi;
if(heado == YES) { // alloc output header
check_error(SNDAlloc(&sndout,0,fmato,srate,chano,infoSize));
if(info != NULL) strncpy(sndout->info,info,infoSize - 1);
fwrite((void *) sndout,sizeof(char),sndout->dataLocation,ofp);
}
samrate = (float) srate; // set sample rate for ascii output
if(overwrite == YES && ascii_out == NO) { // advance output pointer of pad
switch(fmato) {
case SND_FORMAT_LINEAR_16: // by shorts
if(bego > 0) fseek(ofp,(unsigned long) (bego * sizeof(short)),SEEK_CUR);
else if(bego < 0) {
for( ; bego < 0; bego++) fwrite((void *) &s_pad,sizeof(short),1,ofp);
}
break;
case SND_FORMAT_FLOAT: // by floats
if(bego > 0) fseek(ofp,(unsigned long) (bego * sizeof(float)),SEEK_CUR);
else if(bego < 0) {
for( ; bego < 0; bego++) fwrite((void *) &f_pad,sizeof(float),1,ofp);
}
break;
}
}
switch(fmati) { // convert and output input data
case SND_FORMAT_LINEAR_16: // input is short
if(ascii_in == YES) tobegi(begi,SND_FORMAT_LINEAR_16);
else if(pipe_in == NO && headi == YES) { // set pointer to short samples
s_top = (void *) (((char *) sndin) + sndin->dataLocation);
s_top = (s_top + begi);
}
else if(begi != 0) fseek(ifp,(unsigned long) (begi * sizeof(short)),SEEK_CUR);
switch(fmato) {
case SND_FORMAT_LINEAR_16: // output is short
if(ascii_in == YES) stosa(ifp,begi,endi,chani); // ascii input
else if(pipe_in == YES) stosp(ifp,begi,endi,chani); // pipe in
else if(headi == YES) stos(s_top,begi,endi,chani); // sndfile in
else stoshf(ifp,begi,endi,chani); // headless file
break;
case SND_FORMAT_FLOAT: // output is float
if(ascii_in == YES) stofa(ifp,begi,endi,chani);
else if(pipe_in == YES) stofp(ifp,begi,endi,chani);
else if(headi == YES) stof(s_top,begi,endi,chani);
else stofhf(ifp,begi,endi,chani);
break;
}
break;
case SND_FORMAT_FLOAT: // input is float
if(ascii_in == YES) tobegi(begi,SND_FORMAT_FLOAT);
else if(pipe_in == NO && headi == YES) { // set pointer to float samples
f_top = (void *) (((char *) sndin) + sndin->dataLocation);
f_top = (f_top + begi);
}
else if(begi != 0) fseek(ifp,(unsigned long) (begi * sizeof(float)),SEEK_CUR);
switch (fmato) {
case SND_FORMAT_LINEAR_16: // output is short
if(ascii_in == YES) clip = ftosa(ifp,begi,endi,chani);
else if(pipe_in == YES) clip = ftosp(ifp,begi,endi,chani);
else if(headi == YES) clip = ftos(f_top,begi,endi,chani);
else clip = ftoshf(ifp,begi,endi,chani);
if(clip != 0) {
fprintf(stderr,"\nsndio error: %d clipped samples.\n\n",clip);
}
break;
case SND_FORMAT_FLOAT: // output is float
if(ascii_in == YES) ftofa(ifp,begi,endi,chani);
else if(pipe_in == YES) ftofp(ifp,begi,endi,chani);
else if(headi == YES) ftof(f_top,begi,endi,chani);
else ftofhf(ifp,begi,endi,chani);
break;
}
break;
default: break; // can't happen! safty net
}
if(endo > endi) { // pad output file
int inc,floor,y = -1;
switch(fmato) {
case SND_FORMAT_LINEAR_16: // pad is short
if(ascii_out == YES) { // and ascii
if(out_index == 's') { // sample indexed
for(inc = endi; inc < endo; inc++) {
if(chans[++y >= chani ? (y = 0) : y]) {
fprintf(ofp,"%d\t0\n",(int) inc / chani);
}
}
}
else if(out_index == 't') { // time indexed
for(inc = endi; inc < endo; inc++) {
if(chans[++y >= chani ? (y = 0) : y]) {
floor = (int) inc / chani;
fprintf(ofp,"%f\t0\n",((float) floor) / samrate);
}
}
}
else { // no index
for(inc = endi; inc < endo; inc++) {
if(chans[++y >= chani ? (y = 0) : y]) fprintf(ofp,"0\n");
}
}
}
else {
for(inc = endi; inc < endo; inc++) {
if(chans[++y >= chani ? (y = 0) : y]) {
fwrite((void *) &s_pad,sizeof(short),1,ofp);
}
}
}
break;
case SND_FORMAT_FLOAT: // pad is float
if(ascii_out == YES) { // and ascii
if(out_index == 's') { // sample indexed
for(inc = endi; inc < endo; inc++) {
if(chans[++y >= chani ? (y = 0) : y]) {
fprintf(ofp,"%d\t0.0\n",(int) inc / chani);
}
}
}
else if(out_index == 't') { // time indexed
for(inc = endi; inc < endo; inc++) {
if(chans[++y >= chani ? (y = 0) : y]) {
floor = (int) inc / chani;
fprintf(ofp,"%f\t0.0\n",((float) floor) / samrate);
}
}
}
else { // no index
for(inc = endi; inc < endo; inc++) {
if(chans[++y >= chani ? (y = 0) : y]) fprintf(ofp,"0.0\n");
}
}
}
else {
for(inc = endi; inc < endo; inc++) {
if(chans[++y >= chani ? (y = 0) : y]) {
fwrite((void *) &f_pad,sizeof(float),1,ofp);
}
}
}
break;
}
}
if(ifp != NULL) fclose(ifp); // clean house
if(ofp != NULL) fclose(ofp);
free(info);
SNDFree(sndin);
SNDFree(sndout);
exit(0);
}
// advances ascii input stream to point begin
void tobegi(long begin,int format)
{
unsigned long inc; // actual number of smaples in sobuf[]
switch(format) { // advance pointer thru output data
case SND_FORMAT_LINEAR_16: // advance shorts
switch(in_index) {
case 's':
for(inc = 0; inc < begin; inc++) {
if(fscanf(ifp,"%*d %*d") == EOF) break;
}
break;
case 't':
for(inc = 0; inc < begin; inc++) {
if(fscanf(ifp,"%*f %*d") == EOF) break;
}
break;
default:
for(inc = 0; inc < begin; inc++) {
if(fscanf(ifp,"%*d") == EOF) break;
}
break;
}
break;
case SND_FORMAT_FLOAT: // advance floats
switch(in_index) {
case 's':
for(inc = 0; inc < begin; inc++) {
if(fscanf(ifp,"%*d %*f") == EOF) break;
}
break;
case 't':
for(inc = 0; inc < begin; inc++) {
if(fscanf(ifp,"%*f %*f") == EOF) break;
}
break;
default:
for(inc = 0; inc < begin; inc++) {
if(fscanf(ifp,"%*f") == EOF) break;
}
break;
}
break;
}
}
int check_error(int err)
{
if(err) {
fprintf(stderr,"sndio error: %s\n",SNDSoundError(err));
exit(err);
}
return err;
}
int usage(int x)
{
fprintf(stderr,"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
"\nusage:\tsndio [flags] input_file > output\n",
"\tsndio [flags] output_file < input\n",
"\tsndio [flags] < input > output\n",
"flags:\t-bN\tsets begin time of input to N [default: 0.0].\n",
"\t-eN\tsets end time of input to N [end of input data].\n",
"\t-dN\tsets duration of input to N [end of input data].\n",
"\t-aX\tarabic (ascii) input. X denotes sample indexing format.\n",
"\t\tX = t, time index; X = s, sample numbers; no X, no index.\n",
"\t-fX\tsets format for headless input to X (see -F below) [s].\n",
"\t-cN\tsets number of channels for headless input to N [1].\n",
"\t-rN\tsets sample rate of headless input to N [44100].\n",
"\t-IS\tS is an info string (without white chars) for output header.\n",
"\t-iS\tS is an file name containing info for output header.\n",
"\t-BN\tsets output begin time to N (for padding or overwrite) [0.0].\n",
"\t-EN\tsets output end time to N (for padding) [-e value].\n",
"\t-DN\tsets output duration to N (for padding) [-e value].\n",
"\t-CS\tS is a comma-separated list of selected output channels.\n",
"\t-FX\tX overrides (converts) default output format, X can be:\n",
"\t\t\tf - pipe: 32 bit floats; tty: floating point.\n",
"\t\t\ts - pipe: 16 bit ints; tty: integer.\n",
"\t-AX\tforce arabic output, X sets indexing format (see -a above).\n",
"\t-H\tsuppress generating sound file header for output.\n",
"\t-u\tprints this usage information.\n"
);
exit(x);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.