Esempio n. 1
0
        public OsuPattern FromSelected(Beatmap beatmap, string name, out Beatmap patternBeatmap)
        {
            // Copy it so the changes dont affect the given beatmap object
            patternBeatmap = beatmap.DeepCopy();

            // Remove the storyboarding
            patternBeatmap.StoryboardLayerFail.Clear();
            patternBeatmap.StoryboardLayerPass.Clear();
            patternBeatmap.StoryboardLayerBackground.Clear();
            patternBeatmap.StoryboardLayerForeground.Clear();
            patternBeatmap.StoryboardLayerOverlay.Clear();

            // Keep the selected subset of hit objects
            patternBeatmap.HitObjects = patternBeatmap.HitObjects.Where(h => h.IsSelected).ToList();

            var startTime = patternBeatmap.GetHitObjectStartTime() - Padding;
            var endTime   = patternBeatmap.GetHitObjectEndTime() + Padding;

            // Keep the timing points in the range of the hitobjects
            patternBeatmap.BeatmapTiming.TimingPoints = patternBeatmap.BeatmapTiming.TimingPoints
                                                        .Where(tp => tp.Offset >= startTime && tp.Offset <= endTime).ToList();

            // Add some earlier timing points if necessary
            var firstUnInheritedTimingPoint = patternBeatmap.HitObjects.First().UnInheritedTimingPoint;
            var firstNormalTimingPoint      = patternBeatmap.HitObjects.First().TimingPoint;

            if (!patternBeatmap.BeatmapTiming.TimingPoints.Contains(firstUnInheritedTimingPoint))
            {
                patternBeatmap.BeatmapTiming.TimingPoints.Add(firstUnInheritedTimingPoint);
            }
            if (!patternBeatmap.BeatmapTiming.TimingPoints.Contains(firstNormalTimingPoint))
            {
                patternBeatmap.BeatmapTiming.TimingPoints.Add(firstNormalTimingPoint);
            }
            patternBeatmap.BeatmapTiming.Sort();

            // Generate a file name and save the pattern
            var now      = DateTime.Now;
            var fileName = GenerateUniquePatternFileName(name, now);

            return(new OsuPattern {
                Name = name,
                CreationTime = now,
                LastUsedTime = now,
                FileName = fileName,
                ObjectCount = patternBeatmap.HitObjects.Count,
                Duration = TimeSpan.FromMilliseconds(endTime - startTime - 2 * Padding),
                BeatLength = patternBeatmap.BeatmapTiming.GetBeatLength(startTime + Padding, endTime - Padding, true)
            });
        }
Esempio n. 2
0
        public OsuPattern FromSelected(Beatmap beatmap, out Beatmap patternBeatmap, string name)
        {
            // Check if it has selected objects
            if (!beatmap.HitObjects.Any(h => h.IsSelected))
            {
                throw new Exception("No selected hit objects found.");
            }

            // Copy it so the changes dont affect the given beatmap object
            patternBeatmap = beatmap.DeepCopy();

            RemoveStoryboard(patternBeatmap);
            RemoveEverythingThatIsNotTheseHitObjects(patternBeatmap, patternBeatmap.HitObjects.Where(h => h.IsSelected).ToList());

            return(FromBeatmap(patternBeatmap, name));
        }
