/* GSI - general sound interface
 *
 * gsicd.h
 *
 * By W.H.Scholten 1998 - 2000
 *
 * This file is released to the public domain.
 */


#ifndef _GSI__lib__gsicd__gsicd_h
#define _GSI__lib__gsicd__gsicd_h

#ifdef _cplusplus
extern "C" {
#endif /* __cplusplus */

#include <gsi/whs_types.h>

/* CD device status: */
#define GSICD_STATUS_NONE             0
#define GSICD_STATUS_PLAYING          1
#define GSICD_STATUS_PAUSED           2

#define GSICD_STATUS_NO_DISK          3
#define GSICD_STATUS_NO_DRIVE         4
#define GSICD_STATUS_UNAVAILABLE      5


/* Errors: */
#define GSICD_OK                      0
#define GSICD_ERROR_UNKNOWN          -1
#define GSICD_ERROR_MOUNTED          -2
#define GSICD_ERROR_BAD_SLOT         -3


/* Events (first two are generated with a timer, SIGALRM) */
#define GSICD_EVENT_TRACK_START       0
#define GSICD_EVENT_TRACK_END         1
#define GSICD_EVENT_TRACK_PAUSE       2
#define GSICD_EVENT_TRACK_RESUME      3
#define GSICD_EVENT_STOP              4


/* CD output options */
#define GSICD_OUTPUT_MUTE             1
#define GSICD_OUTPUT_LEFT_CHANNEL     2
#define GSICD_OUTPUT_RIGHT_CHANNEL    3
#define GSICD_OUTPUT_MONO             4
#define GSICD_OUTPUT_STEREO           5


#define GSICD_MAX_TRACKS            170 /* dynamic allocation ? */

typedef enum { GSICD_DATA, GSICD_AUDIO, GSICD_END } cd_track_type;

typedef struct gsi_cd_track_info {
	unsigned char min;
	unsigned char sec;
	unsigned char frame;
	unsigned char type; /* GSICD_DATA, GSICD_AUDIO = 0,1 */
} gsi_cd_track_info;

typedef struct gsi_cd_track_item {
	unsigned char offset_min;    /* offset from 'track' */
	unsigned char offset_sec;    /*      ,,             */
	unsigned char offset_frame;  /*      ,,             */
	unsigned char track;
} gsi_cd_track_item;

typedef struct gsi_cd_status {
	int  min;
	int  sec;
	int  frame;
	int  track;
	int  status;
} gsi_cd_status_t;


/*---------------------------------------------------------------------------*
 *      cd device abstraction.
 *---------------------------------------------------------------------------*/
typedef struct {
	char *device; /* the device to open, e.g. /dev/cdrom */
	char id[32];

	int  (*init) (int cd, int modus);
	int  (*close) (int cd);
	int  (*play) (int cd, int m, int s, int f, int em, int es, int ef);
	int  (*stop) (int cd);
	/* add more.. */

	/* set timer for track end/start events
	int  (*set_timer) (int cd, void *update_fn, int sec, int musec);
	int  (*stop_timer) (int cd);
	*/

	int  num_slots;
	int  flags;
} gsi_cd_device_t;

/*      cd device status: */
typedef struct {
	int  dev; /* weg ? */
	int  fd;
	int  fd_ct;
	int  flags; /* put keep_open in here? */

	int  keep_open;

	/* hardware info: */
	int  slot;

	/* current CD info: */
	int  num_tracks;
	int  first_audio_track;
	int  last_audio_track;
	gsi_cd_track_info   track[ GSICD_MAX_TRACKS+2 ];

	int  playing; /* yes/no; used in event generation etc. */
	int  track_of_previous_event;

	/* play range (tracks + offsets from these tracks): */
	gsi_cd_track_item  first;
	gsi_cd_track_item  last;

	/* status & playing position after last call of gsicd_status: */
	int  status; /* hardware status (playing/paused/no disk etc) */
	int  current_track;
	int  current_m;
	int  current_s;
	int  current_f;

	/* events */
	int  next_track; /* we expect an alarm for this one */
} gsi_cd_devicedata_t;


extern gsi_cd_device_t *cd_devices;
extern int num_cds;
extern gsi_cd_devicedata_t cd_status[16]; /* temp */



/*****************************************************************************
 *
 *        Functions
 *
 *****************************************************************************/
int  gsicd_init(int cd);
int  gsicd_done(int cd);

int  gsicd_stop(int cd);
int  gsicd_pause(int cd);
int  gsicd_resume(int cd);

/* int  gsicd_play(gsi_cd_track_item *t1, gsi_cd_track_item *t2); */
int  gsicd_play(int cd, int t1, int m1, int s1, int f1,  int t2, int m2, int s2, int f2);

int  gsicd_eject(int cd);
int  gsicd_insert(int cd);
int  gsicd_select_slot(int cd, int slot);

int  gsicd_update_status(int cd);

int  gsicd_set_channels(int cd, int cmd);
void gsicd_set_output_volume(int cd, int volume);
int  gsicd_get_output_volume(int cd);


/* internal: */
int  _gsicd_get_contents(int cd);
int  _gsicd_get_status(int cd, gsi_cd_status_t *pos);


/* utils: */
int  gsicd_m_from_lba (int lba);
int  gsicd_s_from_lba (int lba);
int  gsicd_f_from_lba (int lba);
/*   a frame is 1/75 seconds. */

int  gsicd_lba_from_msf (int m, int s, int f);
int  gsicd_lba_track_len (int cd, int i);
int  gsicd_lba_track_pos (int cd, int i);


/* events: */
int  _gsicd_nearest_track (int cd);

void _gsicd_stop_timer (void);
void _gsicd_set_timer (void *updatefn, int sec, int musec);

void _gsicd_update (int signum);
void gsicd_set_timer (void);

void gsicd_event (int event, int cd, int track);
void gsicd_set_event_function (void *fn);

void gsicd_lowlevel_event (void);
void gsicd_set_lowlevel_event_function (void *fn);

void gsicd_generate_events (void);

/* timer: */
int  gsicd_stop_timer_for(int cd);
/* void gsicd_set_timer_for(int cd, void *updatefn, int sec, int musec); */

#ifdef _cplusplus
}
#endif /* __cplusplus */

#endif /* _GSI__lib__gsicd__gsicd_h */
