#ifndef __PGALIB_H__
#define __PGALIB_H__

#include <inttypes.h>

#if __cplusplus
extern "C" {
#endif

#include <PGLib/PGATypes.h>

// API for Portable Game Audio
//
// The most direct audio object is the PGA_Streamer.  You create the 
// PGA_Streamer object (using PGA_StreamerCreate), set the callback
// function (using PGA_StreamerSetCallback), and start the object
// streaming.  (using PGA_StreamerStart)  You can stop/start the same 
// streamer as often as you like. (stop it with PGA_StreamerStop)  When
// you are done with a streamer, you can delete it with 'PGA_StreamerDelete'.
//
PGA_Streamer PGA_StreamerCreate(int32_t fps,int32_t spf,int32_t bps,int32_t frame_count);
int32_t PGA_StreamerDelete(PGA_Streamer);
int32_t PGA_StreamerSetCallback(PGA_Streamer,PGA_StreamerCallback,void *obj);
int32_t PGA_StreamerStart(PGA_Streamer);
int32_t PGA_StreamerStop(PGA_Streamer);

//
// Quite often, your audio application will want to deal with playing
// individual sounds.  To make this easier for you, we have a mixer
// object that will do multiple sound mixing for you, sending the output 
// through a newly created PGA_Streamer. (Created using the PGA_MixerCreate
// function call.)  You can create multiple PGA_Mixers, but that defeats 
// the purpose of a mixer.  The last PGA_Mixer created is assigned to the 
// global variable, gMixer.  If you specify NULL for the PGA_Mixer variable 
// in any function, the gMixer will be used. (And created if neccessary,
// using a 44.1khz, 16 bit stereo stream.) You should delete any PGA_Mixer's 
// you create when you're done with them. (using PGA_MixerDelete.)

extern PGA_Mixer gMixer;
PGA_Mixer PGA_MixerCreate(int32_t fps,int32_t spf,int32_t bps,int32_t frame_count);
int32_t PGA_MixerDelete(PGA_Mixer);

// 
// You'll also want function to start/stop the mixer. (IE when you pause
// the game.)  You can use PGA_MixerStart and PGA_MixerStop for this:
// While PGA_MixerDelete will automatically call PGA_MixerStop, its cleaner
// if you stop the mixer yourself before deleting it.
// You can also set the mixers base volume with the PGA_MixerSetVolume
// function, and query the current base volume with the PGA_MixerVolume
// function.
//

int32_t PGA_MixerStart(PGA_Mixer);
int32_t PGA_MixerStop(PGA_Mixer);
int32_t PGA_MixerSetVolume(PGA_Mixer,int32_t vol);
int32_t PGA_MixerVolume(PGA_Mixer);

// 
// Sound Sample Functions:
//
// Very often, all you'll want to do in your application is play simple sounds
// at random times.  If these are one-shot sounds (you won't be playing the 
// same sound over and over), you can play the sound using the 
// PGA_SoundPlayOneShot function.  This function call is asynchronous, so 
// you'll have control back while the sound is still playing. (And you can
// free the data immediately.  A copy is used for the mixer.)  You don't have
// to worry about freeing up any other memory when the sound has finished
// playing. The function also does any data conversion from your format to that
// of the mixer.
//
PGA_SoundID PGA_SoundPlayOneShot(PGA_Mixer,void *data,int32_t bytes,int32_t fps,int32_t spf,int32_t bps,float vol,float pan,float dir,int32_t loop);

// 
// You may also have a sound (or sounds) that you play often. (Perhaps the
// sound of a cannon being fired.)  Rather then repeatedly calling the
// PGA_SoundPlayOneShot function over and over (and having the data converted
// to the proper format over and over) you can create a PGA_Sound object from
// your data using PGA_SoundCreate function, and play it over and over (even
// more than one at a time) without a problem using the PGA_SoundPlay function.
// When you are finished with a PGA_Sound object, you can free it with the 
// PGA_SoundDelete function call. Since the PGA_Sound is in a given PGA_Mixer's
// format, you don't have to specify a PGA_Mixer for any PGA_Sound* function 
// calls.
//
// In order to do the fastest mixing possible, samples are precalculated when
// possible.  The more we know about the sounds conditions when we're going
// to play it, the more we can precalculate.  (Ie Sound pitch, pan, 
// front/back direction, etc.) If any of these values are 'soft' (will change
// later), set the appropriate PGA_*_SOFT flags. (Fill in the appropriate
// parameters with the hard values if you have any.)  You will almost always 
// want to leave the sample rate hard.  The values specified in PGA_SoundPlay
// are only used if you specified a SOFT flag for that value when the sound
// was created.
//
PGA_Sound PGA_SoundCreate(PGA_Mixer m,void *data,int32_t size,int32_t fps,int32_t spf,int32_t bps);
int32_t PGA_SoundDelete(PGA_Sound);
PGA_SoundID PGA_SoundPlay(PGA_Sound,float vol,float pan,float dir,int32_t loop);

// You might also have a WAV file you'd like to read in to play... You can use
// PGA_SoundLoadWAVFile to do this. (You must PGA_SoundDelete it when you're
// done as well.)  The WAV file is automatically converted to the format the
// mixer is in.
// 
PGA_Sound PGA_SoundLoadWAVFile(PGA_Mixer,char *filename);
//
// You might want to stop a sound (one-shot or normal) before its finished
// playing.  Simply call the PGA_SoundStop() function with the PGA_SoundID
// value returned by the PGA_SoundCreate* function, and the sound will be
// stopped. You can find out if a sound is still playing with the
// PGA_SoundIsPlaying function call. (returns 0 if not playing)
//

int32_t PGA_SoundStopInstance(PGA_Mixer,PGA_SoundID);
int32_t PGA_SoundStop(PGA_Sound);
int32_t PGA_SoundIsPlaying(PGA_Mixer,PGA_SoundID);
int32_t PGA_SoundUpdate(PGA_Mixer,PGA_SoundID,float vol,float pan,float dir);

//
// If you'd like to change paramaters of a sound that's already playing,
// you can use the PGA_SoundSetVolume and PGA_SoundSetPan functions. (And
// query it using the corresponding PGA_SoundGet* functions.) Of course,
// you would have had to set the appropriate PGA_*_SOFT flags, or these
// calls will be ignored.
//

int32_t PGA_SoundSetVolume(PGA_Mixer,PGA_SoundID,float vol);
float PGA_SoundGetVolume(PGA_Mixer,PGA_SoundID);
int32_t PGA_SoundSetPan(PGA_Mixer,PGA_SoundID,float pan);
float PGA_SoundGetPan(PGA_Mixer,PGA_SoundID);
int32_t PGA_SoundSetDir(PGA_Mixer,PGA_SoundID,float dir);
float PGA_SoundGetDir(PGA_Mixer,PGA_SoundID);

//
// Alternative Streaming Method:
//
// In some cases, having a callback isn't good enough.  Another approach with
// the same overhead (memory usage, processing time) would be to use a 'Push'
// streamer, which uses the 'acquire buffer/fill buffer/release buffer' 
// sequence. You can create a Push streamer with the PGA_PusherCreate function.
// Then, when you wish to push out some audio, simply call PGA_PusherAcquire
// to acquire the buffer, then fill the buffer with whatever values you want,
// and then call PGA_PusherRelease to release the buffer to the mixer.
//
PGA_Pusher PGA_PusherCreate(int32_t fps,int32_t spf,int32_t bps,int32_t frame_count);
int32_t PGA_PusherAcquire(PGA_Pusher,void **data);
int32_t PGA_PusherRelease(PGA_Pusher,void *data);

//
// One problem with the Acquire/Release functions is that you have to fill
// in the entire buffer before you release.  If you only have a partial buffer,
// this could be a problem, since you may only have the rest of the buffer
// later, and you need to keep processing other data meanwhile.  The solution
// is to push the raw data, instead of acquire/fill/releasing it.  This means
// that your raw data must be in the same format as the streamer was set up
// as.  It is also not as efficient as the acquire/fill/release method if your
// original data has to be converted to the output format, since you'll need
// an extra intermediate buffer.
// 
int32_t PGA_PusherPush(PGA_Pusher,void *data,int32_t s_count);

#if __cplusplus
};
#endif

#endif