Esempio n. 3
0
        private string Copy_Hitsounds(HitsoundCopierVm arg, BackgroundWorker worker)
        {
            var doMutedIndex = arg.MutedIndex >= 0;

            var paths        = arg.PathTo.Split('|');
            var mapsDone     = 0;
            var sampleSchema = new SampleSchema();

            var reader = EditorReaderStuff.GetFullEditorReaderOrNot();

            foreach (var pathTo in paths)
            {
                BeatmapEditor editorTo  = EditorReaderStuff.GetNewestVersionOrNot(pathTo, reader);;
                Beatmap       beatmapTo = editorTo.Beatmap;
                Beatmap       beatmapFrom;

                if (!string.IsNullOrEmpty(arg.PathFrom))
                {
                    var editorFrom = EditorReaderStuff.GetNewestVersionOrNot(arg.PathFrom, reader);
                    beatmapFrom = editorFrom.Beatmap;
                }
                else
                {
                    // Copy from an empty beatmap similar to the map to copy to
                    beatmapFrom = beatmapTo.DeepCopy();
                    beatmapFrom.HitObjects.Clear();
                    beatmapFrom.BeatmapTiming.Clear();
                }

                Timeline processedTimeline;

                if (arg.CopyMode == 0)
                {
                    // Every defined hitsound and sampleset on hitsound gets copied to their copyTo destination
                    // Timelines
                    var tlTo   = beatmapTo.GetTimeline();
                    var tlFrom = beatmapFrom.GetTimeline();

                    var volumeMuteTimes = arg.CopyVolumes && arg.AlwaysPreserve5Volume ? new List <double>() : null;

                    if (arg.CopyHitsounds)
                    {
                        ResetHitObjectHitsounds(beatmapTo);
                        CopyHitsounds(arg, tlFrom, tlTo);
                    }

                    // Save tlo times where timingpoint volume is 5%
                    // Timingpointchange all the undefined tlo from copyFrom
                    volumeMuteTimes?.AddRange(from tloTo in tlTo.TimelineObjects
                                              where tloTo.CanCopy && Math.Abs(tloTo.SampleVolume) < Precision.DOUBLE_EPSILON &&
                                              Math.Abs(tloTo.FenoSampleVolume - 5) < Precision.DOUBLE_EPSILON
                                              select tloTo.Time);

                    // Volumes and samplesets and customindices greenlines get copied with timingpointchanges and allafter enabled
                    var timingPointsChanges = beatmapFrom.BeatmapTiming.TimingPoints.Select(tp =>
                                                                                            new TimingPointsChange(tp, sampleset: arg.CopySampleSets, index: arg.CopySampleSets,
                                                                                                                   volume: arg.CopyVolumes)).ToList();

                    // Apply the timingpoint changes
                    TimingPointsChange.ApplyChanges(beatmapTo.BeatmapTiming, timingPointsChanges, true);

                    processedTimeline = tlTo;

                    // Return 5% volume to tlo that had it before
                    if (volumeMuteTimes != null)
                    {
                        var timingPointsChangesMute = new List <TimingPointsChange>();
                        processedTimeline.GiveTimingPoints(beatmapTo.BeatmapTiming);

                        // Exclude objects which use their own sample volume property instead
                        foreach (var tloTo in processedTimeline.TimelineObjects.Where(o => Math.Abs(o.SampleVolume) < Precision.DOUBLE_EPSILON))
                        {
                            if (volumeMuteTimes.Contains(tloTo.Time))
                            {
                                // Add timingpointschange to copy timingpoint hitsounds
                                var tp = tloTo.HitsoundTimingPoint.Copy();
                                tp.Offset = tloTo.Time;
                                tp.Volume = 5;
                                timingPointsChangesMute.Add(new TimingPointsChange(tp, volume: true));
                            }
                            else
                            {
                                // Add timingpointschange to preserve index and volume
                                var tp = tloTo.HitsoundTimingPoint.Copy();
                                tp.Offset = tloTo.Time;
                                tp.Volume = tloTo.FenoSampleVolume;
                                timingPointsChangesMute.Add(new TimingPointsChange(tp, volume: true));
                            }
                        }

                        // Apply the timingpoint changes
                        TimingPointsChange.ApplyChanges(beatmapTo.BeatmapTiming, timingPointsChangesMute);
                    }
                }
                else
                {
                    // Smarty mode
                    // Copy the defined hitsounds literally (not feno, that will be reserved for cleaner). Only the tlo that have been defined by copyFrom get overwritten.
                    var tlTo   = beatmapTo.GetTimeline();
                    var tlFrom = beatmapFrom.GetTimeline();

                    var timingPointsChanges = new List <TimingPointsChange>();
                    var mode         = (GameMode)beatmapTo.General["Mode"].IntValue;
                    var mapDir       = editorTo.GetParentFolder();
                    var firstSamples = HitsoundImporter.AnalyzeSamples(mapDir);

                    if (arg.CopyHitsounds)
                    {
                        CopyHitsounds(arg, beatmapTo, tlFrom, tlTo, timingPointsChanges, mode, mapDir, firstSamples, ref sampleSchema);
                    }

                    if (arg.CopyBodyHitsounds)
                    {
                        // Remove timingpoints in beatmapTo that are in a sliderbody/spinnerbody for both beatmapTo and BeatmapFrom
                        foreach (var tp in from ho in beatmapTo.HitObjects
                                 from tp in ho.BodyHitsounds
                                 where beatmapFrom.HitObjects.Any(o => o.Time <tp.Offset && o.EndTime> tp.Offset)
                                 where !tp.Uninherited
                                 select tp)
                        {
                            beatmapTo.BeatmapTiming.Remove(tp);
                        }

                        // Get timingpointschanges for every timingpoint from beatmapFrom that is in a sliderbody/spinnerbody for both beatmapTo and BeatmapFrom
                        timingPointsChanges.AddRange(from ho in beatmapFrom.HitObjects
                                                     from tp in ho.BodyHitsounds
                                                     where beatmapTo.HitObjects.Any(o => o.Time <tp.Offset && o.EndTime> tp.Offset)
                                                     select new TimingPointsChange(tp.Copy(), sampleset: arg.CopySampleSets, index: arg.CopySampleSets,
                                                                                   volume: arg.CopyVolumes));
                    }

                    // Apply the timingpoint changes
                    TimingPointsChange.ApplyChanges(beatmapTo.BeatmapTiming, timingPointsChanges);

                    processedTimeline = tlTo;
                }

                if (arg.CopyStoryboardedSamples)
                {
                    if (arg.CopyMode == 0)
                    {
                        beatmapTo.StoryboardSoundSamples.Clear();
                    }

                    beatmapTo.GiveObjectsGreenlines();
                    processedTimeline.GiveTimingPoints(beatmapTo.BeatmapTiming);

                    var mapDir       = editorTo.GetParentFolder();
                    var firstSamples = HitsoundImporter.AnalyzeSamples(mapDir, true);

                    var samplesTo = new HashSet <StoryboardSoundSample>(beatmapTo.StoryboardSoundSamples);
                    var mode      = (GameMode)beatmapTo.General["Mode"].IntValue;

                    foreach (var sampleFrom in beatmapFrom.StoryboardSoundSamples)
                    {
                        if (arg.IgnoreHitsoundSatisfiedSamples)
                        {
                            var tloHere = processedTimeline.TimelineObjects.FindAll(o =>
                                                                                    Math.Abs(o.Time - sampleFrom.StartTime) <= arg.TemporalLeniency);
                            var samplesHere = new HashSet <string>();
                            foreach (var tlo in tloHere)
                            {
                                foreach (var filename in tlo.GetPlayingFilenames(mode))
                                {
                                    var samplePath      = Path.Combine(mapDir, filename);
                                    var fullPathExtLess = Path.Combine(Path.GetDirectoryName(samplePath),
                                                                       Path.GetFileNameWithoutExtension(samplePath));

                                    if (firstSamples.Keys.Contains(fullPathExtLess))
                                    {
                                        samplePath = firstSamples[fullPathExtLess];
                                    }

                                    samplesHere.Add(samplePath);
                                }
                            }

                            var sbSamplePath      = Path.Combine(mapDir, sampleFrom.FilePath);
                            var sbFullPathExtLess = Path.Combine(Path.GetDirectoryName(sbSamplePath),
                                                                 Path.GetFileNameWithoutExtension(sbSamplePath));

                            if (firstSamples.Keys.Contains(sbFullPathExtLess))
                            {
                                sbSamplePath = firstSamples[sbFullPathExtLess];
                            }

                            if (samplesHere.Contains(sbSamplePath))
                            {
                                continue;
                            }
                        }

                        // Add the StoryboardSoundSamples from beatmapFrom to beatmapTo if it doesn't already have the sample
                        if (!samplesTo.Contains(sampleFrom))
                        {
                            beatmapTo.StoryboardSoundSamples.Add(sampleFrom);
                        }
                    }

                    // Sort the storyboarded samples
                    beatmapTo.StoryboardSoundSamples.Sort();
                }

                if (arg.MuteSliderends)
                {
                    var timingPointsChanges = new List <TimingPointsChange>();
                    beatmapTo.GiveObjectsGreenlines();
                    processedTimeline.GiveTimingPoints(beatmapTo.BeatmapTiming);

                    foreach (var tloTo in processedTimeline.TimelineObjects)
                    {
                        if (FilterMuteTlo(tloTo, beatmapTo, arg))
                        {
                            // Set volume to 5%, remove all hitsounds, apply customindex and sampleset
                            tloTo.SampleSet   = arg.MutedSampleSet;
                            tloTo.AdditionSet = 0;
                            tloTo.Normal      = false;
                            tloTo.Whistle     = false;
                            tloTo.Finish      = false;
                            tloTo.Clap        = false;

                            tloTo.HitsoundsToOrigin();

                            // Add timingpointschange to copy timingpoint hitsounds
                            var tp = tloTo.HitsoundTimingPoint.Copy();
                            tp.Offset      = tloTo.Time;
                            tp.SampleSet   = arg.MutedSampleSet;
                            tp.SampleIndex = arg.MutedIndex;
                            tp.Volume      = 5;
                            timingPointsChanges.Add(new TimingPointsChange(tp, sampleset: true, index: doMutedIndex,
                                                                           volume: true));
                        }
                        else
                        {
                            // Add timingpointschange to preserve index and volume and sampleset
                            var tp = tloTo.HitsoundTimingPoint.Copy();
                            tp.Offset = tloTo.Time;
                            timingPointsChanges.Add(new TimingPointsChange(tp, sampleset: true, index: doMutedIndex,
                                                                           volume: true));
                        }
                    }

                    // Apply the timingpoint changes
                    TimingPointsChange.ApplyChanges(beatmapTo.BeatmapTiming, timingPointsChanges);
                }

                // Save the file
                editorTo.SaveFile();

                // Export the sample schema if there are samples
                if (sampleSchema.Count > 0)
                {
                    string exportFolder = MainWindow.ExportPath;

                    DirectoryInfo di = new DirectoryInfo(exportFolder);
                    foreach (FileInfo file in di.GetFiles())
                    {
                        file.Delete();
                    }

                    HitsoundExporter.ExportSampleSchema(sampleSchema, exportFolder);

                    System.Diagnostics.Process.Start(exportFolder);
                }

                // Update progressbar
                if (worker != null && worker.WorkerReportsProgress)
                {
                    worker.ReportProgress(++mapsDone * 100 / paths.Length);
                }
            }

            return("Done!");
        }
