예제 #1
0
        public HitObject(string[] anArgs, Beatmap aBeatmap)
        {
            beatmap = aBeatmap;
            code    = String.Join(",", anArgs);

            Position = GetPosition(anArgs);

            time     = GetTime(anArgs);
            type     = GetTypeFlags(anArgs);
            hitSound = GetHitSound(anArgs);

            // extras
            Tuple <Beatmap.Sampleset, Beatmap.Sampleset, int?, int?, string> extras = GetExtras(anArgs);

            if (extras != null)
            {
                // custom index and volume are by default 0 if there are edge hitsounds or similar
                sampleset   = extras.Item1;
                addition    = extras.Item2;
                customIndex = extras.Item3 == 0 ? null : extras.Item3;
                volume      = extras.Item4 == 0 ? null : extras.Item4;

                // hitsound filenames only apply to circles and hold notes
                string hitSoundFile = extras.Item5;
                if (hitSoundFile.Trim() != "" && (type.HasFlag(Type.Circle) || type.HasFlag(Type.ManiaHoldNote)))
                {
                    filename = PathStatic.ParsePath(hitSoundFile);
                }
            }
        }
예제 #2
0
        private Tuple <Beatmap.Sampleset, Beatmap.Sampleset, int?, int?, string> GetExtras(string[] args)
        {
            string extras = args.Last();

            // Hold notes have "endTime:extras" as format.
            int index = HasType(Type.ManiaHoldNote) ? 1 : 0;

            if (extras.Contains(":"))
            {
                Beatmap.Sampleset samplesetValue = (Beatmap.Sampleset) int.Parse(extras.Split(':')[index]);
                Beatmap.Sampleset additionsValue = (Beatmap.Sampleset) int.Parse(extras.Split(':')[index + 1]);
                int?customIndexValue             = int.Parse(extras.Split(':')[index + 2]);

                // Does not exist in file v11.
                int?volumeValue = null;
                if (extras.Split(':').Count() > index + 3)
                {
                    volumeValue = int.Parse(extras.Split(':')[index + 3]);
                }

                string filenameValue = "";
                if (extras.Split(':').Count() > index + 4)
                {
                    filenameValue = extras.Split(':')[index + 4];
                }

                return(Tuple.Create(samplesetValue, additionsValue, customIndexValue, volumeValue, filenameValue));
            }
            return(null);
        }
예제 #3
0
        public Slider(string[] anArgs, Beatmap aBeatmap)
            : base(anArgs, aBeatmap)
        {
            curveType     = GetSliderType(anArgs);
            nodePositions = GetNodes(anArgs).ToList();
            edgeAmount    = GetEdgeAmount(anArgs);
            pixelLength   = GetPixelLength(anArgs);

            // hit sounding
            var edgeHitSounds = GetEdgeHitSounds(anArgs);
            var edgeAdditions = GetEdgeAdditions(anArgs);

            startHitSound  = edgeHitSounds.Item1;
            startSampleset = edgeAdditions.Item1;
            startAddition  = edgeAdditions.Item2;

            endHitSound  = edgeHitSounds.Item2;
            endSampleset = edgeAdditions.Item3;
            endAddition  = edgeAdditions.Item4;

            reverseHitSounds  = edgeHitSounds.Item3.ToList();
            reverseSamplesets = edgeAdditions.Item5.ToList();
            reverseAdditions  = edgeAdditions.Item6.ToList();

            // non-explicit
            if (beatmap != null)
            {
                redAnchorPositions = GetRedAnchors().ToList();
                pathPxPositions    = GetPathPxPositions();
                endTime            = GetEndTime();
                sliderTickTimes    = GetSliderTickTimes();

                UnstackedEndPosition = edgeAmount % 2 == 1 ? pathPxPositions.Last() : UnstackedPosition;
            }
        }
예제 #4
0
        public TimingLine(string[] anArgs)
        {
            code = String.Join(",", anArgs);

            offset      = GetOffset(anArgs);
            meter       = GetMeter(anArgs);
            sampleset   = GetSampleset(anArgs);
            customIndex = GetCustomIndex(anArgs);
            volume      = GetVolume(anArgs);
            uninherited = IsUninherited(anArgs);

            type         = GetType(anArgs);
            kiai         = type.HasFlag(Type.Kiai);
            omitsBarLine = type.HasFlag(Type.OmitBarLine);

            // may not be explicit
            svMult = GetSvMult(anArgs);
        }
