public DataProvider GetSingleWavClipDataProvider()
        {
            if (mWavClips.Count == 1)
            {
                WavClip theChosenOne = mWavClips[0];
                return(theChosenOne.DataProvider);
            }

            return(null);
        }
        //private void checkPcmFormat(Stream stream)
        //{
        //    if (!Presentation.MediaDataManager.EnforceSinglePCMFormat)
        //    {
        //        return;
        //    }

        //    uint dataLength;
        //    AudioLibPCMFormat format = AudioLibPCMFormat.RiffHeaderParse(stream, out dataLength);

        //    //if (dataLength <= 0)
        //    //{
        //    //    dataLength = (uint)(stream.Length - stream.Position);
        //    //}

        //    if (!format.IsCompatibleWith(PCMFormat.Data))
        //    {
        //        throw new exception.InvalidDataFormatException(
        //            String.Format("RIFF WAV file has incompatible PCM format"));
        //    }
        //}

        public override void AppendPcmData(DataProvider fileDataProvider)
        {
            if (fileDataProvider.MimeType != DataProviderFactory.AUDIO_WAV_MIME_TYPE)
            {
                throw new exception.OperationNotValidException(
                          "The mime type of the given DataProvider is not WAV !");
            }

            WavClip newSingleWavClip = new WavClip(fileDataProvider);

            mWavClips.Add(newSingleWavClip);

            checkPcmFormat(newSingleWavClip);

            NotifyAudioDataInserted(this, AudioDuration, newSingleWavClip.MediaDuration);
        }
        public void InsertPcmData(WavAudioMediaData mediaData, Time insertPoint, Time duration)
        {
            Time movingInsertPoint          = insertPoint.Copy();
            Time remainingAvailableDuration = duration.Copy();

            foreach (WavClip wavClip in mediaData.mWavClips)
            {
                Time wavClipDur = wavClip.Duration;

                if (wavClipDur.IsLessThan(remainingAvailableDuration) ||
                    wavClipDur.IsEqualTo(remainingAvailableDuration))
                {
                    InsertPcmData(wavClip.Copy(), movingInsertPoint, wavClipDur);
                    movingInsertPoint.Add(wavClipDur);
                    remainingAvailableDuration.Substract(wavClipDur);

                    if (remainingAvailableDuration.IsLessThan(Time.Zero) ||
                        remainingAvailableDuration.IsEqualTo(Time.Zero))
                    {
                        break;
                    }
                }
                else
                {
                    WavClip smallerClip = wavClip.Copy();
                    smallerClip.ClipEnd = smallerClip.ClipBegin.Copy();
                    smallerClip.ClipEnd.Add(remainingAvailableDuration);

                    InsertPcmData(smallerClip, movingInsertPoint, remainingAvailableDuration);

                    //Stream stream = wavClip.OpenPcmInputStream(Time.Zero,
                    //    new Time(wavClip.ClipBegin.AsTimeSpan + remainingAvailableDuration.AsTimeSpan));
                    //try
                    //{
                    //    InsertPcmData(stream, movingInsertPoint, remainingAvailableDuration);
                    //}
                    //finally
                    //{
                    //    stream.Close();
                    //}
                    break;
                }
            }
        }
        /// <summary>
        /// Forces the PCM data to be stored in a single <see cref="DataProvider"/>.
        /// </summary>
        /// <remarks>
        /// This effectively copies the data,
        /// since the <see cref="DataProvider"/>(s) previously used to store the PCM data are left untouched
        /// </remarks>
        public DataProvider ForceSingleDataProvider(bool reuseSingleWavClip, string fileNamePrefix)
        {
            if (mWavClips.Count == 0)
            {
                return(null);
            }

            if (reuseSingleWavClip && mWavClips.Count == 1)
            {
                WavClip theChosenOne = mWavClips[0];
                if (theChosenOne.ClipBegin.IsEqualTo(Time.Zero) &&
                    theChosenOne.ClipEnd.IsEqualTo(theChosenOne.MediaDuration))
                {
                    if (!String.IsNullOrEmpty(fileNamePrefix))
                    {
                        ((FileDataProvider)theChosenOne.DataProvider).Rename(fileNamePrefix);
                    }
                    return(theChosenOne.DataProvider);
                }
            }

            WavClip newSingleClip;

            DataProvider dataProvider = null;

            Stream audioData = OpenPcmInputStream();

            try
            {
                dataProvider  = CreateDataProviderFromRawPCMStream(audioData, null, fileNamePrefix);
                newSingleClip = new WavClip(dataProvider);
            }
            finally
            {
                audioData.Close();
            }
            mWavClips.Clear();
            mWavClips.Add(newSingleClip);

            return(dataProvider);
        }
        public override void AppendPcmData(DataProvider fileDataProvider, Time clipBegin, Time clipEnd)
        {
            if (fileDataProvider.MimeType != DataProviderFactory.AUDIO_WAV_MIME_TYPE)
            {
                throw new exception.OperationNotValidException(
                          "The mime type of the given DataProvider is not WAV !");
            }

            WavClip newSingleWavClip = new WavClip(fileDataProvider);

            if (clipBegin != null)
            {
                newSingleWavClip.ClipBegin = clipBegin.Copy();
            }
            if (clipEnd != null)
            {
                newSingleWavClip.ClipEnd = clipEnd.Copy();
            }
            mWavClips.Add(newSingleWavClip);

            checkPcmFormat(newSingleWavClip);

            NotifyAudioDataInserted(this, AudioDuration, newSingleWavClip.Duration); //ClipEnd.GetDifference(newSingleWavClip.ClipBegin));
        }
        private void checkPcmFormat(WavClip clip)
        {
            if (!Presentation.MediaDataManager.EnforceSinglePCMFormat)
            {
                return;
            }

            if (!clip.PcmFormat.IsCompatibleWith(PCMFormat.Data))
            {
                throw new exception.InvalidDataFormatException(
                          String.Format("RIFF WAV file has incompatible PCM format"));
            }

            ////Stream stream = newSingleWavClip.OpenPcmInputStream(); // Skips the RIFF header !
            //Stream stream = clip.DataProvider.OpenInputStream();
            //try
            //{
            //    checkPcmFormat(stream);
            //}
            //finally
            //{
            //    stream.Close();
            //}
        }
        /// <summary>
        /// Removes the audio between given clip begin and end points
        /// </summary>
        /// <param name="clipBegin">The given clip begin point</param>
        /// <param name="clipEnd">The given clip end point</param>
        public override void RemovePcmData(Time clipBegin, Time clipEnd)
        {
            if (clipBegin == null || clipEnd == null)
            {
                throw new exception.MethodParameterIsNullException("Clip begin or clip end can not be null");
            }

            //long oneMS = PCMFormat.Data.ConvertTimeToBytes(1);
            //double timeBlockAlign = PCMFormat.Data.ConvertBytesToTime(PCMFormat.Data.BlockAlign);

            if (
                clipBegin.IsLessThan(Time.Zero) ||
                clipBegin.IsGreaterThan(clipEnd) ||
                clipEnd.IsGreaterThan(AudioDuration))
            {
                throw new exception.MethodParameterIsOutOfBoundsException(
                          String.Format("The given clip times are not valid, must be between 00:00:00.000 and {0} ([{1} --> {2})",
                                        AudioDuration, clipBegin, clipEnd));
            }
            Time curBeginTime = Time.Zero;

            List <WavClip> newClipList = new List <WavClip>();

            foreach (WavClip curClip in mWavClips)
            {
                Time curEndTime = new Time(curBeginTime.AsTimeSpanTicks + curClip.Duration.AsTimeSpanTicks, true);
                if ((!curEndTime.IsGreaterThan(clipBegin)) || (!curBeginTime.IsLessThan(clipEnd)))
                {
                    //The current clip is before or beyond the range to remove -
                    //so the clip is added unaltered to the new list of clips
                    newClipList.Add(curClip);
                }
                else if (curBeginTime.IsLessThan(clipBegin) && curEndTime.IsGreaterThan(clipEnd))
                {
                    //Some of the current clip is before the range and some is after
                    Time beforePartDur = curBeginTime.GetDifference(clipBegin);
                    Time beyondPartDur = curEndTime.GetDifference(clipEnd);


                    //Time timePointRelativeToClipBeginOfWavClip = new Time(
                    //    curClip.Duration.AsTimeSpan - beyondPartDur.AsTimeSpan);
                    //Stream beyondAS = curClip.OpenPcmInputStream(timePointRelativeToClipBeginOfWavClip);
                    //WavClip beyondPartClip;
                    //try
                    //{
                    //    beyondPartClip = new WavClip(CreateDataProviderFromRawPCMStream(beyondAS, null));
                    //}
                    //finally
                    //{
                    //    beyondAS.Close();
                    //}

                    WavClip beyondPartClip = curClip.Copy();
                    Time    copyEnd        = beyondPartClip.ClipEnd.Copy();
                    copyEnd.Substract(beyondPartDur);
                    beyondPartClip.ClipBegin = copyEnd;

                    curClip.ClipEnd = new Time(curClip.ClipBegin.AsTimeSpanTicks + beforePartDur.AsTimeSpanTicks, true);

                    newClipList.Add(curClip);
                    newClipList.Add(beyondPartClip);
                }
                else if (curBeginTime.IsLessThan(clipBegin) && curEndTime.IsGreaterThan(clipBegin))
                {
                    //Some of the current clip is before the range to remove, none is beyond
                    Time beforePartDur = curBeginTime.GetDifference(clipBegin);
                    curClip.ClipEnd = new Time(curClip.ClipBegin.AsTimeSpanTicks + beforePartDur.AsTimeSpanTicks, true);
                    newClipList.Add(curClip);
                }
                else if (curBeginTime.IsLessThan(clipEnd) && curEndTime.IsGreaterThan(clipEnd))
                {
                    //Some of the current clip is beyond the range to remove, none is before
                    Time beyondPartDur = curEndTime.GetDifference(clipEnd);
                    curClip.ClipBegin = new Time(curClip.ClipEnd.AsTimeSpanTicks - beyondPartDur.AsTimeSpanTicks, true);
                    newClipList.Add(curClip);
                }

                curBeginTime = curEndTime;
            }
            mWavClips = newClipList;
            NotifyAudioDataRemoved(this, clipBegin, clipEnd.GetDifference(clipBegin));
        }
        /// <summary>
        /// Inserts audio of a given duration from a given source PCM data <see cref="Stream"/> to the wav audio media data
        /// at a given point
        /// </summary>
        /// <param name="pcmData">The source PCM data stream</param>
        /// <param name="insertPoint">The insert point</param>
        /// <param name="duration">The duration of the aduio to append</param>
        public override void InsertPcmData(Stream pcmData, Time insertPoint, Time duration)
        {
            WavClip newInsClip = new WavClip(CreateDataProviderFromRawPCMStream(pcmData, duration));

            InsertPcmData(newInsClip, insertPoint, duration);
        }
        protected void InsertPcmData(WavClip newInsClip, Time insertPoint, Time duration)
        {
            if (insertPoint.IsLessThan(Time.Zero))
            {
                throw new exception.MethodParameterIsOutOfBoundsException(
                          "The given insert point is negative");
            }

            Time endTime = AudioDuration;

            if (insertPoint.IsGreaterThan(endTime))
            {
                throw new exception.MethodParameterIsOutOfBoundsException(
                          "The given insert point is beyond the end of the WavAudioMediaData");
            }


            checkPcmFormat(newInsClip);

            if (insertPoint.IsEqualTo(endTime))
            {
                mWavClips.Add(newInsClip);
                NotifyAudioDataInserted(this, insertPoint, duration);
                return;
            }
            Time elapsedTime = Time.Zero;
            int  clipIndex   = 0;

            while (clipIndex < mWavClips.Count)
            {
                WavClip curClip = mWavClips[clipIndex];
                if (insertPoint.IsEqualTo(elapsedTime))
                {
                    //If the insert point at the beginning of the current clip, insert the new clip and break
                    mWavClips.Insert(clipIndex, newInsClip);
                    break;
                }
                if (insertPoint.IsLessThan(new Time(elapsedTime.AsTimeSpanTicks + curClip.Duration.AsTimeSpanTicks, true)))
                {
                    //If the insert point is between the beginning and end of the current clip,
                    //Replace the current clip with three clips containing
                    //the audio in the current clip before the insert point,
                    //the audio to be inserted and the audio in the current clip after the insert point respectively
                    Time insPtInCurClip = insertPoint.GetDifference(elapsedTime);

                    WavClip curClipBeforeIns = curClip.Copy();
                    curClipBeforeIns.ClipEnd = curClipBeforeIns.ClipBegin.Copy();
                    curClipBeforeIns.ClipEnd.Add(insPtInCurClip);

                    //Stream audioDataStream = curClip.OpenPcmInputStream(Time.Zero, insPtInCurClip);
                    //try
                    //{
                    //    curClipBeforeIns = new WavClip(CreateDataProviderFromRawPCMStream(audioDataStream, null));
                    //}
                    //finally
                    //{
                    //    audioDataStream.Close();
                    //}

                    WavClip curClipAfterIns = curClip.Copy();
                    curClipAfterIns.ClipBegin.Add(insPtInCurClip);

                    //audioDataStream = curClip.OpenPcmInputStream(insPtInCurClip);
                    //try
                    //{
                    //    curClipAfterIns = new WavClip(CreateDataProviderFromRawPCMStream(audioDataStream, null));
                    //}
                    //finally
                    //{
                    //    audioDataStream.Close();
                    //}

                    mWavClips.RemoveAt(clipIndex);
                    mWavClips.InsertRange(clipIndex, new WavClip[] { curClipBeforeIns, newInsClip, curClipAfterIns });
                    break;
                }
                elapsedTime.Add(curClip.Duration);
                clipIndex++;
            }
            NotifyAudioDataInserted(this, insertPoint, duration);
        }
        /// <summary>
        /// Gets a <see cref="Stream"/> providing read access to all audio between given clip begin and end <see cref="Time"/>s
        /// as raw PCM data
        /// </summary>
        /// <param name="clipBegin">The given clip begin <see cref="Time"/></param>
        /// <param name="clipEnd">The given clip end <see cref="Time"/></param>
        /// <returns>The <see cref="Stream"/></returns>
        public override Stream OpenPcmInputStream(Time clipBegin, Time clipEnd)
        {
            if (clipBegin.IsNegative)
            {
                throw new exception.MethodParameterIsOutOfBoundsException(
                          "The clip begin value can not be a negative time");
            }
            if (clipEnd.IsLessThan(clipBegin))
            {
                throw new exception.MethodParameterIsOutOfBoundsException(
                          "The clip end can not be before clip begin");
            }
            if (clipEnd.IsGreaterThan(AudioDuration))
            {
                throw new exception.MethodParameterIsOutOfBoundsException(
                          "The clip end can not beyond the end of the audio content");
            }
            if (mWavClips.Count == 0)
            {
                Debug.Fail("That's probably going to create problems ?");
                return(new MemoryStream(0));
            }
            if (mWavClips.Count == 1)
            {
                return(mWavClips[0].OpenPcmInputStream(
                           clipBegin,
                           clipEnd));
            }

            Time elapsedTime = new Time();
            int  i           = 0;

#if USE_NORMAL_LIST
            List
#else
            LightLinkedList
#endif //USE_NORMAL_LIST
            <Stream> resStreams = new
#if USE_NORMAL_LIST
                                  List
#else
                                  LightLinkedList
#endif //USE_NORMAL_LIST
                                  <Stream>();

            while (i < mWavClips.Count)
            {
                WavClip curClip             = mWavClips[i];
                Time    currentClipDuration = curClip.Duration;
                Time    newElapsedTime      = new Time(elapsedTime.AsTimeSpanTicks + currentClipDuration.AsTimeSpanTicks, true);
                if (newElapsedTime.IsLessThan(clipBegin))
                {
                    //Do nothing - the current clip and the [clipBegin;clipEnd] are disjunkt
                }
                else if (elapsedTime.IsLessThan(clipBegin))
                {
                    if (newElapsedTime.IsLessThan(clipEnd))
                    {
                        //Add part of current clip between clipBegin and newElapsedTime
                        //(ie. after clipBegin, since newElapsedTime is at the end of the clip)
                        resStreams.Add(curClip.OpenPcmInputStream(
                                           clipBegin.GetDifference(elapsedTime)));
                    }
                    else
                    {
                        //Add part of current clip between clipBegin and clipEnd
                        resStreams.Add(curClip.OpenPcmInputStream(
                                           clipBegin.GetDifference(elapsedTime),
                                           clipEnd.GetDifference(elapsedTime)));
                    }
                }
                else if (elapsedTime.IsLessThan(clipEnd))
                {
                    if (newElapsedTime.IsLessThan(clipEnd))
                    {
                        //Add part of current clip between elapsedTime and newElapsedTime
                        //(ie. entire clip since elapsedTime and newElapsedTime is at
                        //the beginning and end of the clip respectively)
                        resStreams.Add(curClip.OpenPcmInputStream());
                    }
                    else
                    {
                        //Add part of current clip between elapsedTime and clipEnd
                        //(ie. before clipEnd since elapsedTime is at the beginning of the clip)
                        resStreams.Add(curClip.OpenPcmInputStream(
                                           Time.Zero,
                                           clipEnd.GetDifference(elapsedTime)));
                    }
                }
                else
                {
                    //The current clip and all remaining clips are beyond clipEnd
                    break;
                }
                elapsedTime = newElapsedTime;
                i++;
            }
            if (resStreams.IsEmpty)
            {
                Debug.Fail("That's probably going to create problems ?");
                return(new MemoryStream(0));
            }
            return(new SequenceStream(resStreams));
        }
        /// <summary>
        /// Splits the audio media data at a given split point in time,
        /// <c>this</c> retaining the audio before the split point,
        /// creating a new <see cref="WavAudioMediaData"/> containing the audio after the split point
        /// </summary>
        /// <param name="splitPoint">The given split point</param>
        /// <returns>A audio media data containing the audio after the split point</returns>
        /// <exception cref="exception.MethodParameterIsNullException">
        /// Thrown when the given split point is <c>null</c>
        /// </exception>
        /// <exception cref="exception.MethodParameterIsOutOfBoundsException">
        /// Thrown when the given split point is negative or is beyond the duration of <c>this</c>
        /// </exception>
        public override AudioMediaData Split(Time splitPoint)
        {
            if (splitPoint == null)
            {
                throw new exception.MethodParameterIsNullException(
                          "The split point can not be null");
            }
            if (splitPoint.IsNegative)
            {
                throw new exception.MethodParameterIsOutOfBoundsException(
                          "The split point can not be negative");
            }
            if (splitPoint.IsGreaterThan(AudioDuration))
            {
                throw new exception.MethodParameterIsOutOfBoundsException(
                          String.Format(
                              "Split point {0} is beyond the WavAudioMediaData end - audio length is {1}",
                              splitPoint, AudioDuration));
            }
            WavAudioMediaData oWAMD =
                Presentation.MediaDataFactory.Create <WavAudioMediaData>();

            if (oWAMD == null)
            {
                throw new exception.FactoryCannotCreateTypeException(String.Format(
                                                                         "Thrown if the MediaDataFactory can not create a WacAudioMediaData matching Xuk QName {1}:{0}",
                                                                         GetXukName(), GetXukNamespace()));
            }
            oWAMD.PCMFormat = PCMFormat.Copy();

            Time originalDuration = AudioDuration;
            Time newClipDuration  = AudioDuration.GetDifference(splitPoint);

            Time           curClip_Begin = Time.Zero;
            List <WavClip> clips         = new List <WavClip>(mWavClips);

            mWavClips.Clear();
            oWAMD.mWavClips.Clear();
            for (int i = 0; i < clips.Count; i++)
            {
                WavClip curClip = clips[i];
                Time    savedCurClipDuration = curClip.Duration;

                Time curClip_End = new Time(curClip_Begin.AsTimeSpanTicks + curClip.Duration.AsTimeSpanTicks, true);
                if (splitPoint.IsLessThanOrEqualTo(curClip_Begin))
                {
                    oWAMD.mWavClips.Add(curClip);
                }
                else if (splitPoint.IsLessThan(curClip_End))
                {
                    WavClip secondPartClip = new WavClip(
                        curClip.DataProvider,
                        curClip.ClipBegin,
                        curClip.IsClipEndTiedToEOM ? null : curClip.ClipEnd);

                    curClip.ClipEnd = new Time(curClip.ClipBegin.AsTimeSpanTicks + (splitPoint.AsTimeSpanTicks - curClip_Begin.AsTimeSpanTicks), true);

                    secondPartClip.ClipBegin = curClip.ClipEnd.Copy();
                    mWavClips.Add(curClip);
                    oWAMD.mWavClips.Add(secondPartClip);
                }
                else
                {
                    mWavClips.Add(curClip);
                }
                curClip_Begin.Add(savedCurClipDuration);
            }
            NotifyAudioDataRemoved(this, splitPoint, newClipDuration);
            oWAMD.NotifyAudioDataInserted(oWAMD, Time.Zero, newClipDuration);

#if DEBUG
            DebugFix.Assert(AudioLibPCMFormat.TimesAreEqualWithMillisecondsTolerance(
                                newClipDuration.AsLocalUnits,
                                oWAMD.AudioDuration.AsLocalUnits));

            DebugFix.Assert(newClipDuration.IsEqualTo(oWAMD.AudioDuration));



            DebugFix.Assert(AudioLibPCMFormat.TimesAreEqualWithMillisecondsTolerance(
                                this.AudioDuration.AsLocalUnits + oWAMD.AudioDuration.AsLocalUnits,
                                originalDuration.AsLocalUnits));

            Time copy = this.AudioDuration.Copy();
            copy.Add(oWAMD.AudioDuration);
            DebugFix.Assert(originalDuration.IsEqualTo(copy));
#endif //DEBUG

            return(oWAMD);
        }