SynGame/allegro/include/allegro5/internal/aintern_audio.h

328 lines
12 KiB
C

/* internal-only header
* Updated for 4.9 api inclusion by Ryan Dickie
* Originally done by KC/Milan
*/
#ifndef AINTERN_AUDIO_H
#define AINTERN_AUDIO_H
#include "allegro5/allegro.h"
#include "allegro5/internal/aintern_vector.h"
#include "../allegro_audio.h"
typedef enum ALLEGRO_AUDIO_DRIVER_ENUM
{
/* Various driver modes. */
ALLEGRO_AUDIO_DRIVER_AUTODETECT = 0x20000,
ALLEGRO_AUDIO_DRIVER_OPENAL = 0x20001,
ALLEGRO_AUDIO_DRIVER_ALSA = 0x20002,
ALLEGRO_AUDIO_DRIVER_DSOUND = 0x20003,
ALLEGRO_AUDIO_DRIVER_OSS = 0x20004,
ALLEGRO_AUDIO_DRIVER_AQUEUE = 0x20005,
ALLEGRO_AUDIO_DRIVER_PULSEAUDIO = 0x20006
} ALLEGRO_AUDIO_DRIVER_ENUM;
typedef struct ALLEGRO_AUDIO_DRIVER ALLEGRO_AUDIO_DRIVER;
struct ALLEGRO_AUDIO_DRIVER {
const char *specifier;
int (*open)(void);
void (*close)(void);
int (*allocate_voice)(ALLEGRO_VOICE*);
void (*deallocate_voice)(ALLEGRO_VOICE*);
int (*load_voice)(ALLEGRO_VOICE*, const void*);
void (*unload_voice)(ALLEGRO_VOICE*);
int (*start_voice)(ALLEGRO_VOICE*);
int (*stop_voice)(ALLEGRO_VOICE*);
bool (*voice_is_playing)(const ALLEGRO_VOICE*);
unsigned int (*get_voice_position)(const ALLEGRO_VOICE*);
int (*set_voice_position)(ALLEGRO_VOICE*, unsigned int);
};
extern ALLEGRO_AUDIO_DRIVER *_al_kcm_driver;
const void *_al_voice_update(ALLEGRO_VOICE *voice, unsigned int *samples);
bool _al_kcm_set_voice_playing(ALLEGRO_VOICE *voice, bool val);
/* A voice structure that you'd attach a mixer or sample to. Ideally there
* would be one ALLEGRO_VOICE per system/hardware voice.
*/
struct ALLEGRO_VOICE {
ALLEGRO_AUDIO_DEPTH depth;
ALLEGRO_CHANNEL_CONF chan_conf;
unsigned int frequency;
size_t buffer_size;
size_t num_buffers;
/* If non-0, they must be honored by the driver. */
ALLEGRO_SAMPLE_INSTANCE *attached_stream;
/* The stream that is attached to the voice, or NULL.
* May be an ALLEGRO_SAMPLE_INSTANCE or ALLEGRO_MIXER object.
*/
bool is_streaming;
/* True for voices with an attached mixer. */
ALLEGRO_MUTEX *mutex;
ALLEGRO_COND *cond;
ALLEGRO_AUDIO_DRIVER *driver;
/* XXX shouldn't there only be one audio driver active
* at a time?
*/
void *extra;
/* Extra data for use by the driver. */
};
typedef union {
float *f32;
uint32_t *u24;
int32_t *s24;
uint16_t *u16;
int16_t *s16;
uint8_t *u8;
int8_t *s8;
void *ptr;
} any_buffer_t;
struct ALLEGRO_SAMPLE {
ALLEGRO_AUDIO_DEPTH depth;
ALLEGRO_CHANNEL_CONF chan_conf;
unsigned int frequency;
int len;
any_buffer_t buffer;
bool free_buf;
/* Whether `buffer' needs to be freed when the sample
* is destroyed, or when `buffer' changes.
*/
};
/* Read some samples into a mixer buffer.
*
* source:
* The object to read samples from. This may be one of several types.
*
* *vbuf: (in-out parameter)
* Pointer to pointer to destination buffer.
* (should confirm what it means to change the pointer on return)
*
* *samples: (in-out parameter)
* On input indicates the maximum number of samples that can fit into *vbuf.
* On output indicates the actual number of samples that were read.
*
* buffer_depth:
* The audio depth of the destination buffer.
*
* dest_maxc:
* The number of channels in the destination.
*/
typedef void (*stream_reader_t)(void *source, void **vbuf,
unsigned int *samples, ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc);
typedef struct {
union {
ALLEGRO_MIXER *mixer;
ALLEGRO_VOICE *voice;
void *ptr;
} u;
bool is_voice;
} sample_parent_t;
/* The sample struct also serves the base of ALLEGRO_AUDIO_STREAM, ALLEGRO_MIXER. */
struct ALLEGRO_SAMPLE_INSTANCE {
/* ALLEGRO_SAMPLE_INSTANCE does not generate any events yet but ALLEGRO_AUDIO_STREAM
* does, which can inherit only ALLEGRO_SAMPLE_INSTANCE. */
ALLEGRO_EVENT_SOURCE es;
ALLEGRO_SAMPLE spl_data;
volatile bool is_playing;
/* Is this sample is playing? */
ALLEGRO_PLAYMODE loop;
float speed;
float gain;
float pan;
/* When resampling an audio stream there will be fractional sample
* positions due to the difference in frequencies.
*/
int pos;
int pos_bresenham_error;
int loop_start;
int loop_end;
int step;
int step_denom;
/* The numerator and denominator of the step are
* stored separately. The actual step is obtained by
* dividing step by step_denom */
float *matrix;
/* Used to convert from this format to the attached
* mixers, if any. Otherwise is NULL.
* The gain is premultiplied in.
*/
bool is_mixer;
stream_reader_t spl_read;
/* Reads sample data into the provided buffer, using
* the specified format, converting as necessary.
*/
ALLEGRO_MUTEX *mutex;
/* Points to the parent object's mutex. It is NULL if
* the sample is not directly or indirectly attached
* to a voice.
*/
sample_parent_t parent;
/* The object that this sample is attached to, if any.
*/
};
void _al_kcm_destroy_sample(ALLEGRO_SAMPLE_INSTANCE *sample, bool unregister);
void _al_kcm_stream_set_mutex(ALLEGRO_SAMPLE_INSTANCE *stream, ALLEGRO_MUTEX *mutex);
void _al_kcm_detach_from_parent(ALLEGRO_SAMPLE_INSTANCE *spl);
typedef size_t (*stream_callback_t)(ALLEGRO_AUDIO_STREAM *, void *, size_t);
typedef void (*unload_feeder_t)(ALLEGRO_AUDIO_STREAM *);
typedef bool (*rewind_feeder_t)(ALLEGRO_AUDIO_STREAM *);
typedef bool (*seek_feeder_t)(ALLEGRO_AUDIO_STREAM *, double);
typedef double (*get_feeder_position_t)(ALLEGRO_AUDIO_STREAM *);
typedef double (*get_feeder_length_t)(ALLEGRO_AUDIO_STREAM *);
typedef bool (*set_feeder_loop_t)(ALLEGRO_AUDIO_STREAM *, double, double);
struct ALLEGRO_AUDIO_STREAM {
ALLEGRO_SAMPLE_INSTANCE spl;
/* ALLEGRO_AUDIO_STREAM is derived from
* ALLEGRO_SAMPLE_INSTANCE.
*/
unsigned int buf_count;
/* The stream buffer is divided into a number of
* fragments; this is the number of fragments.
*/
void *main_buffer;
/* Pointer to a single buffer big enough to hold all
* the fragments. Each fragment has additional samples
* at the start for linear/cubic interpolation.
*/
void **pending_bufs;
void **used_bufs;
/* Arrays of offsets into the main_buffer.
* The arrays are each 'buf_count' long.
*
* 'pending_bufs' holds pointers to fragments supplied
* by the user which are yet to be handed off to the
* audio driver.
*
* 'used_bufs' holds pointers to fragments which
* have been sent to the audio driver and so are
* ready to receive new data.
*/
volatile bool is_draining;
/* Set to true if sample data is not going to be passed
* to the stream any more. The stream must change its
* playing state to false after all buffers have been
* played.
*/
ALLEGRO_THREAD *feed_thread;
volatile bool quit_feed_thread;
unload_feeder_t unload_feeder;
rewind_feeder_t rewind_feeder;
seek_feeder_t seek_feeder;
get_feeder_position_t get_feeder_position;
get_feeder_length_t get_feeder_length;
set_feeder_loop_t set_feeder_loop;
stream_callback_t feeder;
/* If ALLEGRO_AUDIO_STREAM has been created by
* al_load_audio_stream(), the stream will be fed
* by a thread using the 'feeder' callback. Such
* streams don't need to be fed by the user.
*/
void *extra;
/* Extra data for use by the flac/vorbis addons. */
};
bool _al_kcm_refill_stream(ALLEGRO_AUDIO_STREAM *stream);
typedef void (*postprocess_callback_t)(void *buf, unsigned int samples,
void *userdata);
/* ALLEGRO_MIXER is derived from ALLEGRO_SAMPLE_INSTANCE. Certain internal functions and
* pointers may take either object type, and such things are explicitly noted.
* This is never exposed to the user, though. The sample object's read method
* will be set to a different function that will call the read method of all
* attached streams (which may be a sample, or another mixer).
*/
struct ALLEGRO_MIXER {
ALLEGRO_SAMPLE_INSTANCE ss;
/* ALLEGRO_MIXER is derived from ALLEGRO_SAMPLE_INSTANCE. */
ALLEGRO_MIXER_QUALITY quality;
postprocess_callback_t postprocess_callback;
void *pp_callback_userdata;
_AL_VECTOR streams;
/* Vector of ALLEGRO_SAMPLE_INSTANCE*. Holds the list of
* streams being mixed together.
*/
};
extern void _al_kcm_mixer_rejig_sample_matrix(ALLEGRO_MIXER *mixer,
ALLEGRO_SAMPLE_INSTANCE *spl);
extern void _al_kcm_mixer_read(void *source, void **buf, unsigned int *samples,
ALLEGRO_AUDIO_DEPTH buffer_depth, size_t dest_maxc);
typedef enum {
ALLEGRO_NO_ERROR = 0,
ALLEGRO_INVALID_PARAM = 1,
ALLEGRO_INVALID_OBJECT = 2,
ALLEGRO_GENERIC_ERROR = 255
} AL_ERROR_ENUM;
extern void _al_set_error(int error, char* string);
/* Supposedly internal */
ALLEGRO_KCM_AUDIO_FUNC(int, _al_kcm_get_silence, (ALLEGRO_AUDIO_DEPTH depth));
ALLEGRO_KCM_AUDIO_FUNC(void*, _al_kcm_feed_stream, (ALLEGRO_THREAD *self, void *vstream));
/* Helper to emit an event that the stream has got a buffer ready to be refilled. */
void _al_kcm_emit_stream_events(ALLEGRO_AUDIO_STREAM *stream);
void _al_kcm_init_destructors(void);
void _al_kcm_shutdown_destructors(void);
void _al_kcm_register_destructor(void *object, void (*func)(void*));
void _al_kcm_unregister_destructor(void *object);
void _al_kcm_foreach_destructor(
void (*callback)(void *object, void (*func)(void *), void *udata),
void *userdata);
ALLEGRO_KCM_AUDIO_FUNC(void, _al_kcm_shutdown_default_mixer, (void));
ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_CHANNEL_CONF, _al_count_to_channel_conf, (int num_channels));
ALLEGRO_KCM_AUDIO_FUNC(ALLEGRO_AUDIO_DEPTH, _al_word_size_to_depth_conf, (int word_size));
#endif
/* vim: set sts=3 sw=3 et: */