예제 #5
0
                       IEnumerable <Beatmap.Sampleset>, IEnumerable <Beatmap.Sampleset> > GetEdgeAdditions(string[] anArgs)
        {
            Beatmap.Sampleset edgeStartSampleset = 0;
            Beatmap.Sampleset edgeStartAddition  = 0;

            Beatmap.Sampleset edgeEndSampleset = 0;
            Beatmap.Sampleset edgeEndAddition  = 0;

            IEnumerable <Beatmap.Sampleset> edgeReverseSamplesets = new List <Beatmap.Sampleset>();
            IEnumerable <Beatmap.Sampleset> edgeReverseAdditions  = new List <Beatmap.Sampleset>();

            if (anArgs.Count() > 9)
            {
                string edgeAdditions = anArgs[9];

                // not set in some situations
                if (edgeAdditions.Contains("|"))
                {
                    for (int i = 0; i < edgeAdditions.Split('|').Length; ++i)
                    {
                        Beatmap.Sampleset sampleset = (Beatmap.Sampleset) int.Parse(edgeAdditions.Split('|')[i].Split(':')[0]);
                        Beatmap.Sampleset addition  = (Beatmap.Sampleset) int.Parse(edgeAdditions.Split('|')[i].Split(':')[1]);

                        if (i == 0)
                        {
                            edgeStartSampleset = sampleset;
                            edgeStartAddition  = addition;
                        }
                        else if (i == edgeAdditions.Split('|').Length - 1)
                        {
                            edgeEndSampleset = sampleset;
                            edgeEndAddition  = addition;
                        }
                        else
                        {
                            edgeReverseSamplesets = edgeReverseSamplesets.Concat(new Beatmap.Sampleset[] { sampleset });
                            edgeReverseAdditions  = edgeReverseAdditions.Concat(new Beatmap.Sampleset[] { sampleset });
                        }
                    }
                }
            }

            return(Tuple.Create(edgeStartSampleset, edgeStartAddition, edgeEndSampleset, edgeEndAddition, edgeReverseSamplesets, edgeReverseAdditions));
        }
예제 #6
0
        public HitObject(string[] args, Beatmap beatmap)
        {
            this.beatmap = beatmap;
            code         = String.Join(",", args);

            Position = GetPosition(args);

            time     = GetTime(args);
            type     = GetTypeFlags(args);
            hitSound = GetHitSound(args);

            // extras
            Tuple <Beatmap.Sampleset, Beatmap.Sampleset, int?, int?, string> extras = GetExtras(args);

            if (extras != null)
            {
                // custom index and volume are by default 0 if there are edge hitsounds or similar
                sampleset   = extras.Item1;
                addition    = extras.Item2;
                customIndex = extras.Item3 == 0 ? null : extras.Item3;
                volume      = extras.Item4 == 0 ? null : extras.Item4;

                // hitsound filenames only apply to circles and hold notes
                string hitSoundFile = extras.Item5;
                if (hitSoundFile.Trim() != "" && (HasType(Type.Circle) || HasType(Type.ManiaHoldNote)))
                {
                    filename = PathStatic.ParsePath(hitSoundFile, false, true);
                }
            }

            // Sliders and spinners include additional edges which support hit sounding, so we
            // should handle that after those edges are initialized in Slider/Spinner instead.
            if (!(this is Slider) && !(this is Spinner))
            {
                usedHitSamples = GetUsedHitSamples().ToList();
            }
        }
