/*
 * Purpose: Definitions for the vmix driver
 */
/*
 * This file is part of Open Sound System
 *
 * Copyright (C) 4Front Technologies 1996-2008.
 *
 * This software is released under the BSD license.
 * See the COPYING file included in the main directory of this source
 * distribution for the license terms and conditions
 */


#define SUPPORTED_FORMATS (AFMT_S16_NE | AFMT_S16_OE | AFMT_S32_NE | AFMT_S32_OE)

/*
 * Maximum number of clients per "real" device is defined by MAX_CLIENTS. Limit of 4 would be good for 95% of systems.
 * For each client there will be a mixer volume control and peak meter in the mixer interface. Raising the
 * client limit will make the mixer interface larger and larger. Something like 8 is probably the practical limit
 * for number of clients.
 *
 * Mixing more than 16 streams together doesn't make much sense since the result is likely to be
 * just noise. Mixing a stream will cause some overhead so it's not a good idea to let large number of iddle
 * applications running muted or playing silence.
 */

#define MAX_CLIENTS		9	

#define MAX_LOOPDEVS		2	/* Maximum number of vmix loopback devices */

/*
 * 8 play channels and 2 rec channels might be OK for most devices. However envy24 requires 10 play and 12 rec 
 * channels for the "raw devices". Some professional (ADAT) cards like Digi96 requires 8+8 channels.
 */
#define MAX_PLAY_CHANNELS	12
/* MAX_REC_CHANNELS must be less or equal than MAX_PLAY_CHANNELS */
#define MAX_REC_CHANNELS	12

#define CHBUF_SAMPLES		2048	/* Max samples (frames) per fragment */

typedef struct _vmix_mixer_t vmix_mixer_t;
typedef struct _vmix_portc_t vmix_portc_t;
typedef struct _vmix_engine_t vmix_engine_t;
typedef unsigned char vmix_channel_map_t[MAX_PLAY_CHANNELS];

struct _vmix_portc_t		/* Audio device specific data */
{
  int num;
  vmix_mixer_t *mixer;
  vmix_portc_t *next;		/* Linked list for all portc structures */
  int dev_type;
#define DT_IN		1
#define DT_OUT		2
#define DT_LOOP		3

  int disabled_modes;

  int fmt, bits;
  int channels;
  int rate;

  int audio_dev;
  int open_mode;
  int trigger_bits;

  int open_pending;	/* Set to 1 by vmix_create_client() and cleared by vmix_open() */

  int play_dma_pointer;
  int play_choffs;		/* Index of the first channel on multich play engines */
  int rec_choffs;		/* Index of the first channel on multich rec engines */
#ifdef CONFIG_OSS_VMIX_FLOAT
  double play_dma_pointer_src;
#endif
  int rec_dma_pointer;
  int volume[2]; /* Left and right ch volumes */
  int vu[2];

  void (*play_mixing_func) (vmix_portc_t * portc, int nsamples);
  void (*rec_mixing_func) (vmix_portc_t * portc, int nsamples);
  int do_src;
  vmix_channel_map_t channel_order;
};

#ifdef CONFIG_OSS_VMIX_FLOAT
   typedef float vmix_sample_t;
#else
   typedef int vmix_sample_t;
#endif

typedef void (*converter_t) (vmix_engine_t * engine, void *outbuf,
			     vmix_sample_t * chbufs[], int channels,
			     int samples);

struct _vmix_engine_t
{
  int rate, channels, fmt, bits;
  int max_playahead;
  int fragsize;
  int samples_per_frag;

  converter_t converter;
  vmix_sample_t *chbufs[MAX_PLAY_CHANNELS];
  unsigned int limiter_statevar;

/*
 * Mixer volumes, etc.
 */
  int outvol;
  int vu[2];
  int num_active_outputs;
  vmix_channel_map_t channel_order;
};

struct _vmix_mixer_t		/* Instance specific data */
{
  vmix_mixer_t *next;		/* Pointer to the next vmix instance */
  int instance_num;
  int disabled;
  oss_device_t *osdev;
  oss_device_t *master_osdev;
  oss_mutex_t mutex;
  unsigned int attach_flags;

