Exemplo n.º 1
0
        private async Task AddSingleHitObject(RawHitObject obj, HashSet <string> waves,
                                              ConcurrentBag <SoundElement> elements)
        {
            if (obj.ObjectType != HitObjectType.Slider)
            {
                var itemOffset = obj.ObjectType == HitObjectType.Spinner
                    ? obj.HoldEnd // spinner
                    : obj.Offset; // hold & circle
                var timingPoint = _osuFile.TimingPoints.GetLine(itemOffset);

                float balance = GetObjectBalance(obj.X);
                float volume  = GetObjectVolume(obj, timingPoint);

                var tuples = AnalyzeHitsoundFiles(obj.Hitsound, obj.SampleSet, obj.AdditionSet,
                                                  timingPoint, obj, waves);
                foreach (var(filePath, _) in tuples)
                {
                    var element = SoundElement.Create(itemOffset, volume, balance, filePath);
                    elements.Add(element);
                }
            }
            else // sliders
            {
                // edges
                bool forceUseSlide = obj.SliderInfo.EdgeSamples == null;
                foreach (var item in obj.SliderInfo.Edges)
                {
                    var itemOffset  = item.Offset;
                    var timingPoint = _osuFile.TimingPoints.GetLine(itemOffset);

                    float balance = GetObjectBalance(item.Point.X);
                    float volume  = GetObjectVolume(obj, timingPoint);

                    var hs = forceUseSlide
                        ? obj.Hitsound
                        : item.EdgeHitsound;
                    var addition = forceUseSlide
                        ? obj.AdditionSet
                        : item.EdgeAddition;
                    var sample = forceUseSlide
                        ? obj.SampleSet
                        : item.EdgeSample;
                    var tuples = AnalyzeHitsoundFiles(hs, sample, addition,
                                                      timingPoint, obj, waves);
                    foreach (var(filePath, _) in tuples)
                    {
                        var element = SoundElement.Create(itemOffset, volume, balance, filePath);
                        elements.Add(element);
                    }
                }

                // ticks
                var ticks = obj.SliderInfo.Ticks;
                foreach (var sliderTick in ticks)
                {
                    var itemOffset  = sliderTick.Offset;
                    var timingPoint = _osuFile.TimingPoints.GetLine(itemOffset);

                    float balance = GetObjectBalance(sliderTick.Point.X);
                    float volume  = GetObjectVolume(obj, timingPoint) * 1.25f; // ticks x1.25

                    var(filePath, _) = AnalyzeHitsoundFiles(HitsoundType.Tick, obj.SampleSet, obj.AdditionSet,
                                                            timingPoint, obj, waves).First();

                    var element = SoundElement.Create(itemOffset, volume, balance, filePath);
                    elements.Add(element);
                }

                // sliding
                {
                    var slideElements = new List <SoundElement>();

                    var startOffset = obj.Offset;
                    var endOffset   = obj.SliderInfo.Edges[obj.SliderInfo.Edges.Length - 1].Offset;
                    var timingPoint = _osuFile.TimingPoints.GetLine(startOffset);

                    float balance = GetObjectBalance(obj.X);
                    float volume  = GetObjectVolume(obj, timingPoint);

                    // start sliding
                    var tuples = AnalyzeHitsoundFiles(
                        obj.Hitsound & HitsoundType.SlideWhistle | HitsoundType.Slide,
                        obj.SampleSet, obj.AdditionSet,
                        timingPoint, obj, waves);
                    foreach (var(filePath, hitsoundType) in tuples)
                    {
                        int channel;
                        if (hitsoundType.HasFlag(HitsoundType.Slide))
                        {
                            channel = 0;
                        }
                        else if (hitsoundType.HasFlag(HitsoundType.SlideWhistle))
                        {
                            channel = 1;
                        }
                        else
                        {
                            continue;
                        }

                        var element = SoundElement.CreateLoopSignal(startOffset, volume, balance, filePath, channel);
                        slideElements.Add(element);
                    }

                    // change sample (will optimize if only adjust volume) by inherit timing point
                    var timingsOnSlider = _osuFile.TimingPoints.TimingList
                                          .Where(k => k.Offset > startOffset && k.Offset < endOffset)
                                          .ToList();

                    for (var i = 0; i < timingsOnSlider.Count; i++)
                    {
                        var timing     = timingsOnSlider[i];
                        var prevTiming = i == 0 ? timingPoint : timingsOnSlider[i - 1];
                        if (timing.Track != prevTiming.Track ||
                            timing.TimingSampleset != prevTiming.TimingSampleset)
                        {
                            volume = GetObjectVolume(obj, timing);
                            tuples = AnalyzeHitsoundFiles(
                                obj.Hitsound & HitsoundType.SlideWhistle | HitsoundType.Slide,
                                obj.SampleSet, obj.AdditionSet,
                                timing, obj, waves);
                            foreach (var(filePath, hitsoundType) in tuples)
                            {
                                SoundElement element;
                                if (hitsoundType.HasFlag(HitsoundType.Slide) && slideElements
                                    .Last(k => k.PlaybackType == PlaybackType.Loop)
                                    .FilePath == filePath)
                                {
                                    // optimize by only change volume
                                    element = SoundElement.CreateLoopVolumeSignal(timing.Offset, volume);
                                }
                                else
                                {
                                    int channel;
                                    if (hitsoundType.HasFlag(HitsoundType.Slide))
                                    {
                                        channel = 0;
                                    }
                                    else if (hitsoundType.HasFlag(HitsoundType.SlideWhistle))
                                    {
                                        channel = 1;
                                    }
                                    else
                                    {
                                        continue;
                                    }

                                    // new sample
                                    element = SoundElement.CreateLoopSignal(timing.Offset, volume, balance,
                                                                            filePath, channel);
                                }

                                slideElements.Add(element);
                            }

                            continue;
                        }

                        // optimize useless timing point
                        timingsOnSlider.RemoveAt(i);
                        i--;
                    }

                    // end slide
                    var stopElement  = SoundElement.CreateLoopStopSignal(endOffset, 0);
                    var stopElement2 = SoundElement.CreateLoopStopSignal(endOffset, 1);
                    slideElements.Add(stopElement);
                    slideElements.Add(stopElement2);
                    foreach (var slideElement in slideElements)
                    {
                        elements.Add(slideElement);
                    }
                }

                // change balance while sliding (not supported in original game)
                var trails = obj.SliderInfo.BallTrail;
                var all    = trails
                             .Select(k => new
                {
                    offset  = k.Offset,
                    balance = GetObjectBalance(k.Point.X)
                })
                             .Select(k => SoundElement.CreateLoopBalanceSignal(k.offset, k.balance));
                foreach (var balanceElement in all)
                {
                    elements.Add(balanceElement);
                }
            }

            await Task.CompletedTask;
        }