예제 #7
0
        /// <summary> Returns all used combinations of customs, samplesets and hit sounds for this object.
        /// This assumes the game mode is not taiko (special rules apply to taiko only). </summary>
        private IEnumerable <HitSample> GetUsedHitSamplesNonTaiko()
        {
            // Spinners have no impact sound.
            if (!(this is Spinner))
            {
                // Head
                foreach (HitSound splitStartHitSound in SplitHitSound(GetStartHitSound().GetValueOrDefault()))
                {
                    yield return(GetEdgeSample(time, GetStartSampleset(true), splitStartHitSound));
                }
                yield return(GetEdgeSample(time, GetStartSampleset(false), HitSound.Normal));
            }

            // Hold notes can not have a hit sounds on their tails.
            if (!(this is HoldNote))
            {
                // Tail
                foreach (HitSound splitEndHitSound in SplitHitSound(GetEndHitSound().GetValueOrDefault()))
                {
                    yield return(GetEdgeSample(GetEndTime(), GetEndSampleset(true), splitEndHitSound));
                }
                yield return(GetEdgeSample(GetEndTime(), GetEndSampleset(false), HitSound.Normal));
            }

            if (this is Slider slider)
            {
                // Reverse
                for (int i = 0; i < slider.reverseHitSounds.Count; ++i)
                {
                    HitSound?reverseHitSound = slider.reverseHitSounds.ElementAt(i);

                    double theoreticalStart = time - beatmap.GetTheoreticalUnsnap(time);
                    double reverseTime      = Timestamp.Round(theoreticalStart + slider.GetCurveDuration() * (i + 1));

                    foreach (HitSound splitReverseHitSound in SplitHitSound(reverseHitSound.GetValueOrDefault()))
                    {
                        yield return(GetEdgeSample(reverseTime, slider.GetReverseSampleset(i, true), splitReverseHitSound));
                    }
                    yield return(GetEdgeSample(reverseTime, slider.GetReverseSampleset(i), HitSound.Normal));
                }

                List <TimingLine> lines =
                    beatmap.timingLines.Where(line =>
                                              line.offset > slider.time &&
                                              line.offset <= slider.endTime).ToList();
                lines.Add(beatmap.GetTimingLine(slider.time, hitSoundLeniency: true));

                // Body, only applies to standard. Catch has droplets instead of body. Taiko and mania have a body but play no background sound.
                if (beatmap.generalSettings.mode == Beatmap.Mode.Standard)
                {
                    foreach (TimingLine line in lines)
                    {
                        // Priority: object sampleset > line sampleset
                        // The addition is ignored for sliderslides, it seems.
                        Beatmap.Sampleset effectiveSampleset =
                            sampleset != Beatmap.Sampleset.Auto ?
                            sampleset :
                            line.sampleset;

                        // Additions are not ignored for sliderwhistles, however.
                        if (slider.hitSound == HitSound.Whistle)
                        {
                            effectiveSampleset = addition != Beatmap.Sampleset.Auto ? addition : effectiveSampleset;
                        }

                        // The regular sliderslide will always play regardless of using sliderwhistle.
                        yield return(new HitSample(
                                         line.customIndex,
                                         effectiveSampleset,
                                         HitSound.None,
                                         HitSample.HitSource.Body,
                                         line.offset));

                        if (hitSound != HitSound.None)
                        {
                            yield return(new HitSample(
                                             line.customIndex,
                                             effectiveSampleset,
                                             hitSound,
                                             HitSample.HitSource.Body,
                                             line.offset));
                        }
                    }
                }

                // Tick, only applies to standard and catch. Mania has no ticks, taiko sliders play regular impacts.
                if (beatmap.generalSettings.mode == Beatmap.Mode.Standard ||
                    beatmap.generalSettings.mode == Beatmap.Mode.Catch)
                {
                    foreach (double tickTime in slider.sliderTickTimes)
                    {
                        TimingLine line = beatmap.GetTimingLine(tickTime);

                        // If no line exists, we use the default settings.
                        int customIndex = line?.customIndex ?? 1;

                        // Unlike the slider body (for sliderwhistles) and edges, slider ticks are unaffected by additions.
                        Beatmap.Sampleset sampleset = GetSampleset(false, tickTime);

                        // Defaults to normal if none is set (before any timing line).
                        if (sampleset == Beatmap.Sampleset.Auto)
                        {
                            sampleset = Beatmap.Sampleset.Normal;
                        }

                        yield return(new HitSample(customIndex, sampleset, null, HitSample.HitSource.Tick, tickTime));
                    }
                }
            }
        }
