/* multi_audio.h */

/* Interface description for drivers implementing studio-level audio I/O with */
/* possible auxillary functions (transport, time code, etc). */
/* Copyright © 1998-2001 Be Incorporated. All rights reserved. */

#if !defined(_MULTI_AUDIO_H)
#define _MULTI_AUDIO_H

#include <Drivers.h>
#include <Debug.h>
#include <audio_base.h>

#define B_MULTI_DRIVER_BASE (B_AUDIO_DRIVER_BASE+20)

enum {	/* open() modes */
	/*	O_RDONLY is 0, O_WRONLY is 1, O_RDWR is 2	*/
	B_MULTI_CONTROL = 3
};

/* ioctl codes */
enum {
	/* multi_description */
	B_MULTI_GET_DESCRIPTION = B_MULTI_DRIVER_BASE,
	/* multi_event_handling */
	B_MULTI_GET_EVENT_INFO,
	B_MULTI_SET_EVENT_INFO,
	B_MULTI_GET_EVENT,
	/* multi_channel_enable */
	B_MULTI_GET_ENABLED_CHANNELS,
	B_MULTI_SET_ENABLED_CHANNELS,
	/* multi_format_info */
	B_MULTI_GET_GLOBAL_FORMAT,
	B_MULTI_SET_GLOBAL_FORMAT,		/* always sets for all channels, always implemented */
	/* multi_channel_formats */
	B_MULTI_GET_CHANNEL_FORMATS,
	B_MULTI_SET_CHANNEL_FORMATS,	/* only implemented if possible */
	/* multi_mix_value_info */
	B_MULTI_GET_MIX,
	B_MULTI_SET_MIX,
	/* multi_mix_channel_info */
	B_MULTI_LIST_MIX_CHANNELS,
	/* multi_mix_control_info */
	B_MULTI_LIST_MIX_CONTROLS,
	/* multi_mix_connection_info */
	B_MULTI_LIST_MIX_CONNECTIONS,
	/* multi_buffer_list */
	B_MULTI_GET_BUFFERS,			/* Fill out the struct for the first time; doesn't start anything. */
	B_MULTI_SET_BUFFERS,			/* Set what buffers to use, if the driver supports soft buffers. */
	/* bigtime_t */
	B_MULTI_SET_START_TIME,			/* When to actually start */
	/* multi_buffer_info */
	B_MULTI_BUFFER_EXCHANGE,		/* stop and go are derived from this being called */
	B_MULTI_BUFFER_FORCE_STOP,		/* force stop of playback */
	/* extension protocol */
	B_MULTI_LIST_EXTENSIONS,		/* get a list of supported extensions */
	B_MULTI_GET_EXTENSION,			/* get the value of an extension (or return error if not supported) */
	B_MULTI_SET_EXTENSION,			/* set the value of an extension */
	/* multi_mode_list */
	B_MULTI_LIST_MODES,				/* get a list of possible modes (multi_mode_list * arg) */
	B_MULTI_GET_MODE,				/* get the current mode (int32 * arg) */
	B_MULTI_SET_MODE				/* set a new mode (int32 * arg) */
};

/*	possible sample lock sources */
#define B_MULTI_LOCK_INPUT_CHANNEL 0x0	/* lock_source_data is channel id */
#define B_MULTI_LOCK_INTERNAL 0x1
#define B_MULTI_LOCK_WORDCLOCK 0x2
#define B_MULTI_LOCK_SUPERCLOCK 0x4
#define B_MULTI_LOCK_LIGHTPIPE 0x8
#define B_MULTI_LOCK_VIDEO 0x10			/* or blackburst */
#define B_MULTI_LOCK_FIRST_CARD 0x20	/* if you have more than one card */
#define B_MULTI_LOCK_MTC 0x40
#define B_MULTI_LOCK_SPDIF 0x80

/* possible timecode sources */
#define B_MULTI_TIMECODE_MTC 0x1
#define B_MULTI_TIMECODE_VTC 0x2
#define B_MULTI_TIMECODE_SMPTE 0x4
#define B_MULTI_TIMECODE_SUPERCLOCK 0x8
#define B_MULTI_TIMECODE_FIREWIRE 0x10