  int installed_ok;

  int open_devices, open_inputs;
  struct fileinfo master_finfo, input_finfo;
  int masterdev_opened;

  int vmix_flags;		/* Copy of adev[master]->vmix_flags */

/*
 * Config options for this instance
 */
  int masterdev;
  int inputdev;
  int rate;

  int src_quality;		/* Control panel setting */
  int multich_enable;		/* Enable multi channel mode */
  int max_channels;

  vmix_engine_t play_engine, record_engine;

  vmix_portc_t *client_portc[MAX_CLIENTS];
  vmix_portc_t *loop_portc[MAX_LOOPDEVS];
  int num_clientdevs, num_loopdevs;

/*
 * Mixer interface
 *
 * Mixer device numbers for the master audio devices
 */
  int output_mixer_dev;
  int input_mixer_dev;
  int first_input_mixext;
  int first_output_mixext;
  int client_mixer_group;	/* Create the client controls under this mixer group */
};

extern void vmix_setup_play_engine (vmix_mixer_t * mixer, adev_t * adev,
				    dmap_t * dmap);
extern void vmix_setup_record_engine (vmix_mixer_t * mixer, adev_t * adev,
				      dmap_t * dmap);
extern void finalize_record_engine (vmix_mixer_t * mixer, int fmt,
				    adev_t * adev, dmap_p dmap);

extern void vmix_outmix_16ne (vmix_portc_t * portc, int nsamples);
extern void vmix_outmix_16oe (vmix_portc_t * portc, int nsamples);
extern void vmix_outmix_32ne (vmix_portc_t * portc, int nsamples);
extern void vmix_outmix_32oe (vmix_portc_t * portc, int nsamples);
#ifdef CONFIG_OSS_VMIX_FLOAT
extern void vmix_outmix_float (vmix_portc_t * portc, int nsamples);
#endif

#ifdef CONFIG_OSS_VMIX_FLOAT
/*
 * For the time being these routines will only work in floating point.
 */
extern void vmix_outmix_16ne_src (vmix_portc_t * portc, int nsamples);
extern void vmix_outmix_16oe_src (vmix_portc_t * portc, int nsamples);
extern void vmix_outmix_32ne_src (vmix_portc_t * portc, int nsamples);
extern void vmix_outmix_32oe_src (vmix_portc_t * portc, int nsamples);
extern void vmix_outmix_float_src (vmix_portc_t * portc, int nsamples);
#endif

extern void vmix_rec_export_16ne (vmix_portc_t * portc, int nsamples);
extern void vmix_rec_export_16oe (vmix_portc_t * portc, int nsamples);
extern void vmix_rec_export_32ne (vmix_portc_t * portc, int nsamples);
extern void vmix_rec_export_32oe (vmix_portc_t * portc, int nsamples);
#ifdef CONFIG_OSS_VMIX_FLOAT
extern void vmix_rec_export_float (vmix_portc_t * portc, int nsamples);
#endif

#define DB_SIZE	50
#define VMIX_VOL_SCALE	127

#ifdef CONFIG_OSS_VMIX_FLOAT
   extern const float vmix_db_table[DB_SIZE + 1];
#else
   extern const int vmix_db_table[DB_SIZE + 1];
#endif

#ifdef VMIX_MAIN
#include "db_scale.h"
#endif

#ifdef SWAP_SUPPORT
/*
 * Endianess swapping functions
 */
static __inline__ short
bswap16 (short x)
{
  short y = 0;
  unsigned char *a = ((unsigned char *) &x) + 1;
  unsigned char *b = (unsigned char *) &y;

  *b++ = *a--;
  *b++ = *a--;

  return y;
}

static __inline__ int
bswap32 (int x)
{

  int y = 0;
  unsigned char *a = ((unsigned char *) &x) + 3;
  unsigned char *b = (unsigned char *) &y;

  *b++ = *a--;
  *b++ = *a--;
  *b++ = *a--;
  *b++ = *a--;

  return y;
}
#endif