예제 #8
0
        /// <summary> Returns all used combinations of customs, samplesets and hit sounds for this object. </summary>
        public IEnumerable <HitSample> GetUsedHitSamples()
        {
            // Head
            foreach (HitSound splitStartHitSound in SplitHitSound(GetStartHitSound().GetValueOrDefault()))
            {
                yield return(GetEdgeSample(time, GetStartSampleset(true), splitStartHitSound));
            }
            yield return(GetEdgeSample(time, GetStartSampleset(false), HitSound.Normal));

            // Hold notes can not have a hit sounds on their tails.
            if (!(this is HoldNote))
            {
                // Tail
                foreach (HitSound splitEndHitSound in SplitHitSound(GetEndHitSound().GetValueOrDefault()))
                {
                    yield return(GetEdgeSample(GetEndTime(), GetEndSampleset(true), splitEndHitSound));
                }
                yield return(GetEdgeSample(GetEndTime(), GetEndSampleset(false), HitSound.Normal));
            }

            if (this is Slider slider)
            {
                // Reverse
                for (int i = 0; i < slider.reverseHitSounds.Count; ++i)
                {
                    HitSound?         reverseHitSound  = slider.reverseHitSounds.ElementAt(i);
                    Beatmap.Sampleset?reverseSampleset = slider.GetReverseSampleset(i);
                    Beatmap.Sampleset?reverseAddition  =
                        slider.reverseAdditions.Any() ?   // not a thing in file version 9
                        slider.reverseAdditions.ElementAt(i) :
                        (Beatmap.Sampleset?)null;

                    double reverseTime = slider.GetCurveDuration() * (i + 1);

                    foreach (HitSound splitReverseHitSound in SplitHitSound(reverseHitSound.GetValueOrDefault()))
                    {
                        yield return(GetEdgeSample(reverseTime, reverseAddition ?? reverseSampleset, splitReverseHitSound));
                    }
                    yield return(GetEdgeSample(reverseTime, reverseSampleset, HitSound.Normal));
                }

                List <TimingLine> lines =
                    beatmap.timingLines.Where(aLine =>
                                              aLine.offset > slider.time &&
                                              aLine.offset <= slider.endTime).ToList();
                lines.Add(beatmap.GetTimingLine(slider.time, true));

                // Body
                foreach (TimingLine line in lines)
                {
                    yield return(new HitSample(line.customIndex, line.sampleset, hitSound, HitSample.HitSource.Body, line.offset));
                }

                // Tick
                foreach (double tickTime in slider.sliderTickTimes)
                {
                    TimingLine line = beatmap.GetTimingLine(tickTime);

                    // If no line exists, we use the default settings.
                    int customIndex             = line?.customIndex ?? 1;
                    Beatmap.Sampleset sampleset = GetSampleset(true, tickTime);

                    // Defaults to normal if none is set (before any timing line).
                    if (sampleset == Beatmap.Sampleset.Auto)
                    {
                        sampleset = Beatmap.Sampleset.Normal;
                    }

                    yield return(new HitSample(customIndex, sampleset, null, HitSample.HitSource.Tick, tickTime));
                }
            }
        }
예제 #9
0
                       List <Beatmap.Sampleset>, List <Beatmap.Sampleset> > GetEdgeAdditions(string[] args)
        {
            Beatmap.Sampleset edgeStartSampleset = 0;
            Beatmap.Sampleset edgeStartAddition  = 0;

            Beatmap.Sampleset edgeEndSampleset = 0;
            Beatmap.Sampleset edgeEndAddition  = 0;

            List <Beatmap.Sampleset> edgeReverseSamplesets = new List <Beatmap.Sampleset>();
            List <Beatmap.Sampleset> edgeReverseAdditions  = new List <Beatmap.Sampleset>();

            if (args.Count() > 9)
            {
                // Not set in some situations (e.g. older file versions or no hit sounds).
                string edgeAdditions = args[9];
                if (edgeAdditions.Contains("|"))
                {
                    for (int i = 0; i < edgeAdditions.Split('|').Length; ++i)
                    {
                        Beatmap.Sampleset sampleset = (Beatmap.Sampleset) int.Parse(edgeAdditions.Split('|')[i].Split(':')[0]);
                        Beatmap.Sampleset addition  = (Beatmap.Sampleset) int.Parse(edgeAdditions.Split('|')[i].Split(':')[1]);

                        if (i == 0)
                        {
                            edgeStartSampleset = sampleset;
                            edgeStartAddition  = addition;
                        }
                        else if (i == edgeAdditions.Split('|').Length - 1)
                        {
                            edgeEndSampleset = sampleset;
                            edgeEndAddition  = addition;
                        }
                        else
                        {
                            edgeReverseSamplesets.Add(sampleset);
                            edgeReverseAdditions.Add(addition);
                        }
                    }
                }
            }
            else
            {
                // If an object has no complex hit sounding, it omits fields such as edge
                // hit sounds. Instead, it simply uses one hit sound over everything.
                edgeStartSampleset = sampleset;
                edgeEndSampleset   = sampleset;
                for (int i = 0; i < edgeAmount; ++i)
                {
                    edgeReverseSamplesets.Add(sampleset);
                }

                edgeStartAddition = addition;
                edgeEndAddition   = addition;
                for (int i = 0; i < edgeAmount; ++i)
                {
                    edgeReverseAdditions.Add(addition);
                }
            }

            return(Tuple.Create(edgeStartSampleset, edgeStartAddition, edgeEndSampleset, edgeEndAddition, edgeReverseSamplesets, edgeReverseAdditions));
        }