/* interface_flags values */
/* Available functions on this device. */
#define B_MULTI_INTERFACE_PLAYBACK 0x1
#define B_MULTI_INTERFACE_RECORD 0x2
#define B_MULTI_INTERFACE_TRANSPORT 0x4
#define B_MULTI_INTERFACE_TIMECODE 0x8
/* "Soft" buffers means you can change the pointer values and the driver will still be happy. */
#define B_MULTI_INTERFACE_SOFT_PLAY_BUFFERS 0x10000
#define B_MULTI_INTERFACE_SOFT_REC_BUFFERS 0x20000
/* Whether the data stream is interrupted when changing channel enables. */
#define B_MULTI_INTERFACE_CLICKS_WHEN_ENABLING_OUTPUTS 0x40000
#define B_MULTI_INTERFACE_CLICKS_WHEN_ENABLING_INPUTS 0x80000

#define B_CURRENT_INTERFACE_VERSION 0x4502
#define B_MINIMUM_INTERFACE_VERSION 0x4502

typedef struct multi_description multi_description;
typedef struct multi_channel_info multi_channel_info;
struct multi_description {

	size_t			info_size;			/* sizeof(multi_description) */
	uint32			interface_version;	/* current version of interface that's implemented */
	uint32			interface_minimum;	/* minimum version required to understand driver */

	char			friendly_name[32];	/* name displayed to user (C string) */
	char			vendor_info[32];	/* name used internally by vendor (C string) */

	int32			output_channel_count;
	int32			input_channel_count;
	int32			output_bus_channel_count;
	int32			input_bus_channel_count;
	int32			aux_bus_channel_count;

	int32			request_channel_count;		/* how many channel_infos are there */
	multi_channel_info *
					channels;

	uint32			output_rates;
	uint32			input_rates;
	float			min_cvsr_rate;
	float			max_cvsr_rate;
	uint32			output_formats;
	uint32			input_formats;
	uint32			lock_sources;
	uint32			timecode_sources;

	uint32			interface_flags;
	bigtime_t		start_latency;		/* how much in advance driver needs SET_START_TIME */

	uint32			_reserved_[11];

	char			control_panel[64];	/* MIME type of control panel application */
};

#define B_CHANNEL_MONO_BUS 0x4000000
#define B_CHANNEL_STEREO_BUS 0x2000000		/* + left/right */
#define B_CHANNEL_SURROUND_BUS 0x1000000	/* multichannel */

/* If you have interactions where some inputs can not be used when some */
/* outputs are used, mark both inputs and outputs with this flag. */
#define B_CHANNEL_INTERACTION 0x80000000UL
/* If input channel #n is simplexed with output channel #n, they should both */
/* have this flag set (different from the previous flag, which is more vague). */
#define B_CHANNEL_SIMPLEX 0x40000000UL

/* connector values */
/* analog connectors */
#define B_CHANNEL_RCA 0x1
#define B_CHANNEL_XLR 0x2
#define B_CHANNEL_TRS 0x4
#define B_CHANNEL_QUARTER_INCH_MONO 0x8
#define B_CHANNEL_MINI_JACK_STEREO 0x10
#define B_CHANNEL_QUARTER_INCH_STEREO 0x20
#define B_CHANNEL_ANALOG_HEADER 0x100	/* internal on card */
#define B_CHANNEL_SNAKE 0x200			/* or D-sub */
/* digital connectors (stereo) */
#define B_CHANNEL_OPTICAL_SPDIF 0x1000
#define B_CHANNEL_COAX_SPDIF 0x2000
#define B_CHANNEL_COAX_EBU 0x4000
#define B_CHANNEL_XLR_EBU 0x8000
#define B_CHANNEL_TRS_EBU 0x10000
#define B_CHANNEL_SPDIF_HEADER 0x20000	/* internal on card */
/* multi-channel digital connectors */
#define B_CHANNEL_LIGHTPIPE 0x100000
#define B_CHANNEL_TDIF 0x200000
#define B_CHANNEL_FIREWIRE 0x400000
#define B_CHANNEL_USB 0x800000
/* If you have multiple output connectors, only one of which can */
/* be active at a time. */
#define B_CHANNEL_EXCLUSIVE_SELECTION 0x80000000UL


