/*
 * DATlib   Copyright (c) 1995-1996 Marcus Meissner &
 *          Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU), IMMD4
 *          All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by Marcus Meissner
 *    at the Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU), IMMD4
 *
 * 4. The name of the University or the author may not be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE AUTHOR ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR THE AUTHOR BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/* $Id: record.c,v 1.2 1997/06/03 18:40:56 msmeissn Exp $
 *
 * $Log: record.c,v $
 * Revision 1.2  1997/06/03 18:40:56  msmeissn
 * endian fixes...
 *
 * Revision 1.1  1997/03/16 20:27:25  msmeissn
 * Initial revision
 *
 *
 * record.c: Small program to copy audio-files from disk to audio-DAT
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/fcntl.h>

#include "dataudiolib.h"
#include "xaudio.h"
#include "audio_filehdr.h"

void
usage(char **argv) {
		fprintf(stderr,
"Usage: %s [options]\n"
"       [--stdin] [-] 	Use stdin as input (default: Audiodevice)\n"
"       [--samplerate <samplerate>] [-s <samplerate>]\n"
"                       Use samplerate\n"
"       [--pack] [-p]   Use 12bit linear encoding (32khz only)\n"
"       [--pnr <programnumber>] [-n <programmnr>]\n"
"                       Record with programnr\n"
"       [--raw] [-r]    Input are raw samples (default is Sun Audio)\n",
"       [--endian] [-e] ['big'|'little']\n"
"                       Input endianess (default is host endianess)\n",
		argv[0]);
}

/* Sparc -> Big Endian, Intel -> Little Endian */

#define ENDIAN_LITTLE	1
#define ENDIAN_BIG	2

int hostendian;

check_endianess() {
	long	a=0x12345678;
	u8	*b;

	b=(u8*)&a;
	if (b[0]==0x12)
		hostendian=ENDIAN_BIG;
	else
		hostendian=ENDIAN_LITTLE;
}

u16
u16_h2b(u16 x) {
	u16	y;
	u8	*a,*b;

	a=(u8*)&y;b=(u8*)&x;
	if (hostendian==ENDIAN_BIG)
		return x;
	a[0]=b[1];
	a[1]=b[0];
	return y;
	
}

#define u16_b2h(x) u16_h2b(x)

u32
u32_h2b(u32 x) {
	u32	y;
	u8	*a,*b;

	a=(u8*)&y;b=(u8*)&x;
	if (hostendian==ENDIAN_BIG)
		return x;
	a[0]=b[3];
	a[3]=b[0];
	a[2]=b[1];
	a[1]=b[2];
	return y;
}

#define u32_b2h(x) u32_h2b(x)