Esempio n. 4
0
        /// <summary>
        /// Places each hit object of the pattern beatmap into the other beatmap and applies timingpoint changes to copy timingpoint stuff aswell.
        /// The given pattern beatmap could be modified by this method if protectBeatmapPattern is false.
        /// </summary>
        /// <param name="patternBeatmap">The pattern beatmap to be placed into the beatmap.</param>
        /// <param name="beatmap">To beatmap to place the pattern in.</param>
        /// <param name="offset">An offset to move the pattern beatmap in time with.</param>
        /// <param name="protectBeatmapPattern">If true, copies the pattern beatmap to prevent the pattern beatmap from being modified by this method.</param>
        public void PlaceOsuPattern(Beatmap patternBeatmap, Beatmap beatmap, double offset = 0, bool protectBeatmapPattern = true)
        {
            if (protectBeatmapPattern)
            {
                // Copy so the original pattern doesnt get changed
                patternBeatmap = patternBeatmap.DeepCopy();
            }

            // Do the offset
            if (Math.Abs(offset) > Precision.DOUBLE_EPSILON)
            {
                patternBeatmap.OffsetTime(offset);
            }

            // We adjust the pattern first so it alligns with the beatmap.
            // The right timing is applied and optional pre-processing is applied.
            // Sliderends and object timingpoints get recalculated.
            PreparePattern(patternBeatmap, beatmap, out var parts, out var timingPointsChanges);

            // Keep just the timing point changes which are inside the parts.
            // These timing point changes have everything that is necessary for inside the parts of the pattern. (even timing)
            timingPointsChanges = timingPointsChanges.Where(tpc => parts.Any(part =>
                                                                             part.StartTime <= tpc.MyTP.Offset && part.EndTime >= tpc.MyTP.Offset)).ToList();

            // Remove stuff
            if (PatternOverwriteMode != PatternOverwriteMode.NoOverwrite)
            {
                foreach (var part in parts)
                {
                    RemovePartOfBeatmap(beatmap, part.StartTime - Padding, part.EndTime + Padding);
                }
            }

            // Add timingpoint changes for each hitobject to make sure they still have the wanted SV and hitsounds (especially near the edges of parts)
            // It is possible for the timingpoint of a hitobject at the start of a part to be outside of the part, so this fixes issues related to that
            timingPointsChanges.AddRange(
                beatmap.HitObjects.Where(ho => ho.TimingPoint != null)
                .Select(GetSvChange));

            if (IncludeHitsounds)
            {
                timingPointsChanges.AddRange(
                    beatmap.HitObjects.Where(ho => ho.HitsoundTimingPoint != null)
                    .Select(GetHitsoundChange));
            }

            // Apply the changes
            TimingPointsChange.ApplyChanges(beatmap.BeatmapTiming, timingPointsChanges);

            // Add the hitobjects of the pattern
            beatmap.HitObjects.AddRange(patternBeatmap.HitObjects);

            // Sort hitobjects
            beatmap.SortHitObjects();

            if (FixColourHax)
            {
                beatmap.FixComboSkip();
            }

            beatmap.GiveObjectsGreenlines();
            beatmap.CalculateSliderEndTimes();
        }