typedef enum {
	B_MULTI_NO_CHANNEL_KIND,
	B_MULTI_OUTPUT_CHANNEL = 0x1,
	B_MULTI_INPUT_CHANNEL = 0x2,
	B_MULTI_OUTPUT_BUS = 0x4,
	B_MULTI_INPUT_BUS = 0x8,
	B_MULTI_AUX_BUS = 0x10
} channel_kind;

struct multi_channel_info {
	int32			channel_id;
	channel_kind	kind;
	uint32			designations;
	uint32			connectors;
	uint32			_reserved_[4];
};


/* Constants */
#define B_MULTI_EVENT_MINMAX		16
/* Event flags/masks */
#define B_MULTI_EVENT_TRANSPORT 	0x40000000UL
#define B_MULTI_EVENT_HAS_TIMECODE 	0x80000000UL

/* possible transport events */
#define B_MULTI_EVENT_NONE			0x00000000UL
#define B_MULTI_EVENT_START 		0x40010000UL
#define B_MULTI_EVENT_LOCATION 		0x40020000UL		/* location when shuttling or locating */
#define B_MULTI_EVENT_SHUTTLING 	0x40040000UL
#define B_MULTI_EVENT_STOP 			0x40080000UL
#define B_MULTI_EVENT_RECORD 		0x40100000UL
#define B_MULTI_EVENT_PAUSE 		0x40200000UL
#define B_MULTI_EVENT_RUNNING 		0x40400000UL		/* location when running */
/* possible device events */
enum {
	B_MULTI_EVENT_STARTED				= 0x1,
	B_MULTI_EVENT_STOPPED				= 0x2,
	B_MULTI_EVENT_CHANNEL_FORMAT_CHANGED= 0x4,
	B_MULTI_EVENT_BUFFER_OVERRUN 		= 0x8,
	B_MULTI_EVENT_SIGNAL_LOST 			= 0x10,
	B_MULTI_EVENT_SIGNAL_DETECTED 		= 0x20, 
	B_MULTI_EVENT_CLOCK_LOST 			= 0x40,
	B_MULTI_EVENT_CLOCK_DETECTED 		= 0x80,
	B_MULTI_EVENT_NEW_MODE 				= 0x100,
	B_MULTI_EVENT_CONTROL_CHANGED 		= 0x200
};

typedef struct multi_get_event_info multi_get_event_info;
struct multi_get_event_info {
	size_t		info_size;		/* sizeof(multi_get_event_info) */
	uint32		supported_mask;	/* what events h/w supports */
	uint32		current_mask;	/* current driver value */
	uint32		queue_size;		/* current queue size */
	uint32		event_count;	/* number of events currently in queue*/
	uint32		_reserved[3];
};

typedef struct multi_set_event_info multi_set_event_info;
struct multi_set_event_info {
	size_t		info_size;		/* sizeof(multi_set_event_info) */
	uint32		in_mask;		/* what events to wait for */
	int32		semaphore;		/* semaphore app will wait on */
	uint32		queue_size;		/* minimum number of events to save */
	uint32		_reserved[4];
};

typedef struct multi_get_event multi_get_event;
struct multi_get_event {
	size_t		info_size;		/* sizeof(multi_get_event) */
	uint32		event;
	bigtime_t	timestamp;		/* real time at which event was received */
	int32		count;			/* used for configuration events */
	union {
			int32		channels[100];
			uint32		clocks;
			int32		mode;
			int32		controls[100];
			struct { /* transport event */
				float		out_rate;		/* what rate it's now playing at */
				int32		out_hours;		/* location at the time given */
				int32		out_minutes;
				int32		out_seconds;
				int32		out_frames;
			}transport;
			char			_reserved_[400];		
	#if defined(__cplusplus)
		};
	#else
		} u;
	#endif
	uint32	_reserved_1[10];
};

