Ejemplo n.º 1
0
        /// <summary>
        ///     Determines whether a bearable track/mix is allowed.
        /// </summary>
        /// <param name="currentTrack">The current track.</param>
        /// <param name="currentPath">The current path.</param>
        /// <param name="allowBearable">The allow bearable.</param>
        /// <param name="mixTracks">The mix tracks.</param>
        /// <returns>True if a bearable track/mix is allowed.</returns>
        private bool IsBearableTrackMixAllowed(Track currentTrack,
            IReadOnlyList<Track> currentPath,
            AllowBearableMixStrategy allowBearable,
            IReadOnlyCollection<Track> mixTracks)
        {
            var bearableAllowed = false;

            switch (allowBearable)
            {
                case AllowBearableMixStrategy.Always:
                    bearableAllowed = true;
                    break;
                case AllowBearableMixStrategy.AfterTwoGoodTracks:
                    bearableAllowed = (!IsLastMixBearable(currentPath) && !IsPenultimateMixBearable(currentPath))
                                      || (currentTrack.PowerDown && mixTracks.Count == 0);
                    break;
                case AllowBearableMixStrategy.AfterEachGoodTrack:
                    bearableAllowed = !IsLastMixBearable(currentPath)
                                      || (currentTrack.PowerDown && mixTracks.Count == 0);
                    break;
                case AllowBearableMixStrategy.Never:
                    break;
                case AllowBearableMixStrategy.AfterPowerDown:
                    bearableAllowed = currentTrack.PowerDown;
                    break;
                case AllowBearableMixStrategy.WhenNecessary:
                    bearableAllowed = mixTracks.Count == 0;
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(allowBearable), allowBearable, null);
            }

            return bearableAllowed;
        }
Ejemplo n.º 2
0
        private void GeneratePaths(Direction direction,
            AllowBearableMixStrategy allowBearable,
            MixStrategy strategy,
            UseExtendedMixes useExtendedMixes,
            IReadOnlyDictionary<string, Dictionary<string, Track>> excludedMixes,
            bool restrictArtistClumping,
            bool restrictGenreClumping,
            bool restrictTitleClumping,
            KeyMixStrategy keyMixStrategy,
            Track workingTrack,
            ICollection<string> availableTrackDescriptions,
            List<TrackPath> nextPaths,
            TrackPath currentPath)
        {
            var currentTrack = currentPath.Tracks.Last();

            DebugHelper.WriteLine("Start GeneratePaths " + currentTrack.Description);

            var excludeTrackDescriptions = GetDistinctTrackDescriptions(currentPath.Tracks);

            List<Track> mixTracks;
            if (strategy == MixStrategy.BestMix || strategy == MixStrategy.Variety ||
                strategy == MixStrategy.ExtraVariety)
            {
                mixTracks = GetBestMixTracks(currentTrack, currentPath.Tracks, allowBearable, availableTrackDescriptions,
                    excludeTrackDescriptions, restrictArtistClumping, restrictGenreClumping, restrictTitleClumping,
                    keyMixStrategy);
            }
            else if (strategy == MixStrategy.Unranked)
            {
                mixTracks = GetUnrankedTracks(currentTrack, currentPath.Tracks, availableTrackDescriptions,
                    excludeTrackDescriptions, keyMixStrategy, true);
            }
            else if (strategy == MixStrategy.Working)
            {
                mixTracks = GetWorkingTracks(currentTrack, currentPath.Tracks, workingTrack, availableTrackDescriptions,
                    excludeTrackDescriptions, keyMixStrategy);
            }
            else
            {
                mixTracks = new List<Track>();
            }

            if (direction != Direction.Any)
            {
                var preferredDirection = direction;
                if (preferredDirection == Direction.Cycle)
                    preferredDirection = GetPreferredDirection(currentTrack, currentPath.Tracks);

                var filteredTracks = FilterTracksByDirection(currentTrack, mixTracks, preferredDirection);
                if (filteredTracks.Count > 0) mixTracks = filteredTracks;
            }

            if ((strategy == MixStrategy.BestMix || strategy == MixStrategy.Variety ||
                 strategy == MixStrategy.ExtraVariety)
                && useExtendedMixes != UseExtendedMixes.Any)
            {
                mixTracks = FilterTracksByExtendedMix(currentTrack, mixTracks, useExtendedMixes);
            }

            if (excludedMixes != null)
            {
                mixTracks = FilterExcludedMixes(currentTrack, mixTracks, excludedMixes);
            }

            if (strategy == MixStrategy.BestMix || strategy == MixStrategy.Variety ||
                strategy == MixStrategy.ExtraVariety)
            {
                mixTracks = mixTracks
                    .OrderByDescending(x => GetAverageTrackAndMixAndKeyRank(currentTrack, x))
                    .ThenBy(x => x.Length)
                    .ToList();

                if (strategy == MixStrategy.Variety)
                {
                    mixTracks = FilterTracksForVariety(currentTrack, mixTracks);
                }
                else if (strategy == MixStrategy.ExtraVariety)
                {
                    mixTracks = FilterTracksForExtraVariety(currentTrack, mixTracks);
                }
            }

            var max = 3*Environment.ProcessorCount;
            mixTracks = mixTracks
                .Take(max)
                .ToList();

            var trackPaths = mixTracks.Select(mixTrack => new TrackPath(mixTrack, currentPath));
            foreach (var newPath in trackPaths)
            {
                lock (nextPaths)
                {
                    nextPaths.Add(newPath);
                    CalculateAverageRankForPath(newPath);
                }

                if (IsGenerationHalted()) break;
            }

            DebugHelper.WriteLine("End GeneratePaths " + currentTrack.Description);
        }
