/*
 * ---------------------------------------------------------------------------
 * sfxserver/channel.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 <stdio.h>
#include <stdlib.h>


#include "global.h"
#include "types.h"
#include "error.h"
#include "io.h"
#include "sample.h"


/* Current channel number */
int channel_number;


void C_Init(channel_t **channel)
{
  int loop;

  IO_WriteStdout("        Setting up channel data structures\n");

  for(loop = 0; loop < MAX_CHANNELS; loop++)
    channel[loop] = NULL;

  channel_number = 0;
}


void C_DeInit(channel_t **channel)
{
  int loop;

  for(loop = 0; loop < channel_number; loop++)
  {
    free(channel[loop]);
    channel[loop] = NULL;
  }

  /* Reset the channel number */
  channel_number = 0;
}


int C_AllocChannel(channel_t **channel, sample_t *sample, int left, int right)
{
  int loop;

  for(loop = 0; loop < MAX_CHANNELS; loop++)
  {
    /* See if it is a free channel */
    if(channel[loop] != NULL)
    {
      /* See if the channel is in use */
      if(channel[loop]->in_use)
	continue;

      else
      {
	/* The struct has already been allocated, so assign pointers */
	channel[loop]->position = 0;
	channel[loop]->vol_left = (float)left / 255.0;
	channel[loop]->vol_right = (float)right / 255.0;
	channel[loop]->in_use = TRUE;
	channel[loop]->sample = sample;

	return(loop);
      }
    }

    /* We need to malloc the area and initialize */
    else
    {
      if((channel[loop] = (channel_t *)malloc(sizeof(channel_t))) == NULL)
	E_FatalError("C_AllocChannel", "could not malloc %ul bytes", sizeof(channel_t));

      channel[loop]->position = 0;
      channel[loop]->vol_left = (float)left / 255.0;
      channel[loop]->vol_right = (float)right / 255.0;
      channel[loop]->in_use = TRUE;
      channel[loop]->sample = sample;

      channel_number++;

      return(loop);
    }
  }

  /* There are no free channels */
  return(-1);
}


int C_VerifyChannel(int number)
{
  if(number < channel_number)
    return(TRUE);
  else
    return(FALSE);
}


int C_ChangeVolume(channel_t **channel, char side, int number, int volume)
{
  /* See if that channel is allocated */
  if(!C_VerifyChannel(number))
  {
    E_NonFatalError("C_ChangeVolume", "channel %ul is not allocated", number);
    return(-1);
  }

  /* Make sure the space is allocated */
  /* This error should NEVER occur */
  if(channel[number] == NULL)
  {
    E_NonFatalError("C_ChangeVolume", "channel %ul is not allocated", number);
    return(-1);
  }

  /* See if that channel is in use */
  if(channel[number]->in_use != TRUE)
  {
    E_NonFatalError("C_ChangeVolume", "channel %ul is not in use", number);
    return(-1);
  }

  if(side == 'l')
    channel[number]->vol_left = (float)volume / 255.0;
  else if(side == 'r')
      channel[number]->vol_right = (float)volume / 255.0;
  else
  {
    E_NonFatalError("C_ChangeVolume", "illegal side value '%c' for volume", side);
    return(-1);
  }

  return(volume);
}


int C_ChannelsInUse(channel_t **channel)
{
  int loop;
  int num_channels = 0;

  for(loop = 0; loop < channel_number; loop++)
  {
    /* See if it is a free channel */
    if(channel[loop] != NULL)
    {
      /* See if the channel is in use */
      if(channel[loop]->in_use)
	num_channels++;
    }
  }

  return(num_channels);
}