typedef struct multi_channel_enable multi_channel_enable;
struct multi_channel_enable {
	size_t			info_size;			/* sizeof(multi_channel_enable) */
	/* this must have bytes for all channels (see multi_description) */
	/* channel 0 is lowest bit of first byte */
	uchar *			enable_bits;

	uint32			lock_source;
	int32			lock_data;
	uint32			timecode_source;
	uint32 *		connectors;			/* which connector(s) is/are active, per channel */
};

#include <stdio.h>

#if defined(__cplusplus)
	inline void B_SET_CHANNEL(void * bits, int channel, bool value)
	{
		ASSERT(channel>=0);
		(((uchar *)(bits))[((channel)&0x7fff)>>3] =
			(((uchar *)(bits))[((channel)&0x7fff)>>3] & ~(1<<((channel)&0x7))) |
			((value) ? (1<<((channel)&0x7)) : 0));
	}
	inline bool B_TEST_CHANNEL(const void * bits, int channel)
	{
		return ((((uchar *)(bits))[((channel)&0x7fff)>>3] >> ((channel)&0x7)) & 1);
	}
#else
	#define B_SET_CHANNEL(bits, channel, value) \
		ASSERT(channel>=0); \
		(((uchar *)(bits))[((channel)&0x7fff)>>3] = \
			(((uchar *)(bits))[((channel)&0x7fff)>>3] & ~(1<<((channel)&0x7))) | \
			((value) ? (1<<((channel)&0x7)) : 0))
	#define B_TEST_CHANNEL(bits, channel) \
		((((uchar *)(bits))[((channel)&0x7fff)>>3] >> ((channel)&0x7)) & 1)
#endif

typedef struct multi_channel_formats multi_channel_formats;
typedef struct multi_format_info multi_format_info;
typedef struct _multi_format _multi_format;

struct _multi_format {
	uint32			rate;
	float			cvsr;
	uint32			format;
	uint32			_reserved_[3];
};
enum {	/* timecode kinds */
	B_MULTI_NO_TIMECODE,
	B_MULTI_TIMECODE_30,			/* MIDI */
	B_MULTI_TIMECODE_30_DROP_2,		/* NTSC */
	B_MULTI_TIMECODE_30_DROP_4,		/* Brazil */
	B_MULTI_TIMECODE_25,			/* PAL */
	B_MULTI_TIMECODE_24				/* Film */
};
struct multi_format_info {
	size_t			info_size;			/* sizeof(multi_format_info) */
	bigtime_t		output_latency;
	bigtime_t		input_latency;
	int32			timecode_kind;
	uint32			_reserved_[7];
	_multi_format	input;
	_multi_format	output;
};
struct multi_channel_formats {
	size_t			info_size;			/* sizeof(multi_channel_formats) */
	int32			request_channel_count;
	int32			request_first_channel;
	int32			returned_channel_count;
	int32			timecode_kind;
	int32			_reserved_[4];
	_multi_format *
					channels;
	bigtime_t *		latencies;			/* DMA/hardware latencies; client calculates for buffers */
};


typedef struct multi_mix_value multi_mix_value;
struct multi_mix_value {
	int32			id;
	union {
		float			gain;
		uint32			mux;	/* bitmask of mux points */
		bool			enable;
		uint32			_reserved_[2];
#if defined(__cplusplus)
	};
#else
	} u;
#endif
	int32			ramp;
	uint32			_reserved_2[2];
};

typedef struct multi_mix_value_info multi_mix_value_info;
struct multi_mix_value_info {
	size_t			info_size;		/* sizeof(multi_mix_value_info) */
	int32			item_count;
	multi_mix_value *
					values;
	int32			at_frame;		/* time at which to start the change */
};

