/// <summary>
        /// Calculate the file segments for analysis.
        /// </summary>
        /// <param name="fileSegments">
        /// The file segments.
        /// </param>
        /// <param name="settings">
        /// The settings.
        /// </param>
        /// <returns>
        /// Enumerable of sub-segments.
        /// </returns>
        public IEnumerable <ISegment <TSource> > CalculateSegments <TSource>(
            IEnumerable <ISegment <TSource> > fileSegments,
            AnalysisSettings settings)
        {
            if (this.allowSegmentcutting)
            {
                foreach (var segment in fileSegments)
                {
                    if (!(segment is RemoteSegment))
                    {
                        throw new NotImplementedException(
                                  $"{nameof(RemoteSourcePreparer)} only supports operating on {nameof(RemoteSegment)}");
                    }

                    var startOffset = segment.StartOffsetSeconds.Seconds();
                    var endOffset   = segment.EndOffsetSeconds.Seconds();

                    var segmentDuration = endOffset - startOffset;

                    Log.Debug($"{nameof(LocalSourcePreparer)}.{nameof(this.CalculateSegments)}: Calculating segments for duration {segmentDuration}, each {settings.AnalysisMaxSegmentDuration.Value.TotalMilliseconds} long");

                    // segment into exact chunks - all but the last chunk will be equal to the max duration
                    var segments = AudioFilePreparer.DivideExactLeaveLeftoversAtEnd(
                        Convert.ToInt64(segmentDuration.TotalMilliseconds),
                        Convert.ToInt64(settings.AnalysisMaxSegmentDuration.Value.TotalMilliseconds));

                    var  overlap   = settings.SegmentOverlapDuration;
                    long aggregate = 0;

                    // yield each normal segment
                    foreach (long offset in segments)
                    {
                        // The null for minimum means, do not filter short segments. Short filtering is done in AnalysisCoordinator
                        if (LocalSourcePreparer.TryCreateSegment(
                                ref aggregate,
                                offset,
                                segment,
                                startOffset,
                                endOffset,
                                overlap,
                                null /*settings.AnalysisMinSegmentDuration*/,
                                out var validFileSegment))
                        {
                            yield return((ISegment <TSource>)validFileSegment);
                        }
                    }
                }
            }
            else
            {
                foreach (var segment in fileSegments)
                {
                    var duration = (segment.EndOffsetSeconds - segment.StartOffsetSeconds).Seconds();
                    if (duration > settings.AnalysisMaxSegmentDuration.Value)
                    {
                        throw new SegmentSplitException(
                                  $"Splitting segments has been disabled for" +
                                  $" {nameof(RemoteSourcePreparer)}, cannot split {segment}");
                    }

                    yield return(segment);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Calculate the file segments for analysis.
        /// </summary>
        /// <param name="fileSegments">
        /// The file segments.
        /// </param>
        /// <param name="settings">
        /// The settings.
        /// </param>
        /// <returns>
        /// Enumerable of sub-segments.
        /// </returns>
        public IEnumerable <ISegment <TSource> > CalculateSegments <TSource>(
            IEnumerable <ISegment <TSource> > fileSegments,
            AnalysisSettings settings)
        {
            foreach (var segment in fileSegments)
            {
                if (!(segment is FileSegment))
                {
                    throw new NotImplementedException("Anthony was too lazy to fix this properly. " +
                                                      "Adding support proper support for ISegment is difficult " +
                                                      "at this stage.");
                }

                var fileSegment = (FileSegment)segment;

                var startOffset = fileSegment.StartOffsetSeconds.Seconds();
                var endOffset   = fileSegment.EndOffsetSeconds.Seconds();

                // process time alignment
                var startDelta = TimeSpan.Zero;
                var endDelta   = TimeSpan.Zero;
                if (fileSegment.Alignment != TimeAlignment.None)
                {
                    // FileSegment should have already verified a date will be present
                    // ReSharper disable once PossibleInvalidOperationException
                    var startDate = fileSegment.TargetFileStartDate.Value.ToUniversalTime();

                    // if there's a zero second to the time
                    if (startDate.TimeOfDay.Seconds == 0 && startDate.TimeOfDay.Milliseconds == 0)
                    {
                        // then do nothing
                        Log.Debug("TimeAlignment ignored because start date is already aligned");
                    }
                    else
                    {
                        // calculate the delta to the next minute
                        // 1:23:45, startOffset = 15
                        // 1:38:45 - start date with offset
                        // 1:39:00 - next minute
                        var dateWithStartOffset = startDate.Add(startOffset);
                        var nextMinute          = dateWithStartOffset.Ceiling(TimeSpan.FromMinutes(1));
                        startDelta = nextMinute - dateWithStartOffset;

                        var dateWithEndOffset = startDate.Add(endOffset);
                        var lastMinute        = dateWithEndOffset.Floor(TimeSpan.FromMinutes(1));
                        endDelta = dateWithEndOffset - lastMinute;
                    }
                }

                // the rest of the duration (excluding the start and end fractions from the time alignment)
                var fileSegmentDuration = (endOffset - startOffset - startDelta - endDelta).TotalMilliseconds;

                var analysisSegmentMaxDuration = settings.AnalysisMaxSegmentDuration?.TotalMilliseconds ?? fileSegmentDuration;

                var analysisSegmentMinDuration = this.filterShortSegments ? settings.AnalysisMinSegmentDuration : (TimeSpan?)null;

                Log.Debug($"{nameof(LocalSourcePreparer)}.{nameof(this.CalculateSegments)}: Calculating segments for duration {fileSegmentDuration}, each {analysisSegmentMaxDuration} long");

                // segment into exact chunks - all but the last chunk will be equal to the max duration
                var segments = AudioFilePreparer.DivideExactLeaveLeftoversAtEnd(
                    Convert.ToInt64(fileSegmentDuration),
                    Convert.ToInt64(analysisSegmentMaxDuration));

                var  overlap   = settings.SegmentOverlapDuration;
                long aggregate = 0;

                // include fractional segment cut from time alignment
                if ((fileSegment.Alignment == TimeAlignment.TrimEnd ||
                     fileSegment.Alignment == TimeAlignment.TrimNeither) && startDelta > TimeSpan.Zero)
                {
                    Log.Debug($"Generated fractional segment for time alignment ({startOffset} - {startOffset + startDelta})");
                    var startAlignDelta = Convert.ToInt64(startDelta.TotalMilliseconds);

                    if (TryCreateSegment(
                            ref aggregate,
                            startAlignDelta,
                            fileSegment,
                            startOffset,
                            endOffset,
                            overlap,
                            analysisSegmentMinDuration,
                            out var validFileSegment))
                    {
                        yield return((ISegment <TSource>)validFileSegment);
                    }
                }
                else
                {
                    // advance the counter but don't produce the first segment
                    aggregate += Convert.ToInt64(startDelta.TotalMilliseconds);
                }

                // yield each normal segment
                foreach (long offset in segments)
                {
                    if (TryCreateSegment(
                            ref aggregate,
                            offset,
                            fileSegment,
                            startOffset,
                            endOffset,
                            overlap,
                            analysisSegmentMinDuration,
                            out var validFileSegment))
                    {
                        yield return((ISegment <TSource>)validFileSegment);
                    }
                }

                // include fractional segment cut from time alignment
                if ((fileSegment.Alignment == TimeAlignment.TrimStart ||
                     fileSegment.Alignment == TimeAlignment.TrimNeither) && startDelta > TimeSpan.Zero)
                {
                    Log.Debug($"Generated fractional segment for time alignment ({endOffset - endDelta} - {endOffset})");
                    var endAlignDelta = Convert.ToInt64(endDelta.TotalMilliseconds);

                    if (TryCreateSegment(
                            ref aggregate,
                            endAlignDelta,
                            fileSegment,
                            startOffset,
                            endOffset,
                            overlap,
                            analysisSegmentMinDuration,
                            out var validFileSegment))
                    {
                        yield return((ISegment <TSource>)validFileSegment);
                    }
                }
            }
        }