/****************************************************************************
       PROGRAM: audioenv.cpp
       DESCRIPTION: audio object class code
    ****************************************************************************/
    #include "audioenv.h"

    // constructor
    AudioEnv::AudioEnv ()
    {
    	nextBuffer = 0;
    	nextSource = 0;
    }

    // destructor
    AudioEnv::~AudioEnv ()
    {

    }

    // init
    void AudioEnv::Init ()
    {
      /* tsao:
         alutInit, or alcCreateContext, is required to initialize the
         OpenAL library.  As the alut functions are not well specified at
         the moment, it is probably better form to use the following
         initialization technique:

             void *context_id = alcCreateContext(NULL);

	     if(context_id == NULL) {
                     return;
	     }

	     alcMakeContextCurrent(context_id);

         As you can see, alutInit provides no provision for reporting a
         failed initialization, and for this reason alone it's not as
         robust as the technique described above.
       */
    #ifdef ALFUNCTIONS
       alutInit (NULL, 0); // init OpenAL
    #endif
    }

    // init
    void AudioEnv::ListenerPosition (ALfloat* position, ALfloat* angle)
    {
      /* tsao:
         alListenerfv is used to set those Listener attributes which take
         a float vector form.  These include position, orientation, and
         velocity.
         The Listener in OpenAL is the person who hears things.  By
         changing the Listener's position and orientation, the application
         essentially places the user in the scene created by the other
         calls.
       */
    	alListenerfv(AL_POSITION, position);
    	alListenerfv(AL_ORIENTATION, angle);
    }

    // LoadFile
    int AudioEnv::LoadFile (char *filename, bool loop)
    {
       int i;

       /* tsao:
          XLDEMO creates Sources and Buffers as needed, with a one-to-one
          mapping, for each sample desired. This isn't necessary, as one
          can have many Sources referring to the same Buffer.

          The application must associate a sound file with a Buffer and
          associate a Buffer with a Source before the sound file can be
          played. The usual course of events goes something like this:

              alGenSources(1, &sid);
       	      alGenBuffers(1, &bid);

	      ...load PCM data ...
	      alBufferData(bid, format, data, size, freq);

	      alSourcei(sid, AL_BUFFER, bid);

         The call alBufferData is needed to associate a chunk of PCM data
         with a Buffer ID. The format parameter is one of
         AL_FORMAT_MONO8, AL_FORMAT_MONO16, AL_FORMAT_STEREO8, or
         AL_FORMAT_STEREO16, although implementations are free to add
         additional formats as extensions for things like compressed audio
         formats.

         size corresponds to the length of the data in bytes, and freq
         corresponds to the sampling rate of the data.

         The proposed 1.0 spec specifies that functions that cannot completely 
         fulfill a requested allocation/deallocation request fail, setting
         an error, and not perform partial allocation. The Linux
         implementation follows this guideline which is why there is no
         return from alGenSources or alGenBuffers, and instead alGetError
         is checked.

         Buffers are not played, Sources are, although they get their
         sound data from Buffers. Attributes such as position, pitch,
         gain, etc are set for Sources, not Buffers.
        */

       // tsao: Linux OpenAL follows spec in that alGenBuffers
       //       and alGenSources don't return.
       // create Buffer
       alGetError(); /* clear */
       alGenBuffers(1, &buffer[nextBuffer]);
       if(alGetError() != AL_NO_ERROR) {
    	   return 0;
       }

       // create Source
       alGetError(); /* clear */
       alGenSources(1, &source[nextSource]);
       if(alGetError() != AL_NO_ERROR) {
	   return 0;
       }

       /* tsao:
          The alut functions, being unspecified, are different between the
          implementations at the moment. This is why we need seperate
          defines for this section.

          alut functions are meant to be utility functions not reliant on
          the main library proper. Here, alutLoadWAV is used to open a
          wave file and extract (or convert to) a chunk of PCM data,
          setting format, data, size, and frequency for use in a call to
          alBufferData. The bits field, while present in the Linux
          implementation of the call, is unused.
       */

   // load data into Buffer
    #ifdef LINUX
       ALsizei size, freq, bits;
       ALenum format;
       ALvoid *data;
       ALboolean err;
   
       err = alutLoadWAV(filename, &data, &format, &size, &bits, &freq);
       if(err == AL_FALSE) {
	   fprintf(stderr, "Could not load %s\n", filename);
	   return 0;
       }

       alBufferData (buffer[nextBuffer], format, data, size, freq);
    #endif   

       /* tsao:
          Here is where the Buffer above is associated with the source
          just created.  

          In addition, looping is either turned on or off (default) based
          on a passed parameter. The proposed 1.0 spec has a more
          flexible loop mechanism, based on AL_PLAY_COUNT, which allows
          for repitition counts on a playing Source. A backwards
          compatitibility token is also present for infinite loop counts.
        */
       // setup Source
       alSourcei(source[nextSource], AL_BUFFER, buffer[nextBuffer]);
       alSourcei(source[nextSource], AL_LOOPING, loop);

       nextBuffer++;
       nextSource++;
       return nextBuffer;
    }

    // Playfile
    int AudioEnv::PlayFile (char *filename, bool loop)
    {
	int loadhandle;

	loadhandle = LoadFile(filename, loop);

	if (loadhandle != 0) { 
		Play(loadhandle); 
	} else
	{
		return 0;
	}

	return loadhandle;
    }

    //SetSourcePosition
    void AudioEnv::SetSourcePosition (int handle, float *position)
    {
      /* tsao:
         In order to place sounds in an environment, the Source's position
         must be set.

         alSourcefv is used to set Source attributes with a float vector
         form, such as position, velocity, direction.
       */
    	alSourcefv(source[handle-1], AL_POSITION, position);
    }

    // Play
    void AudioEnv::Play(int handle)
    {
      /* tsao:
         Sources must be played to be heard. alSourcePlay (and
         alSourcePlayv, the vector form) can be used to play Sources.
       */
	alSourcePlay(source[handle-1]); 
    }

    // Stop
    void AudioEnv::Stop(int handle)
    {
      /* tsao:

         Non-looping Sources will stop of their own accord when they reach
         the end of their PCM data, but occasionally the application will
         want to stop a Source prematurely, and alSourceStop (or
         alSourceStopv, the vector form) is the way to do it.

         Because of the introduction of the play count attribute in the
         proposed 1.0 spec, it is possible to have a Source which loops
         for a specified number of iterations and then stops of its own
         accord, although using the backward compatibility token for
         infinite looping will require an explicit stop of the Source if
         the application expects the Source to end at any point.
       */
	alSourceStop(source[handle-1]);
    }