/***************************************************************************
*	NAME:  MIXCTL.C $Revision: 1.11 $
**	COPYRIGHT:
**	"Copyright (c) 1994,1995 by e-Tek Labs"
**
**       "This software is furnished under a license and may be used,
**       copied, or disclosed only in accordance with the terms of such
**       license and with the inclusion of the above copyright notice.
**       This software or any other copies thereof may not be provided or
**       otherwise made available to any other person. No title to and
**       ownership of the software is hereby transfered."
****************************************************************************
* $Log: mixctl.c $
* Revision 1.11  1995/10/13 17:21:01  mleibow
* Added effects mixer slider.
* Added code to make it easier to change mixer node map in future.
* Added code to make master volumes change at 10dB drop offs instead of 6dB.
* Revision 1.10  1995/07/10 17:20:18  sdsmith
* Removed errors for init string errors
* Revision 1.9  1995/07/10 11:02:57  sdsmith
* Fixed init string process bug
* Revision 1.8  1995/07/07 16:01:14  sdsmith
* Added mixer version and checksum to mixer string
* Revision 1.7  1995/05/29 17:34:13  sdsmith
* Various bug fixes
* Revision 1.6  1995/04/26 16:22:32  sdsmith
* Fixed the public function commentary
* Revision 1.5  1995/04/19 17:40:16  sdsmith
* Added default init string support
* Revision 1.4  1995/04/14 09:19:51  sdsmith
* Added support for B0 silicon
* Revision 1.3  1995/03/30 09:47:49  sdsmith
* New mixer fixes
* Revision 1.2  1995/03/27 07:59:09  sdsmith
* New mixer node stuff
* Revision 1.1  1995/02/23 11:07:48  unknown
* Initial revision
***************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dos.h>
#include "iw.h"
#include "iwl.h"
#include "globals.h"
#include "digital.h"
#include "codec.h"
#include "iwllist.h"
#include "iwnote.h"

static char tmp[8];
extern int MAX_CODEC_NODES;

/***************************************************************************

FUNCTION DEFINITION:
iw_mix_strlen - returns number of bytes necessary to store mixer settings

DESCRIPTION:
iw_mix_strlen returns the number of bytes necessary to store a text
representation of the current settings of the mixer mute, multiplexer, and
gain nodes.

RETURNS: number of bytes necessary to store the settings string
*/
int iw_mix_strlen()
{
	int i, count;

	count = 8;
	for (i=0; i<MAX_CODEC_NODES; i++) {
		if (iw_mixer_nodes[i].type == CONTROL ||
				(iw_mixer_nodes[i].type == JUNCTION &&
				 iw_mixer_nodes[i].subtype == MUX)) {
			switch (iw_mixer_nodes[i].subtype) {
				case MUX:
				case SWITCH:
					if (iw_mixer_nodes[i].attributes & IW_MIX_ATTR_STEREO)
						count += 7;
					else
						count += 5;
					break;
				case LEVEL:
					if (iw_mixer_nodes[i].attributes & IW_MIX_ATTR_STEREO)
						count += 11; /* 2 for id 3 for left and right each */
					else
						count += 7; /* 2 for id 3 for left and right each */
					break;
				default:
					break;
			}
		}
	}
	return(count);
}

/***************************************************************************

FUNCTION DEFINITION:
iw_mix_get_control - get current setting for a control

DESCRIPTION:
iw_mix_get_control retrieves the current settings for the mixer node 
specified by the caller.  The left and right settings for the control
are returned in the corresponding parameters.  The values will be
in the range indicated by the nodes range and attribute fields.

For a mono control, only the left value is used.  The right value
will be undefined.

PARAMETERS:
	id    - id of mixer node to get the current settings for
	left  - current left setting
	right - current right setting

RETURNS: void
*/
void iw_mix_get_control(int id, int RFAR *left, int RFAR *right)
{
	int node_index;

      /* Find the node index */
	node_index = iwl_get_node_index(id);
	if (node_index >= 0) {
		if (iw_mixer_nodes[node_index].type == CONTROL ||
				(iw_mixer_nodes[node_index].type == JUNCTION &&
				 iw_mixer_nodes[node_index].subtype != TEE)) {
			if (left) {
				*left = iw_mixer_nodes[node_index].current.stereo.left;
			}
			if (right) {
				*right = iw_mixer_nodes[node_index].current.stereo.right;
			}
		}
	}
}