Ejemplo n.º 3
0
        /// <summary>
        ///     Gets the best mix tracks for play-list generation.
        /// </summary>
        /// <param name="currentTrack">The current track.</param>
        /// <param name="currentPath">The current path.</param>
        /// <param name="allowBearable">The allow bearable.</param>
        /// <param name="availableTrackDescriptions">The available track descriptions.</param>
        /// <param name="excludeTrackDescriptions">The exclude track descriptions.</param>
        /// <param name="restrictArtistClumping">If set to true, genre clumping is restricted.</param>
        /// <param name="restrictGenreClumping">if set to true&gt; restrict genre clumping.</param>
        /// <param name="restrictTitleClumping">if set to true restrict title clumping.</param>
        /// <param name="keyMixStrategy">The key mix strategy.</param>
        /// <returns>
        ///     A list of filtered mix tracks
        /// </returns>
        private List<Track> GetBestMixTracks(Track currentTrack,
            List<Track> currentPath,
            AllowBearableMixStrategy allowBearable,
            ICollection<string> availableTrackDescriptions,
            ICollection<string> excludeTrackDescriptions,
            bool restrictArtistClumping,
            bool restrictGenreClumping,
            bool restrictTitleClumping,
            KeyMixStrategy keyMixStrategy)
        {
            var mixTracks = MixLibrary
                .GetGoodTracks(currentTrack)
                .Where(t => !excludeTrackDescriptions.Contains(t.Description))
                .Where(t => availableTrackDescriptions.Contains(t.Description))
                .ToList();

            FilterMixableTracks(currentTrack,
                currentPath,
                restrictArtistClumping,
                restrictGenreClumping,
                restrictTitleClumping,
                keyMixStrategy,
                mixTracks);

            var bearableAllowed = IsBearableTrackMixAllowed(currentTrack, currentPath, allowBearable, mixTracks);

            if (!bearableAllowed) mixTracks.RemoveAll(t => t.Rank <= 2);

            if (bearableAllowed)
            {
                var bearableTracks = MixLibrary
                    .GetBearableTracks(currentTrack)
                    .Where(t => !excludeTrackDescriptions.Contains(t.Description))
                    .Where(t => availableTrackDescriptions.Contains(t.Description))
                    .ToList();

                mixTracks.AddRange(bearableTracks);
            }

            FilterMixableTracks(currentTrack,
                currentPath,
                restrictArtistClumping,
                restrictGenreClumping,
                restrictTitleClumping,
                keyMixStrategy,
                mixTracks);

            return mixTracks;
        }
