/// <summary>
        ///		Initializes a new sound instance, and loads its sample from the given
        ///		file path (and or memory url).
        /// </summary>
        /// <param name="path">File path or memory url to sound to load.</param>
        /// <param name="flags">Describes how this sound should be loaded and played.</param>
        public Sound(object path, SoundFlags flags)
        {
            // Save details.
            _flags = flags;
            _url = path as string;

            // Load the audio sample then.
            _sample = SampleFactory.LoadSample(path, (flags & SoundFlags.Streamed) != 0);

            // Load one buffer for quick response.
            ISampleBuffer buffer = AudioManager.Driver.CreateSampleBuffer(_sample, flags);
            _frequency = buffer.Frequency;
            _buffers.Add(buffer);

            // If its not dynamic then destroy the samples data as its just cluttering up space.
            if ((_flags & SoundFlags.Dynamic) == 0)
            {
                if (_sample != null)
                {
                    _sampleLength = _sample.Data.Length;
                    _sample.Data = null;
                }
                //GC.Collect();
                _globalBuffer = buffer; // Save the global buffer as its what we will get our data from.
            }
        }
        /// <summary>
        ///     This method is called when Sample load is requested, if you return a Sample
        ///     it will return it from the user else it will keep trying all the other SampleLoaders
        ///     until it does get one
        /// </summary>
        /// <param name="path">File path of the sound to load.</param>
        /// <param name="streamed">If set to true the sound will be loaded in piece by piece rather than all at once.</param>
        /// <returns>New Sample instance or NULL if this factory can't load the given audio sample file format.</returns>
        protected override Sample RequestLoad(object path, bool streamed)
        {
            // Load in the audio file's data.
            Stream stream = StreamFactory.RequestStream(path, StreamMode.Open);
            if (stream == null) return null;
            if (stream.ReadByte() != 'O' || stream.ReadByte() != 'g' || stream.ReadByte() != 'g' || stream.ReadByte() != 'S')
            {
                stream.Close();
                return null;
            }
            stream.Position = 0;

            byte[] data = new byte[stream.Length];
            stream.Read(data, 0, (int)stream.Length);
            stream.Close();

            // Create an audiere memory file to place our data into.
            ManagedAudiere.File file = Audiere.CreateMemoryFile(new MemoryFileBuffer(data, data.Length));
            SampleSource audiereSample = Audiere.OpenSampleSource(file);
            SampleFormatData sampleFormat = audiereSample.GetFormat();

            int size = audiereSample.Length * (Audiere.GetSampleSize(sampleFormat.sample_format) * sampleFormat.channel_count);
            MemoryFileBuffer audiereBuffer = new MemoryFileBuffer(new byte[size], size);
            audiereSample.Read(audiereSample.Length, audiereBuffer);

            // Put the audiere audio buffer into a new sample buffer.
            byte[] pcmBuffer = audiereBuffer.GetBuffer();
            Sample sample = null;

            if (sampleFormat.channel_count == 1)
                sample = new Sample(SampleFormat.MONO16LE, pcmBuffer.Length);
            else
                sample = new Sample(SampleFormat.STEREO16LE, pcmBuffer.Length);

            sample.SampleRate = sampleFormat.sample_rate;
            sample.ChannelCount = sampleFormat.channel_count;
            sample.BlockAlign = Audiere.GetSampleSize(sampleFormat.sample_format) * sampleFormat.channel_count;
            sample.ByteRate = sample.SampleRate * sample.BlockAlign;
            sample.BitsPerSample = Audiere.GetSampleSize(sampleFormat.sample_format) * 8;

            for (int i = 0; i < pcmBuffer.Length; i++)
                sample.Data[i] = pcmBuffer[i];

            return sample;
        }
        /// <summary>
        ///		Loads a chunk of data from a samples stream.
        /// </summary>
        /// <param name="sample">Sample that streamed data needs to be loaded from.</param>
        /// <param name="size">Size in bytes of data that is required.</param>
        /// <param name="position">The variable used for tracking streamed data.</param>
        /// <param name="wrap">Variable indicating if data can be wrapped (used for looping).</param>
        /// <returns>Newly loaded data.</returns>
        public byte[] RequestStreamedData(Sample sample, long size, ref int position, bool wrap)
        {
            if ((sample.DataStream.Position - sample.DataChunkPosition) >= sample.DataChunkLength)
                return new byte[0];

            // Keep reading and wrapping around until we read all the data that we need
            byte[] data = null;
            long readPosition = sample.DataChunkPosition + position;
            sample.DataStream.Position = readPosition;

            if (wrap == true)
            {
                data = new byte[size];
                long dataPosition = 0;
                while (true)
                {
                    // Read in what is left.
                    long sizeLeft = sample.DataChunkLength - (sample.DataStream.Position - sample.DataChunkPosition);
                    long possibleSize = ((data.Length - dataPosition) >= sizeLeft ? sizeLeft : (data.Length - dataPosition));
                    sample.DataStream.Read(data, (int)dataPosition, (int)possibleSize);
                    dataPosition += possibleSize;

                    // Wrap around to the beginning if neccessary.
                    if (dataPosition >= data.Length)
                        break;
                    else
                        sample.DataStream.Position = sample.DataChunkPosition;
                }
            }
            else
            {
                long sizeLeft = sample.DataChunkLength - (sample.DataStream.Position - sample.DataChunkPosition);
                data = new byte[size > sizeLeft ? sizeLeft : size];
                sample.DataStream.Read(data, 0, data.Length);
            }

            position = (int)(sample.DataStream.Position - sample.DataChunkPosition);

            return data;
        }
        /// <summary>
        ///     This method is called when Sample save is requested, if it returns true
        ///		the calling method will stop illiterating through the SampleFactorys and 
        ///		return success to the user.
        /// </summary>
        /// <param name="path">File path or object of the image to load.</param>
        /// <param name="sample">Sample to save.</param>
        /// <param name="flags">Bitmask of flags defining how the sample should be saved.</param>
        /// <returns>True if the save was successfull else false.</returns>
        protected override bool RequestSave(object path, Sample sample, SampleSaveFlags flags)
        {
            if (path.ToString().ToLower().EndsWith(".ogg") == false) return false;

            throw new Exception("OGG save factory currently unfinished and as such unsupported.");
        }
        /// <summary>
        ///     This method is called when Sample load is requested, if you return a Sample
        ///     it will return it from the user else it will keep trying all the other SampleLoaders
        ///     until it does get one
        /// </summary>
        /// <param name="path">File path of the sound to load.</param>
        /// <param name="streamed">If set to true the sound will be loaded in piece by piece rather than all at once.</param>
        /// <returns>New Sample instance or NULL if this factory can't load the given audio sample file format.</returns>
        protected override Sample RequestLoad(object path, bool streamed)
        {
            if (path.ToString().ToLower().EndsWith(".wav") == false &&
                path.ToString().ToLower().EndsWith(".wave") == false) return null;

            Stream stream = StreamFactory.RequestStream(path, StreamMode.Open);
            if (stream == null) return null;
            BinaryReader reader = new BinaryReader(stream);

            //Check the header is correct.
            if (reader.ReadByte() == 'R' && reader.ReadByte() == 'I' &&
                reader.ReadByte() == 'F' && reader.ReadByte() == 'F')
            {
                // Read the header of the RIFF chunk
                reader.ReadBytes(4); // Chunk length
                reader.ReadBytes(4); // WAVE identifier.

                // Local variabl's used to load chunks.
                int audioFormat, channelCount;
                int sampleRate,  byteRate;
                int blockAlign,  bitsPerSample;
                int chunkIndex = 0;
                bool foundFormatChunk = false;
                bool foundDataChunk = false;
                long dataChunkPosition = 0;
                long dataChunkLength = 0;
                Sample sample  = null;

                // Read in every chunk till we find the end of file chunk or
                // we read past the end of the stream.
                while (true)
                {
                    // Check we are not at the end of the stream.
                    if (stream.Position >= stream.Length) break;

                    // Read in chunk's data
                    byte[] chunkTypeChars = reader.ReadBytes(4);
                    int chunkLength       = reader.ReadInt32();
                    string chunkType	  = ((char)chunkTypeChars[0]).ToString() + ((char)chunkTypeChars[1]).ToString() +
                                            ((char)chunkTypeChars[2]).ToString() + ((char)chunkTypeChars[3]).ToString();
                    long originalPosition = stream.Position;

                    switch (chunkType)
                    {
                        // Format chunk.
                        case "fmt ":

                            // Check that the format chunk is first.
                            if (chunkIndex != 0) throw new Exception("Found out of sequence format chunk while reading wav file.");

                            // Check we haven't found multiple occurances.
                            if (foundFormatChunk == true) throw new Exception("Found multiple format chunks while reading wav file, only singular chunks are valid.");
                            foundFormatChunk = false;

                            // Read in the format specifications.
                            audioFormat   = reader.ReadInt16();
                            channelCount  = reader.ReadInt16();
                            sampleRate    = reader.ReadInt32();
                            byteRate	  = reader.ReadInt32();
                            blockAlign	  = reader.ReadInt16();
                            bitsPerSample = reader.ReadInt16();

                            // Make sure audio format is PCM as other mode
                            // are more or less obselete and unsupported by this loader.
                            if (audioFormat != 1) throw new Exception("Encountered unsupported audio format while reading wav file.");

                            // Check for extra parameter if format is PCM.
                            if (stream.Position - originalPosition < chunkLength)
                            {
                                int extraParamSize = reader.ReadInt16();
                                // Lets just skip the extra parameters for
                                // now as we don't need them.
                                stream.Position += extraParamSize;
                            }

                            // Create the audio sample to write data to, based
                            // on the number of channels and amount of bits used
                            // to store the audio sample.
                            if (bitsPerSample == 8 && channelCount == 1)
                                    sample = new Sample(SampleFormat.MONO8,0);
                            if (bitsPerSample == 16 && channelCount == 1)
                                    sample = new Sample(SampleFormat.MONO16LE,0);
                            if (bitsPerSample == 8  && channelCount == 2)
                                    sample = new Sample(SampleFormat.STEREO8,0);
                            if (bitsPerSample == 16 && channelCount == 2)
                                    sample = new Sample(SampleFormat.STEREO16LE,0);

                            // Write the format description into the sample.
                            sample.BitsPerSample = bitsPerSample;
                            sample.ChannelCount  = channelCount;
                            sample.SampleRate    = sampleRate;
                            sample.ByteRate		 = byteRate;
                            sample.BlockAlign	 = blockAlign;

                            break;

                        // Audio data chunk.
                        case "data":

                            // Check we haven't found multiple occurances.
                            if (foundDataChunk == true) throw new Exception("Found multiple data chunks while reading wav file, only singular chunks are valid.");
                            foundDataChunk = false;

                            // Read all the audio data into the sample.
                            dataChunkPosition = stream.Position;
                            dataChunkLength = chunkLength;
                            if (streamed == false)
                                sample.Data = reader.ReadBytes(chunkLength);
                            else
                                stream.Position += chunkLength;

                            break;

                        default:

                            // Probably a good idea to throw up an error
                            // here but for the moment lets just skip it :).
                            stream.Position += chunkLength;

                            break;
                    }

                    chunkIndex++;
                }

                // If its a streamed sound then link it up the the stream loader.
                if (streamed == true)
                {
                    sample.Streamed = true;
                    sample.DataStream = stream;
                    sample.DataChunkPosition = dataChunkPosition;
                    sample.DataChunkLength = dataChunkLength;
                    sample.StreamedDataRequired += RequestStreamedData;
                }
                else
                    stream.Close();

                return sample;
            }
            else // Header check
            {
                reader.Close();
                return null;
            }
        }
 /// <summary>
 ///		Creates and returns a new sample buffer compatible with the current
 ///		audio driver filled with the audio contents of the given sample.
 /// </summary>
 /// <param name="sample">The sample that should be used to create the sound buffer from.</param>
 /// <param name="flags">Describes how this sample buffer should act.</param>
 /// <returns>A newly created ISampleBuffer instance.</returns>
 public static ISampleBuffer CreateSampleBuffer(Sample sample, SoundFlags flags)
 {
     return _driver.CreateSampleBuffer(sample, flags);
 }
 /// <summary>
 ///     This method is called when Sample save is requested, if it returns true
 ///		the calling method will stop illiterating through the SampleFactorys and 
 ///		return success to the user.
 /// </summary>
 /// <param name="path">File path or object of the image to load.</param>
 /// <param name="sample">Sample to save.</param>
 /// <param name="flags">Bitmask of flags defining how the sample should be saved.</param>
 /// <returns>True if the save was successfull else false.</returns>
 protected abstract bool RequestSave(object path, Sample sample, SampleSaveFlags flags);
 public static void SaveSample(object path, Sample sample)
 {
     SaveSample(path, sample, 0);
 }
 /// <summary>
 ///     This method is called when a Sample save is requested, it illiterates through all
 ///     the registered SampleFactory instances to see if there is one capable of saving the
 ///     given format.
 /// </summary>
 /// <param name="sample">Sample to be saved.</param>
 /// <param name="path">File path or save sample to.</param>
 /// <param name="flags">Bitmask of flags to define how the sample should be saved.</param>
 /// <returns>True if save was successfull else false.</returns>
 public static bool SaveSample(object path, Sample sample, SampleSaveFlags flags)
 {
     foreach (SampleFactory factory in _loaderList)
     {
         if (factory.RequestSave(path, sample, flags) == true) return true;
     }
     return false;
 }
        /// <summary>
        ///     This method is called when a sample load is requested, it illiterates through all
        ///     the registered SampleFactory instances to see if there is one capable to loading the
        ///     given format.
        /// </summary>
        /// <param name="path">File path or object of the sound to load.</param>
        /// <param name="streamed">If set to true the sound will be loaded in piece by piece rather than all at once.</param>
        /// <returns>A Sample or NULL if it can't find a factory able to load the given audio sample format.</returns>
        public static Sample LoadSample(object path, bool streamed)
        {
            string fullPath = path.ToString();
            if (fullPath.ToString().ToLower().StartsWith(Environment.CurrentDirectory.ToLower()) == false)
                fullPath = Environment.CurrentDirectory + "\\" + fullPath;

            Sample sample;
            foreach (SampleFactory factory in _loaderList)
            {
                sample = factory.RequestLoad(path, streamed);
                if (sample != null)
                {
                    sample.URL = fullPath;
                    return sample;
                }
            }

            // Can't load it natively? Use MCI.
            sample = new Sample(SampleFormat.STEREO16BE, 0);
            sample.URL = fullPath;
            sample.PlayedUsingMCI = true;

            return sample;
        }