/***************************************************************************

FUNCTION DEFINITION:
iw_mix_set_control - set values for a control

DESCRIPTION:
iw_mix_set_control retrieves the current settings for the mixer node 
specified by the caller.  The left and right settings for the control
are indicated by the corresponding parameters.  The values will be
in the range indicated by the nodes range and attribute fields.

For a mono control, only the left value is used.  The right value
will be undefined.

PARAMETERS:
	id    - id of mixer node to get the current settings for
	left_value  - current left setting
	right_value - current right setting

RETURNS: void
*/
void iw_mix_set_control(int id, int left_value, int right_value)
{
	int i;

	i = iwl_get_node_index(id);
	if (i >= 0) {
		if (iw_mixer_nodes[i].attributes & IW_MIX_ATTR_LOCKLR)
			right_value = left_value;

		if (iw_mixer_nodes[i].type == CONTROL ||
			(iw_mixer_nodes[i].type == JUNCTION &&
			 iw_mixer_nodes[i].subtype != TEE)) {
			switch (iw_mixer_nodes[i].subtype) {
				case MIXER:
				case MUX:
					iwl_mixer_set_mux(i, left_value, right_value);
					break;
				case SWITCH:
					iwl_mixer_set_mute(i, left_value, right_value);
					break;
				case LEVEL:
					iwl_mixer_set_level(i, left_value, right_value);
					break;
			}
		}
	}
}

/***************************************************************************

FUNCTION DEFINITION:
iw_get_mixer_settings - get a text description of current mixer settings

DESCRIPTION:
This routine fills the character array specified by the caller with a 
textual representation of the current setting of the mixer's mute,
multiplexer, and gain nodes.

The first item in the string will be the CODEC version number.

The settings of the nodes are described as follows:

For gain nodes the settings take the form:
node_id, current_left, current_right,

For multiplexer nodes the settings take the form:
node_id, mux_setting,

where node_is is the mute node id; and mux_setting is the current multiplexer
control setting.

For mute nodes the settings take the form:
node_id, mute,

where node_is is the mute node id; and mute is 1 for muted and 0 for unmuted

The setting strings are concatenated together for form one string which
completely describes the mixer settings.

PARAMETERS:
	str - pointer to an array of characters to hold the ASCII
		  representation of the mixer settings

RETURNS: void
*/
void iw_get_mixer_settings(char RFAR *str)
{
	int i;
	unsigned char version, sum, RFAR *cp;

	iwu_strcpy(str,(char RFAR *)"iw");
	IWL_CODEC_IN(MODE_SELECT_ID, version);
	version &= ~0x70;
	iwu_itoa(version, (char RFAR *)tmp, 16);
	iwu_strcat(str,(char RFAR *)tmp);
	iwu_itoa(MIXER_VERSION, (char RFAR *)tmp, 16);
	iwu_strcat(str,(char RFAR *)tmp);
	iwu_strcat(str,(char RFAR *)",");
	for (i=0; i<MAX_CODEC_NODES; i++) {
		if (iw_mixer_nodes[i].type == CONTROL ||
				(iw_mixer_nodes[i].type == JUNCTION &&
				 iw_mixer_nodes[i].subtype == MUX)) {
			iwu_itoa(iw_mixer_nodes[i].id, (char RFAR *)tmp, 10);
			iwu_strcat(str,(char RFAR *)tmp);
			iwu_strcat(str,(char RFAR *)",");
			if ((iw_mixer_nodes[i].attributes & IW_MIX_ATTR_STEREO) &&
			    !(iw_mixer_nodes[i].attributes & IW_MIX_ATTR_LOCKLR)) {
				iwu_itoa(iw_mixer_nodes[i].current.stereo.left, (char RFAR *)tmp, 10);
				iwu_strcat(str,(char RFAR *)tmp);
				iwu_strcat(str,(char RFAR *)",");
				iwu_itoa(iw_mixer_nodes[i].current.stereo.right, (char RFAR *)tmp, 10);
				iwu_strcat(str,(char RFAR *)tmp);
				iwu_strcat(str,(char RFAR *)",");
			}
			else {
				iwu_itoa(iw_mixer_nodes[i].current.value, (char RFAR *)tmp, 10);
				iwu_strcat(str,(char RFAR *)tmp);
				iwu_strcat(str,(char RFAR *)",");
			}
		}
	}
	sum = 0;
	for (cp = str; *cp; cp++) {
	    sum += *cp;
	}
	sum = 0 - sum;
	iwu_itoa(sum, (char RFAR *)tmp, 16);
	iwu_strcat(str,"!,");
	iwu_strcat(str,(char RFAR *)tmp);
}

