/*
	Audio mode values, Sound buffer, and Recorder device
 */

#ifndef YSOUND_H
#define YSOUND_H

#include <sys/types.h>
#include "ytypes.h"
#include "ytiming.h"
#include "midiiow.h"
#include "audiocd.h"

/*
 *	Audio play direction:
 */
#define AUDIO_DIRECTION_PLAY	0
#define	AUDIO_DIRECTION_RECORD	1

/*
 *	Cycle set reliance:
 *
 *	Determines who is to set the cycle.
 */
#define CYCLE_SET_PROGRAM       0
#define CYCLE_SET_HARDWARE      1
#define CYCLE_SET_USER          2


/*
 *	Sound buffers structure:
 *
 *	Midway buffer and actual sound buffer that is sent to the
 *	audio device for playing or recording.
 */
typedef struct {

	/* Midway buffer, it is publically modifyable.
	 *
	 * Note: If the recorder audio's sample_size is set to 16
	 * then the limit of this buffer should be (buffer_length / 2)
	 * and the call to YSoundPlayBuffer() will automatically
	 * expand buffer when it coppies it to device_buffer.
	 *
	 * If YSHM_SUPPORT is defined, then this buffer is a shared
	 * memory segment and needs to be managed with SHMNew() and
	 * SHMUnref() instead of calloc() and free().
	 */
	SoundBuffer	*buffer;
	YDataLength	buffer_length,
			buffer_content_length;
#ifdef YSHM_SUPPORT
	int buffer_shm_id;	/* Garbage if buffer is NULL. */
#endif

	/* Devices's buffer, private.  Do not read or write it! */
	SoundBuffer	*device_buffer;
	YDataLength	device_buffer_length,
			device_buffer_content_length;

} Sound;


/*
 *	Audio structure:
 *
 *	Characteristics of the audio device.
 */
typedef struct {

	/*   Determines who sets the cycle for sound transfers,
	 *   can be one of CYCLE_SET_*
	 */
	int	cycle_set;

	/*   True audio device determined cycle. The audio device
	 *   requires a new buffer to play/record determined by the
	 *   delta time of cycle.  This value is theoretical, using
	 *   this blindly will probably cause gaps in audio, instead
	 *   rely on compensated_cycle (see below).
	 */
	YDeltaTime	cycle;

	/*   Compensated cycle, which is calculated by MAX(cycle -
	 *   cumulative_latency, 0).
	 *   This is similar to cycle except that it takes into account
	 *   the cumulative_latency (see below) that changes very often.
	 *   This is the accurate value you want to use when determining
	 *   when to send a new buffer to the audio device.
	 */
	YDeltaTime	compensated_cycle;


	/*   Amount of time the Audio device lets us send a buffer to
	 *   it ahead of time. This value is NOT used to calculate
	 *   compensated_cycle, but to sync the audio device on
	 *   initializations and syncs.
	 */
	YDeltaTime	write_ahead;

	/*   A count down value in the range of [write_ahead, 0] to
	 *   indicate the time needed to cycle ahead and write()
	 *   buffers to the audio device prematurly.  This is required
	 *   for Linux OSS buffer fragmenting compliancy.  The member
	 *   write_ahead indicates what cycle_ahead_left should be
	 *   reset to each time the audio device is reset/synced/reopened.
	 *   cycle_ahead_left will be decreased by the proper amount
	 *   per each write() to the audio device (see
	 *   YiffUpdateTimers()).
	 */
	YDeltaTime	cycle_ahead_left;

	/*   Total amount of latency caused by the program doing it's
	 *   work per loop. This value is used to calculate
	 *   compensated_cycle.
	 */
	YDeltaTime	cumulative_latency;


	/* Size of sample, in units of bits. Usually 8 or 16.*/
	int sample_size;

	/* Number of channels. Usually 1 or 2. */
	int channels;

	/* Sample's rate, in Hz. */
	int sample_rate;

	/*   Bytes that are played (not to be played) per second.
	 *   For the exact bytes to be played per cycle, see
	 *   buffer_length.
	 */
	YDataLength bytes_per_second;


#ifdef OSS_BUFFRAG
	/*   Buffer fragmentings (this is Linux specific). It was
	 *   was introduced so that games could play sound at
	 *   better timings.
	 */
	Boolean	allow_fragments;

	u_int8_t num_fragments;
	u_int8_t fragment_size;	/* OS Native units, not bytes. */
#endif	/* OSS_BUFFRAG */


	/*   If the device has stereo support and sample_size is set
	 *   to 16, then if this value is True, the stereo will be
	 *   flipped when mixing is done (by the program).
	 *   This is to fix certain problems with some sound cards
	 *   (such as the SB AWE 64) that flip the stereo so we need
	 *   to flip it back.
	 */
	Boolean flip_stereo;


	/*   Record or play mode.  One of AUDIO_DIRECTION_*
	 */
	int direction;

	/* Record of the last audio mode name used to set this
	 * audio (can be NULL for none).
	 */
	char *audio_mode_name;

	/* Descriptor to opened audio device (-1 for not opened). */
	int fd;

	/* Descriptor to opened mixer device (-1 for not opened). */
	int mixer_fd;

	/* See yiff_option_struct option structure for the last values of
	 * the above mixer.
	 */

	/* Name of the Sound device. */
	char *sound_name;

	/* Marks if the Audio is currently shelled out if True. */
	Boolean shelled_out;

	/* MIDI IO wrapper settings and resources, see midiiow.h. */
	MIDIAudio midi_audio;

	/* Audio CD wrapper context, see audiocd.h. */
	AudioCDContext *audiocd_context;

} Audio;


/*
 *	Main structure that contains pointers to one of each
 *	sound device related structures.  This is commonly passed
 *	to the Sound*() functions.
 */
typedef struct {

	/* Characteristics of the sound device. */
	Audio audio;

	/* Sound device's buffer(s). */
	Sound sound;

} Recorder;


/*
 *	Functions:
 */
extern int YSoundInit(Recorder *recorder, Audio *audio);
extern int YSoundShellOut(Recorder *recorder);
extern void YSoundCaliberateCycle(Recorder *recorder);
extern int YSoundPlayBuffer(Recorder *recorder);
extern void YSoundSync(
	Recorder *recorder,
	int options
);
extern void YSoundShutdown(Recorder *recorder);


#endif  /* YSOUND_H */