//	only one of these should be set
#define B_MULTI_MIX_JUNCTION 0x1
#define B_MULTI_MIX_GAIN 0x2
#define B_MULTI_MIX_MUX 0x4
#define B_MULTI_MIX_ENABLE 0x8
#define B_MULTI_MIX_KIND_MASK 0xffff
//	any combination of these can be set
#define B_MULTI_MIX_RAMP 0x10000

typedef struct multi_mix_control multi_mix_control;
struct multi_mix_control {
	int32			id;				/* unique for device -- not same id as any channel/bus ! */
	uint32			flags;			/* including kind */
	int32			master;			/* or 0 if it's not slaved */
	union {
		struct {
			float			min_gain;		/* dB */
			float			max_gain;		/* dB */
			float			granularity;	/* dB */
		}			gain;
		struct {
			uint32			_reserved;
		}			mux;
		struct {
			uint32			_reserved;
		}			enable;
		uint32		_reserved[12];
#if defined(__cplusplus)
	};
#else
	}				u;
#endif
	char			name[32];
};

typedef struct multi_mix_channel_info multi_mix_channel_info;
struct multi_mix_channel_info {
	size_t			info_size;		/* sizeof(multi_mix_channel_info) */
	int32			channel_count;
	int32 *			channels;		/* allocated by caller, lists requested channels */
	int32			max_count;		/* in: control ids per channel */
	int32			actual_count;	/* out: actual max # controls for any individual requested channel */
	int32 **		controls;
};

typedef struct multi_mix_control_info multi_mix_control_info;
struct multi_mix_control_info {
	size_t			info_size;		/* sizeof(multi_mix_control_info) */
	int32			control_count;	/* in: number of controls */
	multi_mix_control *
					controls;		/* allocated by caller, returns control description for each */
};

typedef struct multi_mix_connection multi_mix_connection;
struct multi_mix_connection {
	int32			from;
	int32			to;
	uint32			_reserved_[2];
};

typedef struct multi_mix_connection_info multi_mix_connection_info;
struct multi_mix_connection_info {
	size_t			info_size;
	int32			max_count;		/* in: available space */
	int32			actual_count;	/* out: actual count */
	multi_mix_connection *
					connections;	/* allocated by caller, returns connections */
};


/* possible flags values for what is available (in and out) */
#define B_MULTI_BUFFER_PLAYBACK 0x1
#define B_MULTI_BUFFER_RECORD 0x2
#define B_MULTI_BUFFER_METERING 0x4
#define B_MULTI_BUFFER_TIMECODE 0x40000

typedef struct multi_buffer_list multi_buffer_list;
typedef struct buffer_desc buffer_desc;
/* This struct is used to query the driver about what buffers it will use, */
/* and to tell it what buffers to use if it supports soft buffers. */
struct multi_buffer_list {

	size_t			info_size;				/* sizeof(multi_buffer_list) */
	uint32			flags;

	int32			request_playback_buffers;
	int32			request_playback_channels;
	uint32			request_playback_buffer_size;		/* frames per buffer */
	int32			return_playback_buffers;			/* playback_buffers[b][] */
	int32			return_playback_channels;			/* playback_buffers[][c] */
	uint32			return_playback_buffer_size;		/* frames */
	buffer_desc **	playback_buffers;
	void *			_reserved_1;

	int32			request_record_buffers;
	int32			request_record_channels;
	uint32			request_record_buffer_size;			/* frames per buffer */
	int32			return_record_buffers;
	int32			return_record_channels;
	uint32			return_record_buffer_size;			/* frames */
	buffer_desc **	record_buffers;
	void *			_reserved_2;

};

struct buffer_desc {
	char *			base;		/* pointer to first sample for channel for buffer */
	size_t			stride;		/* offset to next sample */
	uint32			_reserved_[2];
};


/* This struct is used when actually queuing data to be played, and/or */
/* receiving data from a recorder. */
typedef struct multi_buffer_info multi_buffer_info;
struct multi_buffer_info {

	size_t			info_size;			/* sizeof(multi_buffer_info) */
	uint32			flags;

