/*
 *	Fromsnd.c -- read a NeXT format soundfile and write samples to stdout
 *		stp - 8/89, last update - 4/92
 *
 *		usage: fromsnd [-b # [-d # | -e #] -c # -x -f -u -m # ] file > output
 *		   -b X  begin at sample frame X [0 by default]
 *		   -d X  duration is X sample frames [EOF by default]
 *		   -e X  end at sample frame X [EOF by default]
 *		   -c X  selects channel X [all channels by default]
 *		            (channels are numbered from 0)
 *		   -x    specifies byte-wise reversal [not reversed]
 *		   -m X  multiply samples by X [1.0 by default]
 *		   -f    write floating-point samples [integers by default]
 *		   -u 	 to print usage
 */
#include <stdio.h>
#include <sound/sound.h>
#include <sys/file.h>

SNDSoundStruct *snd;

main(argc, argv) int argc; char *argv[]; {
	int 	i, fd, chancount = 0, whichchan = 0, beginsamp = 0,
			endsamp = -1, samp = 0, byterev = 0, floatout = 0, scale = 0;
	FILE 	*fp;
	short	*sampframe, sample;
	float	*fsampframe, fsample, multiplier = 0.0;
	double  atof();
	char	c;
	extern char		*optarg;
	extern int		optind, opterr;

	if (argc == 1)
		usage();
				/******* Process Command-line Arguments ***********/
	while ((c = getopt(argc, argv, "uxfb:d:e:c:m:")) != -1) 
		switch (c) {
		case 'c':
			chancount = 1;
			whichchan = atoi(optarg);
			fprintf(stderr, 
				"fromsnd: set up for mono, channel %d\n", whichchan);
			break;
		case 'x':
			byterev++;
			fprintf(stderr, "fromsnd: set up for byte reversal\n");
			break;
		case 'b':
			beginsamp = atoi(optarg);
			fprintf(stderr, "fromsnd: begin at sample %d\n", beginsamp);
			break;
		case 'e':
			endsamp = atoi(optarg);
			fprintf(stderr, "fromsnd: end at sample %d\n", endsamp);
			break;
		case 'm':
			multiplier = (float) atof(optarg);
			scale++;
			fprintf(stderr, "fromsnd: multiply samples by %f\n", multiplier);
			break;
		case 'd':
			endsamp = beginsamp + atoi(optarg);
			fprintf(stderr, "fromsnd: read %d samples\n", atoi(optarg));
			break;
		case 'f':
			floatout++;
			fprintf(stderr, "fromsnd: set up for floating-point output\n");
			break;
		case 'u':
			usage();
			break;
	}
	if ((fd = open(argv[argc - 1], O_CREAT | O_RDONLY, 0644)) < 0) {
		fprintf(stderr, "fromsnd: Unable to open '%s'\n", argv[argc - 1]);
		exit(-1);
	}
	snd = (SNDSoundStruct *) calloc(sizeof(SNDSoundStruct), 1);
	if(snd == NULL) {
		fprintf(stderr, "fromsnd: Unable to allocate space\n");
		exit(-1);
	}
	SNDReadHeader(fd, snd);
	if (snd->magic != SND_MAGIC) {
		fprintf(stderr, "fromsnd: '%s' not a soundfile\n", argv[argc - 1]);
		exit(-1);
	}
	if ((fp = fdopen(fd, "r")) == NULL) {
		fprintf(stderr, "fromsnd: Unable to fdopen '%s'\n", argv[argc - 1]);
		exit(-1);
	}
	sampframe = (short *) calloc(sizeof(short), snd->channelCount);
	if(sampframe == NULL) {
		fprintf(stderr, "fromsnd: Unable to allocate space\n");
		exit(-1);
	}
	if (floatout) {
		fsampframe = (float *) calloc(sizeof(float), snd->channelCount);
		if(fsampframe == NULL) {
			fprintf(stderr, "fromsnd: Unable to allocate space\n");
			exit(-1);
		}
	}
	rewind(fp);
	for (i = 0; i < snd->dataLocation; i++)
		fread(sampframe, 1, 1, fp);
	for (i = 0; i < beginsamp; i++) {
		fread(sampframe, sizeof(short), snd->channelCount, fp);
		++samp;
	}
	if (chancount == 0)
		chancount = snd->channelCount;
	while (fread(sampframe, sizeof(short), snd->channelCount, fp) != 0) {
		if (floatout) {
			for (i = 0; i < snd->channelCount; i++) {
				*(fsampframe + i) = (float) *(sampframe + i) / 32768.0;
				if (scale)
					*(fsampframe + i) *= multiplier;
			}
			fwrite(fsampframe + whichchan, sizeof(float), chancount, stdout);
		} else {
			if (byterev)
				for (i = 0; i < snd->channelCount; i++) {
					sample = *(sampframe + i);
					sample = (sample << 8) | ((sample >> 8) & 0xff);
					*(sampframe + i) = sample;
				}
			if (scale) 
				for (i = 0; i < snd->channelCount; i++) {
					sample = *(sampframe + i);
					*(sampframe + i) = (int) ((float) sample * multiplier);
				}
			fwrite(sampframe + whichchan, sizeof(short), chancount, stdout);
		}
		if (++samp > endsamp && endsamp >= 0)
			break;
	}
	fclose(fp);
}

usage() {
	fprintf(stderr,
		"\n\nfromsnd [-b # [-d # | -e #] -c # -x -f -u -m # ] file | output\n");
	fprintf(stderr,
		"   -b #  begin at sample frame # [0 by default]\n");
	fprintf(stderr,
		"   -d #  duration is # sample frames [EOF by default]\n");
	fprintf(stderr,
		"   -e #  end at sample frame # [EOF by default]\n");
	fprintf(stderr,
		"   -c #  selects channel # [all channels by default]\n");
	fprintf(stderr,
		"            (channels are numbered from 0)\n");
	fprintf(stderr,
		"   -x    specifies byte-wise reversal [not reversed by default]\n");
	fprintf(stderr,
		"   -m #  multiply values by # [no scaling by default]\n");
	fprintf(stderr,
	    "   -f    specifies float output [default is 16-bit linear]\n");
	fprintf(stderr,
		"   -u    is to print this usage message\n");
	fprintf(stderr,
		"   file is name of input file [.snd extension advised].\n\n");
		exit(0);
}

