/*
#    Sfront, a SAOL to C translator
#    This file: IRIX audio driver for sfront
#    Copyright (C) 1999  Regents of the University of California
#    Copyright (C) 2001  Michael Pruett
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License (Version 2) as
#    published by the Free Software Foundation.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#    Maintainer: John Lazzaro, lazzaro@cs.berkeley.edu
*/

#include <dmedia/audio.h>
#include <unistd.h>

#if defined(ASYS_HASOUTPUT)

/* global variables, must start with asys_ */

ALport asyso_port;	/* audio port */
long asyso_size;	/* number of samples in a buffer */
short *asyso_buf;	/* output buffer */
int asyso_channels;	/* number of channels */

#endif

#if defined(ASYS_HASINPUT)

/* global variables, must start with asys_ */

ALport asysi_port;	/* audio port */
long asysi_size;	/* number of samples in a buffer */
short *asysi_buf;	/* input buffer */
int asysi_channels;	/* number of channels */

#endif

static int setrate (ALport port, double rate)
{
	int	res;
	ALpv	params;

	res = alGetResource(port);

	params.param = AL_RATE;
	params.value.ll = alDoubleToFixed(rate);

	if (alSetParams(res, &params, 1) < 0)
	{
		return ASYS_ERROR;
	}

	return ASYS_DONE;
}

#if defined(ASYS_HASOUTPUT)

/****************************************************************/
/*        core routine for audio output setup                   */
/****************************************************************/

int asyso_setup (long srate, long ochannels, long osize, char *oname)
{
	ALconfig	config;

	config = alNewConfig();

	alSetChannels(config, ochannels);
	alSetWidth(config, AL_SAMPLE_16);

	asyso_port = alOpenPort("sfront", "w", config);

	alFreeConfig(config);

	if (asyso_port == NULL)
		return ASYS_ERROR;

	if (setrate(asyso_port, srate) != ASYS_DONE)
		return ASYS_ERROR;

	asyso_channels = ochannels;
	asyso_size = osize;
	asyso_buf = (short *) calloc(osize, sizeof (short));
	return ASYS_DONE;
}

#endif

#if defined(ASYS_HASINPUT)

/****************************************************************/
/*        core routine for audio input setup                   */
/****************************************************************/

int asysi_setup(long srate, long ichannels, long isize, char *iname)
{
	ALconfig	config;

	config = alNewConfig();

	alSetChannels(config, ichannels);
	alSetWidth(config, AL_SAMPLE_16);

	asysi_port = alOpenPort("sfront", "r", config);

	alFreeConfig(config);

	if (asysi_port == NULL)
		return ASYS_ERROR;

	if (setrate(asysi_port, srate) != ASYS_DONE)
		return ASYS_ERROR;

	asysi_channels = ichannels;
	asysi_size = isize;
	asysi_buf = (short *) calloc(isize, sizeof (short));
	return ASYS_DONE;
}

#endif

#if (defined(ASYS_HASOUTPUT) && !defined(ASYS_HASINPUT))

/****************************************************************/
/*        sets up audio output for a given srate/channels       */
/****************************************************************/

int asys_osetup (long srate, long ochannels, long osample,
	char *oname, long toption)
{
	return asyso_setup(srate, ochannels, ASYS_OCHAN*ACYCLE, oname);
}

#endif


#if (!defined(ASYS_HASOUTPUT) && defined(ASYS_HASINPUT))

/****************************************************************/
/*        sets up audio input for a given srate/channels       */
/****************************************************************/

int asys_isetup(long srate, long ichannels, long isample,
	char *iname, long toption)
{
	return asysi_setup(srate, ichannels, ASYS_ICHAN*ACYCLE, iname);
}

#endif


#if (defined(ASYS_HASOUTPUT) && defined(ASYS_HASINPUT))

/****************************************************************/
/*   sets up audio input and output for a given srate/channels  */
/****************************************************************/

int asys_iosetup (long srate, long ichannels, long ochannels,
	long isample, long osample,
	char *iname, char *oname, long toption)
{
	int	result;

	result = asysi_setup(srate, ichannels, ASYS_ICHAN*ACYCLE, iname);

	if (result != ASYS_DONE)
		return ASYS_ERROR;

	return asyso_setup(srate, ochannels, ASYS_OCHAN*ACYCLE, oname);
}

#endif

#if (defined(ASYS_HASOUTPUT)&&(!defined(ASYS_HASINPUT)))

/****************************************************************/
/*                    shuts down audio output                   */
/****************************************************************/

void asys_oshutdown(void)
{
	while (alGetFilled(asyso_port) > 0)
		sginap(1);

	alClosePort(asyso_port);
}

#endif

#if (!defined(ASYS_HASOUTPUT)&&(defined(ASYS_HASINPUT)))

/****************************************************************/
/*              shuts down audio input device                   */
/****************************************************************/

void asys_ishutdown(void)
{
	alClosePort(asysi_port);
}

#endif

#if (defined(ASYS_HASOUTPUT)&&(defined(ASYS_HASINPUT)))

/****************************************************************/
/*              shuts down audio input and output device        */
/****************************************************************/

void asys_ioshutdown(void)
{
	alClosePort(asysi_port);

	while (alGetFilled(asyso_port) > 0)
		sginap(1);

	alClosePort(asyso_port);
}

#endif

#if defined(ASYS_HASOUTPUT)

/****************************************************************/
/*        creates buffer, and generates starting silence        */
/****************************************************************/

int asys_preamble (ASYS_OTYPE *asys_obuf[], long *osize)

{
	*asys_obuf = asyso_buf;
	*osize = asyso_size;

	alZeroFrames(asyso_port, *osize);

	return ASYS_DONE;
}

/****************************************************************/
/*               sends one frame of audio to output             */
/****************************************************************/

int asys_putbuf (ASYS_OTYPE *asys_obuf[], long *osize)
{
	*osize = asyso_size;

	alWriteFrames(asyso_port, *asys_obuf, *osize / asyso_channels);

	return ASYS_DONE;
}

#endif

#if defined(ASYS_HASINPUT)

/****************************************************************/
/*               gets one frame of audio from input             */
/****************************************************************/

int asys_getbuf (ASYS_ITYPE *asys_ibuf[], long *isize)
{
	if (*asys_ibuf == NULL)
		*asys_ibuf = asysi_buf;
	*isize = asysi_size;

	alReadFrames(asysi_port, *asys_ibuf, *isize / asysi_channels);

	return ASYS_DONE;
}

#endif
