/*
 * ---------------------------------------------------------------------------
 * sfxserver/main.c
 *
 * Copyright by Terry Evans 1994
 * tevans@cs.utah.edu, tevans@slc.unisys.com
 * ---------------------------------------------------------------------------
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
 * ---------------------------------------------------------------------------
 */

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


#include "global.h"
#include "types.h"
#include "error.h"
#include "device.h"
#include "sample.h"
#include "channel.h"
#include "mix.h"
#include "io.h"
#include "main.h"


/* File descriptor for the sound device */
static int s_fd = -1;

/* Fragment size for the device (returned from ioctl call) */
static int frag_size = 0;

/* Fragment specification for sound device */
static int frag_spec = FRAG_SPEC;

/* Playback frequency rate */
static int frequency = SAMPLE_RATE;

/* Support stereo sound */
static int stereo = TRUE;

/* Input buffer */
char command;

/* Filename to load */
char filename[MAX_BUFFSIZE];

/* Temporary buffer */
char buffer[MAX_BUFFSIZE];

/* For now we have 8 channels (in global.h) */
static channel_t *channel[MAX_CHANNELS];
static sample_t *sample[MAX_SAMPLES];
static mix_t mix;


void main(int argc, char *argv[])
{
  fd_set fdvar;
  struct timeval t_val = { 0L, 1L};
  int sample_num;
  int channel_num;
  int volume_level;
  int left;
  int right;
  char side;
  unsigned int volume;

  /* Initialize the sound device */
  s_fd = D_Init("/dev/dsp", &frag_spec, &frequency, &stereo, &frag_size);

  S_Init(sample);
  C_Init(channel);
  M_Init(&mix, frag_size);

  /* Send out the ready message */
  IO_WriteStdout(READY);

  /* Clear out the file handles */
  FD_ZERO(&fdvar);

  /* Now, just go on forever */
  for(;;)
  {
    /* Set the stdio handle */
    FD_SET(0, &fdvar);

    /* Execute the select call to see if anything is ready to read in */
    if(select(1, &fdvar, NULL, NULL, &t_val) < 0)
     E_ErrnoNonFatalError("main", "select() call failed");

    if(FD_ISSET(0, &fdvar))
    {
      if(read(0, &command, 1) < 0)
      {
	E_ErrnoFatalError("main", "read failed on stdin");
	continue;
      }

      /* Flush all entries */
      if(command == 'c')
      {
	/* Read in the new line */
	read(0, &command, 1);

	C_DeInit(channel);
	S_DeInit(sample);
	continue;
      }

      /* Load in a new data file */
      if(command == 'l')
      {
	scanf("%s", filename);

	/* Replace the newline with a null */
	filename[strlen(filename)] = '\0';

	if((sample_num = S_LoadRawSample(filename, sample)) >= 0)
        {
	  sprintf(buffer, "s%2.2x\n", sample_num);
	  IO_WriteStdout(buffer);
	}

	continue;
      }

      if(command == 'p')
      {
	scanf("%2x%2x%2x", &sample_num, &left, &right);

	if(S_VerifySample(sample_num))
	  if((channel_num = C_AllocChannel(channel, sample[sample_num],
					   left, right)) >= 0)
          {
	    sprintf(buffer, "c%2.2x\n", channel_num);
	    IO_WriteStdout(buffer);
	  }
	else
	  E_NonFatalError("main", "sample %ul is not loaded", sample_num);

	continue;
      }

      if(command == 'v')
      {
	if(read(0, &side, 1) < 0)
        {
	  E_FatalError("main", "read() failed from stdin");
	  continue;
	}

	scanf("%2x%2x", &channel_num, &volume);

	sprintf(buffer, "side    = %c\n", side);
	IO_WriteStdout(buffer);

	sprintf(buffer, "channel = %d\n", channel_num);
	IO_WriteStdout(buffer);

	sprintf(buffer, "volume  = %d\n", volume);
	IO_WriteStdout(buffer);

	if((volume_level = C_ChangeVolume(channel, side, channel_num, volume)) >= 0)
        {
	  sprintf(buffer, "v%2.2x\n", volume_level);
	  IO_WriteStdout(buffer);
	}
	
	continue;
      }

      /* Quit the program */
      if(command == 'q')
      {
	/* Read in the new line */
	read(0, &command, 1);
	break;
      }
    }

    M_MixChannels(&mix, channel, frag_size, s_fd, stereo);
  }

  M_DeInit(&mix);
  C_DeInit(channel);
  S_DeInit(sample);
  D_DeInit(s_fd);

  /* Inform the server to exit */
  IO_WriteStdout("q");

  exit(0);
}