Ejemplo n.º 4
0
        public List<Track> GeneratePlayList(List<Track> availableTracks,
            MixLibrary mixLibrary,
            List<Track> currentPlaylist,
            Direction direction,
            int approximateLength,
            AllowBearableMixStrategy allowBearable,
            MixStrategy strategy,
            UseExtendedMixes useExtendedMixes,
            Dictionary<string, Dictionary<string, Track>> excludedMixes,
            bool restrictArtistClumping,
            bool restrictGenreClumping,
            bool restrictTitleClumping,
            ContinueMix continueMix,
            KeyMixStrategy keyMixStrategy,
            int maxTracksToAdd)
        {
            if (strategy == MixStrategy.Working && currentPlaylist.Count == 0) return currentPlaylist;

            Track workingTrack = null;
            if (strategy == MixStrategy.Working)
            {
                direction = Direction.Any;
                workingTrack = currentPlaylist.Last();
            }

            GeneratePlayListStatus = "";
            MixLibrary = mixLibrary;

            AvailableTracks = availableTracks;

            if (strategy == MixStrategy.Working) AvailableTracks.RemoveAll(t => MixLibrary.GetMixOutCount(t) == 0);

            if (AvailableTracks.Count == 0) return currentPlaylist;

            var availableTrackDescriptions = GetDistinctTrackDescriptions(AvailableTracks);

            var trackCountLimit = int.MaxValue;
            if (approximateLength > 0 && approximateLength != int.MaxValue)
            {
                var currentLength = currentPlaylist.Sum(cp => cp.Length);
                var requiredLength = Convert.ToInt32((approximateLength*60) - currentLength);

                if (requiredLength <= 0) return new List<Track>();
                var averageLength = AvailableTracks.Average(t => t.Length);

                trackCountLimit = (requiredLength/Convert.ToInt32(averageLength)) + currentPlaylist.Count;

                if (trackCountLimit == currentPlaylist.Count) return new List<Track>();
            }

            if (maxTracksToAdd != int.MaxValue && trackCountLimit > currentPlaylist.Count + maxTracksToAdd)
            {
                trackCountLimit = currentPlaylist.Count + maxTracksToAdd;
            }

            if (strategy != MixStrategy.Unranked && strategy != MixStrategy.Working)
            {
                if (trackCountLimit > AvailableTracks.Count)
                {
                    trackCountLimit = AvailableTracks.Count;
                }
            }

            var initialPlaylistCount = currentPlaylist.Count;

            var currentPaths = new List<TrackPath>();
            if (currentPlaylist.Count == 0)
            {
                var trackPaths = AvailableTracks.Select(track => new TrackPath(track));
                foreach (var path in trackPaths)
                {
                    CalculateAverageRankForPath(path);
                    currentPaths.Add(path);
                }
            }
            else if (continueMix == ContinueMix.No)
            {
                var trackPaths = AvailableTracks
                    .Select(track => new List<Track>(currentPlaylist) {track})
                    .Select(playlist => new TrackPath(playlist));

                foreach (var path in trackPaths)
                {
                    CalculateAverageRankForPath(path);
                    currentPaths.Add(path);
                }
            }
            else
            {
                var path = new TrackPath(currentPlaylist);
                CalculateAverageRankForPath(path);
                currentPaths.Add(path);
            }

            _cancelGeneratePlayList = false;
            _stopGeneratePlayList = false;

            var nextPaths = new List<TrackPath>();
            while (!IsGenerationHalted())
            {
                ParallelHelper.ForEach(currentPaths, currentPath => GeneratePaths(direction,
                    allowBearable,
                    strategy,
                    useExtendedMixes,
                    excludedMixes,
                    restrictArtistClumping,
                    restrictGenreClumping,
                    restrictTitleClumping,
                    keyMixStrategy,
                    workingTrack,
                    availableTrackDescriptions,
                    nextPaths,
                    currentPath));

                if (IsGenerationHalted()) break;

                if (nextPaths.Count == 0) break;

                GeneratePlayListStatus =
                    $"Generated {nextPaths.Count} possible paths for {nextPaths[0].Tracks.Count} of {trackCountLimit} tracks.";

                var max = 50*Environment.ProcessorCount;

                if (nextPaths.Count > max)
                {
                    nextPaths = nextPaths
                        .OrderByDescending(t => t.AverageRank)
                        .Take(max)
                        .ToList();
                }

                currentPaths.Clear();
                currentPaths.AddRange(nextPaths);

                if (nextPaths[0].Tracks.Count >= trackCountLimit) break;
                nextPaths.Clear();
            }

            if (_cancelGeneratePlayList) return currentPlaylist;

            var resultPath = currentPaths
                .OrderByDescending(t => GetAverageTrackAndMixAndKeyRank(t.Tracks))
                .FirstOrDefault();

            if ((strategy == MixStrategy.BestMix || strategy == MixStrategy.Variety ||
                 strategy == MixStrategy.ExtraVariety)
                && resultPath != null
                && resultPath.Tracks.Count < trackCountLimit
                && resultPath.Tracks.Count > 0)
            {
                availableTrackDescriptions = GetDistinctTrackDescriptions(AvailableTracks);
                var excludeTrackDescriptions = GetDistinctTrackDescriptions(resultPath.Tracks);
                var currentTrack = resultPath.Tracks[resultPath.Tracks.Count - 1];
                var nextTrack =
                    GetBestMixTracks(currentTrack, resultPath.Tracks, allowBearable, availableTrackDescriptions,
                        excludeTrackDescriptions, restrictArtistClumping, restrictArtistClumping, restrictTitleClumping,
                        keyMixStrategy)
                        .OrderBy(t => GetAverageTrackAndMixAndKeyRank(currentTrack, t))
                        .FirstOrDefault();

                if (nextTrack != null) resultPath.Tracks.Add(nextTrack);
            }

            var resultTracks = (resultPath != null)
                ? resultPath.Tracks
                : new List<Track>();

            if (continueMix == ContinueMix.IfPossible && resultTracks.Count == initialPlaylistCount)
            {
                return GeneratePlayList(availableTracks,
                    mixLibrary,
                    currentPlaylist,
                    direction,
                    approximateLength,
                    allowBearable,
                    strategy,
                    useExtendedMixes,
                    excludedMixes,
                    restrictArtistClumping,
                    restrictGenreClumping,
                    restrictTitleClumping,
                    ContinueMix.No,
                    keyMixStrategy,
                    maxTracksToAdd);
            }

            return resultTracks;
        }