/***************************************************************************

FUNCTION DEFINITION:
iw_restore_mixer_settings - restore mixer settings to match text string

DESCRIPTION:
iw_restore_mixer_settings uses the textual string passed in from the caller
to changes the settings of the mixer nodes to match those specified in
the string.

The first item in the mixer settings string is interpreted as the CODEC
version.  If the version does not match, that read from the codec, this
routine will fail and will return IW_CODEC_VERSION_MISMATCH.

If the a node specified in the string does not match one of the types for
which settings are saved, then the operation will fail.

PARAMETERS:
	str - pointer to an array of characters to hold the ASCII
		  representation of the mixer settings

RETURNS: int - IW_OK
			   IW_CODEC_VERSION_MISMATCH
               IW_ILLEGAL - badly formatted settings string 
			  - invalid node to receive settings

SEE ALSO:
iw_get_mixer_settings
*/
int iw_restore_mixer_settings(char RFAR *str)
{
	int node_id, i, rc = IW_OK;
	int last_char;
	int value, left, right;
	char RFAR *tmp;
	unsigned char hold, version, codec_version, sum, chksum;

	last_char = (int)iwu_strlen(str);

        sum = 0;
	for (tmp = str; (*tmp); tmp++) {
	    if (*tmp != '!')
		sum += *tmp;
	    else
	        break;
	}
	sum = 0 - sum;

	/* Skip past the CODEC version id */
	tmp = iwu_strtok(str, (char RFAR *)",");
	/* there should be an iw as the first two characters of the id */
	if (iwu_strncmp(tmp, "iw", 2) == 0) {
		tmp += 2;
		hold = *(tmp + 2);
		*(tmp + 2) = 0;
		version = (unsigned char)iwu_strtol(tmp, NULL, 16);
		IWL_CODEC_IN(MODE_SELECT_ID, codec_version);
		codec_version &= ~0x70;
		if (codec_version == version) {
		        *(tmp + 2) = hold;
			tmp += 2;
			version = (unsigned char)iwu_strtol(tmp, NULL, 16);
			if (MIXER_VERSION == version) {
			tmp = iwu_strtok(NULL, (char RFAR *)",");
			while (tmp && rc == IW_OK && iwu_strcmp(tmp,"!")) {
				node_id = (int)iwu_strtol(tmp, NULL, 10);
				i = iwl_get_node_index(node_id);
				if (i != -1) {
					if (iw_mixer_nodes[i].type == CONTROL ||
						(iw_mixer_nodes[i].type == JUNCTION &&
						 iw_mixer_nodes[i].subtype == MUX)
					) {
					    if ((iw_mixer_nodes[i].attributes & IW_MIX_ATTR_STEREO) &&
						!(iw_mixer_nodes[i].attributes & IW_MIX_ATTR_LOCKLR)) {
							tmp = iwu_strtok(NULL, (char RFAR *)",");
							if (tmp) {
								left = (int)iwu_strtol(tmp, NULL, 10);
								tmp = (char RFAR *)iwu_strtok(NULL, (char RFAR *)",");
								if (tmp) {
									right = (int)iwu_strtol(tmp, NULL, 10);
									iw_mix_set_control(node_id, left, right);
								}
								else
									rc = IW_ILLEGAL;
							}
							else
								rc = IW_ILLEGAL;
						}
						else {
							tmp = iwu_strtok(NULL, (char RFAR *)",");
							if (tmp) {
								value = (int)iwu_strtol(tmp, NULL, 10);
								iw_mix_set_control(node_id, value, value);
							}
							else
								rc = IW_ILLEGAL;
						}
					}
					else
						rc = IW_ILLEGAL;
				}
				else
					rc = IW_ILLEGAL;
				tmp = (char RFAR *)iwu_strtok(NULL, (char RFAR *)",");
			}
			if (tmp && iwu_strcmp(tmp, "!") == 0) {
			    tmp = (char RFAR *)iwu_strtok(NULL, (char RFAR *)",");
			    chksum = (unsigned char)iwu_strtol(tmp, NULL, 16);
			    if (chksum != sum) rc = IW_ILLEGAL;
			}
			}
		}
		for (i=0; i<last_char; i++) {
			if (str[i] == 0)
				str[i] = ',';
		}
	}
	return(rc);
}
