/* NeXT/audio.c 
	vi:ts=3 sw=3:
 */

/* $Id: audio.c,v 1.2 1995/02/08 13:16:22 espie Exp espie $
 * $Log: audio.c,v $
 * Revision 1.2  1995/02/08  13:16:22  espie
 * *** empty log message ***
 *
 * Revision 1.1  1995/02/01  16:43:47  espie
 * Initial revision
 *
 */

#include "defs.h"
#include <sound/sound.h>
#include "extern.h"
/*
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stropts.h>
*/

ID("$Id: audio.c,v 1.2 1995/02/08 13:16:22 espie Exp espie $")

#define SND_PLAY_PRIO   5

LOCAL SNDSoundStruct ainfo;
LOCAL struct {
    SNDSoundStruct snd;
    char data;
} *snd;
LOCAL int tag;
unsigned int play_ahead;
LOCAL char *buffer;
LOCAL short *sbuffer;
LOCAL int idx;

/* ###
LOCAL int dsize;
*/
#define DATASIZE 40960 /* 176400 */
LOCAL int stereo;
LOCAL int primary, secondary;	/* mix factor */

void
set_mix(int percent)
{
    percent *= 256;
    percent /= 100;
    primary = percent;
    secondary = 512 - percent;
}

#define abs(x) ((x) < 0 ? -(x) : (x))

LOCAL int
available(int f)
{
    static int possible[] = { 8012, 22050, 44100, 0};
    int best = 0;
    int i;

    for (i = 0; possible[i]; i++)
	if (abs(possible[i] - f) < abs(best - f))
	    best = possible[i];
    return best;
}

int
open_audio(int f, int s)
{
    if (f == 0)
	f = 22050;
    /* round frequency to acceptable value */
    f = available(f);

    stereo = s;
    ainfo.samplingRate = f;
/*    dsize = 2; ###*/
    if (stereo)
	ainfo.channelCount = 2;
    else
	ainfo.channelCount = 1;
    if(f!=8012)
	ainfo.dataFormat = SND_FORMAT_LINEAR_16;
    else
    {
	ainfo.dataFormat = SND_FORMAT_MULAW_8;
	if (stereo)
	    notice("Warning: Your hardware may not be fast enough for mulaw-stereo.");
    }
    
    idx = 0;
    if (SNDAlloc((SNDSoundStruct **)&snd, DATASIZE, ainfo.dataFormat,
		 ainfo.samplingRate, ainfo.channelCount, 4))
	end_all("Sound allocation error.");
    
    buffer = &snd->data;
    sbuffer = (short *)&snd->data;
    tag = 1;
    play_ahead = 5;
    return f;
}

void
set_synchro(int s)
{
    /* not implemented */
}

int
update_frequency()
{
    /* frequency can't change */
    return 0;
}

void
output_samples(int left, int right)
{
    if (ainfo.dataFormat == SND_FORMAT_LINEAR_16)
    {
	if (stereo)
	{
	    sbuffer[idx++] = (left * primary + right * secondary)/65536;
	    sbuffer[idx++] = (right * primary + left * secondary)/65536;
	}
	else
	    sbuffer[idx++] = left + right;
	
	if (idx >= DATASIZE/2)
	    flush_buffer();
    }
    else
    {
	if (stereo)
	{
	    buffer[idx++] = SNDMulaw((left*primary + right*secondary)/65536);
	    buffer[idx++] = SNDMulaw((right*primary + left*secondary)/65536);
	}
	else
	    buffer[idx++] = SNDMulaw((left + right)/256);

	if (idx >= DATASIZE)
	    flush_buffer();
    }
}

void
flush_buffer(void)
{
/*    snd->snd.dataSize = (idx * ainfo.channelCount *
			 ((ainfo.dataFormat == SND_FORMAT_LINEAR_16)?2:1)); */
    if(tag>play_ahead)
	SNDWait(tag-play_ahead);
    if(SNDStartPlaying(&snd->snd, tag++, SND_PLAY_PRIO, 0,
		       NULL, (SNDNotificationFun)SNDFree))
	notice("Sound playing error.");	/* ### end_all? */

    idx = 0;
    if (SNDAlloc((SNDSoundStruct **)&snd, DATASIZE, ainfo.dataFormat,
		 ainfo.samplingRate, ainfo.channelCount, 4))
	end_all("Sound allocation error.");
    buffer = &snd->data;
    sbuffer = (short *)&snd->data;
}

void
discard_buffer(void)
{
    int i;
    
    for(i=1; i<=play_ahead; i++)
	SNDStop(tag-i);
}

void
close_audio(void)
{
    SNDFree(&snd->snd);
    SNDWait(0);
}