Esempio n. 5
0
        /// <summary>
        /// Places each hit object of the pattern beatmap into the other beatmap and applies timingpoint changes to copy timingpoint stuff aswell.
        /// The given pattern beatmap could be modified by this method if protectBeatmapPattern is false.
        /// </summary>
        /// <param name="patternBeatmap">The pattern beatmap to be placed into the beatmap.</param>
        /// <param name="beatmap">To beatmap to place the pattern in.</param>
        /// <param name="offset">An offset to move the pattern beatmap in time with.</param>
        /// <param name="protectBeatmapPattern">If true, copies the pattern beatmap to prevent the pattern beatmap from being modified by this method.</param>
        public void PlaceOsuPattern(Beatmap patternBeatmap, Beatmap beatmap, double offset = 0, bool protectBeatmapPattern = true)
        {
            if (protectBeatmapPattern)
            {
                // Copy so the original pattern doesnt get changed
                patternBeatmap = patternBeatmap.DeepCopy();
            }

            if (offset != 0)
            {
                patternBeatmap.OffsetTime(offset);
            }

            // Do some kind of processing to fix timing etc
            // Set the global SV and BPM in the pattern beatmap so the object end times can be calculated for the partitioning
            patternBeatmap.BeatmapTiming.SliderMultiplier = beatmap.BeatmapTiming.SliderMultiplier;
            patternBeatmap.BeatmapTiming.TimingPoints.RemoveAll(tp => tp.Uninherited);
            patternBeatmap.BeatmapTiming.TimingPoints.AddRange(beatmap.BeatmapTiming.GetAllRedlines());
            patternBeatmap.BeatmapTiming.Sort();
            patternBeatmap.CalculateSliderEndTimes();

            // Partition the pattern beatmap
            List <Tuple <double, double> > parts;

            if (PatternOverwriteMode == PatternOverwriteMode.PartitionedOverwrite)
            {
                parts = PartitionBeatmap(patternBeatmap);
            }
            else
            {
                parts = new List <Tuple <double, double> > {
                    new Tuple <double, double>(patternBeatmap.GetHitObjectStartTime(), patternBeatmap.GetHitObjectEndTime())
                };
            }

            // Remove stuff
            if (PatternOverwriteMode != PatternOverwriteMode.NoOverwrite)
            {
                foreach (var part in parts)
                {
                    RemovePartOfBeatmap(beatmap, part.Item1 - Padding, part.Item2 + Padding);
                }
            }

            // Add the hitobjects of the pattern
            beatmap.HitObjects.AddRange(patternBeatmap.HitObjects);

            // Add timingpoint changes for each timingpoint in a part in the pattern
            var timingPointsChanges = new List <TimingPointsChange>();

            foreach (var part in parts)
            {
                timingPointsChanges.AddRange(
                    patternBeatmap.BeatmapTiming.TimingPoints.Where(tp => tp.Offset >= part.Item1 - Padding &&
                                                                    tp.Offset <= part.Item2 + Padding)
                    .Select(tp => GetTimingPointsChange(tp, true, true)));
            }

            // Add timingpoint changes for each hitobject to make sure they still have the wanted SV and hitsounds (especially near the edges of parts)
            // It is possible for the timingpoint of a hitobject at the start of a part to be outside of the part, so this fixes issues related to that
            timingPointsChanges.AddRange(
                beatmap.HitObjects.Where(ho => ho.TimingPoint != null)
                .Select(ho => GetTimingPointsChange(ho, true, true)));

            // Apply the changes
            TimingPointsChange.ApplyChanges(beatmap.BeatmapTiming, timingPointsChanges);

            // Sort hitobjects later so the timingpoints changes from the new hitobjects have priority
            beatmap.SortHitObjects();
        }