int
main(int argc,char **argv) {
	int	fd,aud;
	char	*tape;
	u8	buf[2000];
	int	pnr,curleft,res;
	struct	da_time		datime;
	int	eflag,sourcendian,i,channels,raw,xsamplerate,packit,readfromstdin;

	check_endianess();
	xsamplerate=0;packit=0;readfromstdin=0;pnr=0;raw=0;
	sourcendian = hostendian;eflag = 0;
	for (i=1;argv[i];i++) {
		if (!strcmp(argv[i],"--samplerate") || !strcmp(argv[i],"-s")) {
			i++;
			if (sscanf(argv[i],"%d",&xsamplerate))
				continue;
			else
				fprintf(stderr,"Couldn't parse '%s', skipping.\n",argv[i]);
		}
		if (!strcmp(argv[i],"--help") || !strcmp(argv[i],"-h")) {
			usage(argv);
			exit(1);
		}
		if (!strcmp(argv[i],"--pack") || !strcmp(argv[i],"-p")) {
			packit=1;
			continue;
		}
		if (!strcmp(argv[i],"--raw") || !strcmp(argv[i],"-r")) {
			raw=1;
			continue;
		}
		if (!strcmp(argv[i],"--stdin") || !strcmp(argv[i],"-")) {
			readfromstdin=1;
			continue;
		}
		if (	(i+1<argc) &&
			(!strcmp(argv[i],"--endian") || !strcmp(argv[i],"-e"))
		) {
			i++;
			eflag=1;
			if (!strcmp(argv[i],"big")) {
				sourcendian=ENDIAN_BIG;
				continue;
			}
			if (!strcmp(argv[i],"little")) {
				sourcendian=ENDIAN_LITTLE;
				continue;
			}
			usage(argv);
			exit(1);
		}
		if (!strcmp(argv[i],"--pnr") || !strcmp(argv[i],"-n")) {
			i++;
			if (sscanf(argv[i],"%d",&pnr)) {
				if (pnr<1 || pnr >799) {
					fprintf(stderr,"Bad startnumber:%d,setting to 1.\n",pnr);
					pnr=1;
				}
				continue; 
			} else
				fprintf(stderr,"Couldn't parse '%s', skipping.\n",argv[i]);

		}
		usage(argv);
		exit(1);
	}
	if (raw && !eflag)
		fprintf(stderr,"Using raw mode with host endianess. Hope this is correct.\n");
	tape=getenv("TAPE");
	if (!tape) tape=DEFAULTAUDIOTAPE;
	fd=da_open(tape,O_WRONLY);
	if (fd==-1) {
		fprintf(stderr,"%s:da_open:could not open ");
		perror(tape);
		exit(1);
	}
	if (readfromstdin) {
		aud=fileno(stdin);
	} else {
		if (-1==(aud=audio_open(O_RDWR))) {
			perror("open /dev/audio");
			exit(1);
		}
	}
	curleft=0;
	if (!raw) {
		Audio_filehdr *fhdr;

		/* try reading a .au header */
		curleft=0;
		while (curleft<sizeof(*fhdr)) {
			res=read(aud,buf+curleft,sizeof(*fhdr)-curleft);
			if (res==-1) {
				perror("read");
				return 1;
			}
			if (!res)
				return 1;
			curleft+=res;
		}
		fhdr=(Audio_filehdr*)buf;
		if (fhdr->magic==AUDIO_FILE_MAGIC) {
			xsamplerate = u32_b2h(fhdr->sample_rate);
			if (	(xsamplerate != 44100) &&
				(xsamplerate != 48000) &&
				(xsamplerate != 32000) 
			) {
				fprintf(stderr,"The specified .AU file got a invalid sampling rate(%d). Only 44100,48000 and 32000 are allowed.\n",xsamplerate);
				return 1;
			}
			channels = u32_b2h(fhdr->channels);
			if (channels!=2) {
				fprintf(stderr,"The specified .AU file has a wrong number of channels (%d), only 2 are supported for now.\n",channels);
				return 1;
			}
			curleft = u32_b2h(fhdr->hdr_size)-sizeof(*fhdr);
			while (curleft) {
				if (curleft>sizeof(buf))
					res=sizeof(buf);
				else
					res=curleft;
				res=read(aud,buf,res);
				if (res==-1) {
					perror("read");
					return 1;
				}
				if (!res)
					return 1;
				curleft-=res;
			}
		}
	}
	if (!xsamplerate) 
		xsamplerate=44100;
	if (packit && (xsamplerate!=32000)) {
		fprintf(stderr,"Can use compression only in 32Khz mode.\n");
		exit(1);
	}

	switch (xsamplerate) {
	case 48000:
		if (!readfromstdin) audio_change_attribs(aud,48000,16,1);
		break;
	case 44100:
		if (!readfromstdin) audio_change_attribs(aud,44100,16,1);
		break;
	case 32000:
		if (!readfromstdin) audio_change_attribs(aud,32000,16,1);
		break;
	default:
		fprintf(stderr,"Speed '%d' not supported.\n",xsamplerate);
		exit(1);
	}
	res=0;
	if (pnr)
		da_control(fd,DA_SET_PROGNR,(long)&pnr);
	da_control(fd,DA_GET_PROGTIME,(long)&datime);
	datime.indexnr	=
	datime.hour	=
	datime.minute	=
	datime.second	=
	datime.frame	= 0;
	da_control(fd,DA_SET_PROGTIME,(long)&datime);
	if (-1==da_control(fd,DA_SET_SAMPLERATE,(long)&xsamplerate))
		perror("da_control DA_SET_SAMPLERATE");
	if (-1==da_control(fd,DA_SET_PACKED,(long)&packit))
		perror("da_control DA_SET_PACKED");
	/* write mistakingly read audioheader as samples */
	if (curleft && 0) {
		fprintf(stderr,"discarding junk\n");
		curleft=0;
		while (curleft<sizeof(Audio_filehdr)) {
			res=da_write(fd,buf+curleft,sizeof(Audio_filehdr)-curleft);
			if (res==-1) {
				perror("da_write");
				break;
			}
			curleft+=res;
		}
		if (res==-1)
			return 1;
	}
	while (1) {
		curleft=0;
		while (curleft<2000) {
			res=audio_read(aud,buf+curleft,2000-curleft);
			if (res==-1) {
				perror("read");
				break;
			}
			if (!res) break;
			curleft+=res;
		}
		if (res<=0) break;
		if (sourcendian!=ENDIAN_BIG) {
			u16 *buf16 = (u16*)buf;

			for (i=0;i<curleft/2;i++)
				buf16[i] = u16_h2b(buf16[i]);
		}
		if (-1==da_write(fd,buf,2000)) {
			perror("da_write");
			break;
		}
	}
	/* advance one song */
	da_control(fd,DA_GET_PROGNR,(long)&pnr);
	pnr++;
	da_control(fd,DA_SET_PROGNR,(long)&pnr);
	da_control(fd,DA_GET_PROGTIME,(long)&datime);
	datime.indexnr	=
	datime.hour	=
	datime.minute	=
	datime.second	=
	datime.frame	= 0;
	da_control(fd,DA_SET_PROGTIME,(long)&datime);
	da_close(fd);
	return 0;
}
