/*------------ Telecommunications & Signal Processing Lab --------------
                         McGill University

Routine:
  AD.h

Description:
  Declarations for audio device routines

Author / revision:
  P. Kabal  Copyright (C) 1999
  $Revision: 1.18 $  $Date: 1999/06/14 16:10:34 $

----------------------------------------------------------------------*/

#ifndef AD_h_
#define AD_h_

#include <libtsp.h>		/* AFILE */
#include <libtsp/UTtypes.h>	/* uint1_t */
#include "AO.h"			/* AO_LIM_UNDEF */

/* Distinguish Solaris (SunOS 5.x) and SunOS 4.1 */
#ifdef __SVR4
#  define SOLARIS	1
#endif

/* ADopenPlay flags */
#define AD_WAIT_FLAG		1
#define AD_PRINT_FLAG		2

/* Output ports (speaker, headphone, line-out) */
#define NOPORT		3
#define PORT_DELETE	'-'
#define PORT_ADD	'+'

#ifndef	AD_t_
#  define	AD_t_
typedef struct AD_DevPar ADEV;	/* Audio device parameters */
#endif

/* Audio device option structure */
struct AD_DevOpt {
  float Sfreq;
  float Vol;
  float Balance;
  char Ports[NOPORT];
  int Mute;
};

/* Audio device parameter structure */
struct AD_DevPar {
  int fd;		/* Audio device file descriptor */
  struct {
    unsigned int gain;
    unsigned int port;
    unsigned char balance;
  } play;
  unsigned char output_muted;
};

#define DevOpt_INIT(p) { \
	int i__; \
	(p)->Sfreq = SFREQ_DEFAULT; \
	(p)->Vol = VOL_UNDEF; \
	(p)->Balance = BALANCE_UNDEF; \
	for (i__ = 0; i__ < NOPORT; ++i__) \
	  (p)->Ports[i__] = ' '; \
	(p)->Mute = MUTE_DEFAULT; }

#ifndef SOLARIS
static const char *AD_type[] = {
  "Not defined",
  "amd device (ELC)",
  "dbri device (speakerbox)",
  "dbri device",
  "Unknown device (code 4)",
  "multimedia audio card",
  "Unknown device"
};
#define NELEM(array)	((sizeof array) / (sizeof array[0]))
#define NAD_type	(NELEM (AD_type))
#endif

/*
  Choose the UNDEFINED value such that conversion between double & float
  leaves the value unchanged
*/
#define VOL_UNDEF	(-330)	/* Value not in [0,100] */
#define BALANCE_UNDEF	VOL_UNDEF
#define SFREQ_DEFAULT	VOL_UNDEF

#define AD_LIM_UNDEF	AO_LIM_UNDEF

#define MUTE_ON		1
#define MUTE_DEFAULT	0
#define MUTE_OFF	-1

#define AUDIO_DEV_DEFAULT	"/dev/audio"

#define SFREQ_TOL	0.05	/* Fractional deviation */

/*
  There are several versions of the audioio.h file.
  On SunOS 4.1, the file is <sun/audioio.h>
    Version 1.2 92/05/20 (file dated Sept. 3, 1992)
      - definitions for AUDIO_GETINFO etc. work for both  ANSI C and non-ANSI C
      - defines AUDIO_MAX_BALANCE
      - AUDIO_GETINFO returns an integer code
    Version 1.33 (file dated Oct. 14, 1994)
      - definitions for AUDIO_GETINFO etc. work for only for non-ANSI C
      - better comments
      - defines AUDIO_RIGHT_BALANCE
      - AUDIO_GETINFO returns an integer code
  On SunOS 5.5, the file is <sys/audioio.h>
    Version 1.21 94/01/21 (file dated Oct. 25, 1995)
    Version 1.23 95/08/15 (file dated May 2, 1996)
      - defines AUDIO_RIGHT_BALANCE
      - defines new encodings
      - defines new input port
      - AUDIO_GETINFO returns a structure with strings
*/

#ifdef SOLARIS
#  include <sys/audioio.h>

