/// <summary>
        ///     Replace output sample at position with prediction and
        ///     sets prediction error sample to zero
        /// </summary>
        /// <param name="audioData"></param>
        /// <param name="position"></param>
        /// <param name="lenght"></param>
        public static float Repair(AudioData audioData, int position, int lenght)
        {
            for (var index = position; index < position + lenght; index++)
            {
                audioData.SetPredictionErr(index, 0.001F);
                audioData.SetOutputSample(
                    index,
                    CalcBurgPred(audioData, index)
                    );
            }

            for (var index = position + lenght;
                 index < position + lenght + 5;
                 index++)
            {
                audioData.SetPredictionErr(
                    index,
                    CalcBurgPred(audioData, index) -
                    audioData.GetOutputSample(index));
            }

            var historyLengthSamples =
                audioData.AudioProcessingSettings.HistoryLengthSamples;

            HelperCalculator.CalculateErrorAverageCpu(
                audioData,
                position - historyLengthSamples,
                position + lenght + historyLengthSamples,
                historyLengthSamples);

            return(HelperCalculator.CalculateDetectionLevel(audioData, position));
        }
        /// <summary>
        /// Scans segment of audio channel to find damaged samples
        /// and repai them
        /// </summary>
        /// <param name="audioData"></param>
        /// <param name="segmentStart"></param>
        /// <param name="segmentEnd"></param>
        /// <param name="progress"></param>
        /// <param name="cpuCore"></param>
        private static void ScanSegment(
            AudioData audioData,
            int segmentStart,
            int segmentEnd,
            IProgress <double> progress,
            int cpuCore)
        {
            var lastProcessedSample = 0;

            // cycle to check every sample
            for (var index = segmentStart; index < segmentEnd; index++)
            {
                // only core #0 reports progress
                if (cpuCore == 0)
                {
                    ThrottledReportProgress(progress, index, segmentEnd);
                }

                if (index <= lastProcessedSample || !ClickDetector.IsSampleSuspicious(
                        audioData,
                        index))
                {
                    continue;
                }

                var maxLength = HelperCalculator.GetMaxLength(audioData, index);
                var result    = ClickLengthFinder.FindLengthOfClick(
                    audioData,
                    index,
                    maxLength,
                    lastProcessedSample);

                if (!result.Success)
                {
                    continue;
                }

                ClickRepairer.Repair(audioData, result.Position, result.Length);
                audioData.AddClickToList(new AudioClick(
                                             result.Position,
                                             result.Length,
                                             HelperCalculator.CalculateDetectionLevel(audioData, result.Position),
                                             audioData,
                                             audioData.GetCurrentChannelType()));

                lastProcessedSample = result.Position + result.Length + 1;
            }
        }
        /// <summary>
        /// Scans channel to find damaged samples
        /// </summary>
        /// <param name="audioData"></param>
        /// <param name="progress"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        private static async Task ProcessChannelAsync(
            AudioData audioData,
            IProgress <double> progress,
            IProgress <string> status)
        {
            var historyLengthSamples =
                audioData.AudioProcessingSettings.HistoryLengthSamples;

            SetStatus(audioData, status, "preprocessing");

            if (audioData.CurrentChannelIsPreprocessed())
            {
                // if prediction errors were previously calculated
                audioData.RestoreCurrentChannelPredErrors();
            }
            else
            {
                CalculateBurgPredictionErrCpu(audioData, progress);
                audioData.SetCurrentChannelIsPreprocessed();
                audioData.BackupCurrentChannelPredErrors();
            }

            for (var index = 0; index < historyLengthSamples + 16; index++)
            {
                audioData.SetErrorAverage(index, 0.001F);
            }

            HelperCalculator.CalculateErrorAverageCpu(
                audioData,
                historyLengthSamples,
                audioData.LengthSamples(),
                historyLengthSamples);

            status.Report("");

            // copies input samples to output before scanning
            for (var index = 0; index < audioData.LengthSamples(); index++)
            {
                audioData.SetOutputSample(index, audioData.GetInputSample(index));
            }

            SetStatus(audioData, status, "scanning");

            await Task.Run(() => ScanAudioAsync(audioData, progress));

            status.Report("");
        }