ftp.nice.ch/pub/next/unix/audio/cmusic.bs.N.tar.gz#/NeXT_updates/sndio/sndio.c

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.