	bigtime_t		played_real_time;
	bigtime_t		played_frames_count;
	int32			_reserved_0;
	int32			playback_buffer_cycle;

	bigtime_t		recorded_real_time;
	bigtime_t		recorded_frames_count;
	int32			_reserved_1;
	int32			record_buffer_cycle;

	int32			meter_channel_count;
	char *			meters_peak;	/* in the same format as the data; allocated by caller */
	char *			meters_average;	/* in the same format as the data; allocated by caller */

	/*	timecode sent and received at buffer swap	*/
	int32			hours;
	int32			minutes;
	int32			seconds;
	int32			tc_frames;		/* for timecode frames as opposed to sample frames */
	int32			at_frame_delta;	/* how far into buffer (or before buffer for negative) */

};


typedef struct multi_mode_info multi_mode_info;
typedef struct multi_mode_list multi_mode_list;

struct multi_mode_list {
	size_t			info_size;		/* sizeof(multi_mode_list) */
	int32			in_request_count;
	int32			out_actual_count;
	int32			out_current_mode;
	multi_mode_info *
					io_modes;
};

struct multi_mode_info {
	int32			mode_id;
	uint32			flags;
	char			mode_name[64];
	int32			input_channel_count;
	int32			output_channel_count;
	float			best_frame_rate_in;
	float			best_frame_rate_out;
	uint32			sample_formats_in;
	uint32			sample_formats_out;
	char			_reserved[160];
};


/*	This extension protocol can grow however much you want.	*/
/*	Good extensions should be put into this header; really	*/
/*	good extensions should become part of the regular API.	*/
/*	For developer-developed extensions, use all lowercase	*/
/*	and digits (no upper case). If we then bless a third-	*/
/*	party extension, we can just upper-case the selector.	*/

typedef struct multi_extension_list multi_extension_list;
typedef struct multi_extension_info multi_extension_info;
struct multi_extension_info {
	uint32			code;
	uint32			flags;
	char			name[24];
};

#define B_MULTI_MAX_EXTENSION_COUNT 31
struct multi_extension_list	{ /* MULTI_LIST_EXTENSIONS */
	size_t			info_size;		/* sizeof(multi_extension_list) */
	uint32			max_count;
	int32			actual_count;	/* return # of actual extensions */
	multi_extension_info *
					extensions;		/* allocated by caller */
};

typedef struct multi_extension_cmd multi_extension_cmd;
struct multi_extension_cmd {	/* MULTI_GET_EXTENSION and MULTI_SET_EXTENSION */
	size_t			info_size;		/* sizeof(multi_extension_cmd) */
	uint32			code;
	uint32			_reserved_1;
	void *			in_data;
	size_t			in_size;
	void *			out_data;
	size_t			out_size;
};

enum {
	B_MULTI_EX_CLOCK_GENERATION = 'CLGE',
	B_MULTI_EX_DIGITAL_FORMAT = 'DIFO',
	B_MULTI_EX_OUTPUT_NOMINAL = 'OUNO',
	B_MULTI_EX_INPUT_NOMINAL = 'INNO'
};

typedef struct multi_ex_clock_generation multi_ex_clock_generation;
struct multi_ex_clock_generation {
	int32			channel;	/* if specific, or -1 for all */
	uint32			clock;		/* WORDCLOCK or SUPERCLOCK, typically */
};

typedef struct multi_ex_digital_format multi_ex_digital_format;
struct multi_ex_digital_format {
	int32			channel;	/* if specific, or -1 for all */
	uint32			format; 	/* B_CHANNEL_*_SPDIF or B_CHANNEL_*_EBU */
};

enum {
	B_MULTI_NOMINAL_MINUS_10 = 1, 
	B_MULTI_NOMINAL_PLUS_4
};

typedef struct multi_ex_nominal_level multi_ex_nominal_level;
struct multi_ex_nominal_level {
	int32			channel;	/* if specific, or -1 for all */
	int32			level;
};

#endif /* _MULTI_AUDIO_H */