#else		/* SunOS 4.1.X */
#  include <sun/audioio.h>
#  ifndef AUDIO_RIGHT_BALANCE
#    define AUDIO_LEFT_BALANCE	AUDIO_MIN_BALANCE_
#    define AUDIO_RIGHT_BALANCE	AUDIO_MAX_BALANCE
#  endif
#  ifdef __STDC__
#    undef AUDIO_GETINFO
#    undef AUDIO_SETINFO
#    undef AUDIO_DRAIN
#    undef AUDIO_GETDEV
#    define AUDIO_GETINFO	_IOR('A', 1, audio_info_t)
#    define AUDIO_SETINFO	_IOWR('A', 2, audio_info_t)
#    define AUDIO_DRAIN		_IO('A', 3)
#    define AUDIO_GETDEV	_IOR('A', 4, int)
#  endif
#endif

/* Warning messages */
#define ADM_DevAtt	"Audio device attached"
#define ADM_Muted	"Audio output is muted"
#define ADM_WaitDev	"Waiting for audio device"

/* Error messages */
#define ADM_AccessErr	"Error accessing audio device"
#define ADM_BadBal	"Invalid stereo balance value"
#define ADM_BadOPort	"Invalid output port specification"
#define ADM_BadOption	"Option error, use -h for a list of options"
#define ADM_BadSFreq	"Invalid sampling frequency"
#define ADM_BadVol	"Invalid volume value"
#define ADM_DataNChan	"Unable to set data type/ no. channels"
#define ADM_DevBusy	"Audio device is busy"
#define ADM_DrainErr	"Drain failed on audio device"
#define ADM_FlushErr	"Error flushing audio device"
#define ADM_GetErr	"Error reading audio device parameters"
#define ADM_OpenErr	"Error opening audio device"
#define ADM_PortErr	"Selected output port not available"
#define ADM_SetErr	"Error setting audio device parameters"
#define ADM_SigHandler	"Cannot set up signal handler"
#define ADM_UnsAPrec	"Unsupported A-law precision"
#define ADM_UnsData	"Unsupported data encoding"
#define ADM_UnsIPrec	"Unsupported integer precision"
#define ADM_UnsMPrec	"Unsupported mu-law precision"
#define ADM_UnsSFreq	"Unsupported sampling rate"
#define ADM_WriteErr	"Error writing to audio device"
#define ADM_XNChan	"Too many input channels"

/* Printout formats */
#define ADMF_ADev	"Audio device: %s, %*s:\n"
#define ADMF_ADevS	"Audio device: %s, %s:\n"
#define ADMF_Frames	"  frames: %ld to %ld (total %ld, %.3f sec)\n"
#define ADMF_NOvld	"%s: %ld overloads detected"
#define ADMF_Samples	"  samples: %ld to %ld (total %ld, %.3f sec)\n"
#define ADMF_VolBal	"  volume: %.0f%%   balance: %.0f%%\n"
#define ADMF_OFormat	"  playback: %s (%d-bit) %d channel, %d Hz\n"

#define ADMF_SFreqChange "Sampling rate changed from %g to %g"

#ifdef __cplusplus
extern "C" {
#endif

/* Prototypes */
void
ADclosePlay (void);
int
ADdecDevOpt (struct AD_DevOpt *DevOpt);
void
ADdecOPort (const char String[], char Ports[NOPORT]);
void
ADdrain (int audio_fd);
int
ADfI2 (const float Fbuf[], int2_t Ibuf[], int Nval);
int
ADfMulaw (const float Fbuf[], uint1_t Cbuf[], int Nval);
void
ADgetOFormat (int audio_fd, float *Sfreq, int *Format, long int *Nchan);
int
ADopenControl (const char AudDev[], int Flags);
int
ADopenPlay (const char AudioDev[], int Flags);
void
ADplay (int audio_fd, AFILE *AFp, const long int Lim[2]);
void
ADprintOFormat (int audio_fd);
void
ADprintOPort (int audio_fd);
void
ADsetOFormat (int audio_fd, double Sfreq, int Nchan);
void
ADsetOPort (int fd, const char Ports[NOPORT], double Vol, double Balance,
	    int Mute);

#ifdef __cplusplus
}
#endif

#endif /* AD_h_ */
