Пример #1
0
        public override Chart Load(string path)
        {
            BMSChart   data        = new BMSChart(Directory.GetParent(path).FullName);
            BMSMeasure lastMeasure = null;

            bool warnRandom = false;

            using (FileStream fileStream = new FileStream(path, FileMode.Open,
                                                          FileAccess.Read, FileShare.Read, 8192, FileOptions.SequentialScan))
            {
                using (StreamReader stream = new StreamReader(fileStream, System.Text.Encoding.GetEncoding("shift_jis"), true))
                {
                    string line;
                    int    lineNumber = -1;
                    while ((line = stream.ReadLine()) != null)
                    {
                        lineNumber++;

                        string command, value;
                        if (!ParseCommandLine(line, out command, out value))
                        {
                            continue;
                        }

                        if (command.StartsWithFast("WAV"))
                        {
                            OnWAV(data, command, value);
                        }
                        else if (command.StartsWithFast("BMP"))
                        {
                            OnBMP(data, command, value);
                        }
                        else if (command.StartsWithFast("BPM") || command.StartsWithFast("EXBPM"))
                        {
                            OnBPM(data, command, value);
                        }
                        else if (command.StartsWithFast("STOP"))
                        {
                            OnStop(data, command, value);
                        }
                        else if (command.StartsWithFast("LNOBJ"))
                        {
                            OnLongNote(data, command, value);
                        }
                        else if (command == "RANDOM")
                        {
                            warnRandom = true;
                        }
                        else if (command[0] >= '0' && command[0] <= '9')
                        {
                            OnChannel(data, line, ref lastMeasure);
                        }
                        else if (BMSChart.unsupportedObjects.Contains(command))
                        {
                            continue;                             // unsupported command, silently ignored
                        }
                        else
                        {
                            OnHeader(data, command, value);
                        }
                    }
                }
            }

            if (warnRandom)
            {
                Log.Warning("#RANDOM charts are not supported");
            }

            data.measureList.Sort(new Comparison <BMSMeasure>((m1, m2) =>
            {
                return(m1.index > m2.index ? 1 : (m1.index < m2.index ? -1 : 0));
            }));

            // insert empty measures at gaps
            for (int i = 0, skipped = 0; i < data.measureList.Count; i++)
            {
                if (data.measureList[i].index == i + skipped)
                {
                    continue;
                }

                if (skipToFirstMeasure && skipped == 0)
                {
                    skipped = data.measureList[i].index;
                    continue;
                }

                BMSMeasure measure = new BMSMeasure(i + skipped);
                BMSChannel channel = new BMSChannel(1);

                channel.values.Add(0);
                measure.channelList.Add(channel);
                measure.maxLength = 1;

                data.measureList.Insert(i, measure);
            }

            // check against overlapping long and regular notes
            int longNoteType = data.GetHeader <int>("LNTYPE");

            for (int i = 0; i < data.measureList.Count; i++)
            {
                for (int c = (int)BMSChannel.Type.P1KeyFirst; c < (int)BMSChannel.Type.P2KeyLast; ++c)
                {
                    BMSChannel keyChannel = data.measureList[i].GetChannel(c);
                    if (keyChannel == null)
                    {
                        continue;
                    }

                    for (int cl = 0; cl < data.measureList[i].channelList.Count; cl++)
                    {
                        if (data.measureList[i].channelList[cl].index != c + (BMSChannel.Type.P1LongFirst - BMSChannel.Type.P1KeyFirst))
                        {
                            continue;
                        }

                        BMSChannel lnChannel = data.measureList[i].channelList[cl];
                        if (keyChannel.values.Count != lnChannel.values.Count)
                        {
                            int  newLength    = Utility.lcm(keyChannel.values.Count, lnChannel.values.Count);
                            bool lnWorkaround = longNoteType == 2;
                            BMSChannel.NormalizeChannel(keyChannel, newLength, 0);
                            BMSChannel.NormalizeChannel(lnChannel, newLength, lnWorkaround ? -1 : 0);
                        }

                        int lnValue = -1;
                        for (int j = 0; j < keyChannel.values.Count; j++)
                        {
                            if (lnChannel.values[j] != -1)
                            {
                                lnValue = lnChannel.values[j];
                            }
                            else
                            {
                                lnChannel.values[j] = lnValue;
                            }

                            if (keyChannel.values[j] == 0 || lnValue == 0)
                            {
                                continue;
                            }
                            else if (lnValue != 0)
                            {
                                // Both channels have overlapping notes.
                                // Charter probably added both for compatibility reasons
                                // if the client doesn't support long notes.

                                keyChannel.values[j] = 0;
                            }
                        }
                    }
                }
            }

            if (longNoteType != 1)
            {
                Log.Warning("#LNTYPE " + longNoteType.ToString());
            }

            int p1KeyCount = 0;
            int p2KeyCount = 0;

            // merge long note references with regular keys
            List <int> channelKeys = channelRefs.Keys.ToList();

            foreach (int channelIndex in channelKeys)
            {
                if (BMSChannel.IsP1Long(channelIndex) || BMSChannel.IsP2Long(channelIndex))
                {
                    int offset     = BMSChannel.Type.P1LongFirst - BMSChannel.Type.P1KeyFirst;
                    int newChannel = channelIndex - offset;
                    int refs       = channelRefs[channelIndex];

                    if (channelRefs.ContainsKey(newChannel))
                    {
                        channelRefs[newChannel] += refs;
                    }
                    else
                    {
                        channelRefs.Add(newChannel, refs);
                    }
                }
            }

            foreach (var channel in channelRefs)
            {
                if (BMSChannel.IsP1Key(channel.Key))
                {
                    p1KeyCount++;
                }
                else if (BMSChannel.IsP2Key(channel.Key))
                {
                    p2KeyCount++;
                }
            }

            data.playerChannels = Math.Max(p1KeyCount, p2KeyCount);
            if (data.playerChannels != 6 && data.playerChannels != 8 && data.playerChannels != 9)
            {
                // non-standard format or some channels were left empty,
                // fallback to using specific key count based on the file extension.
                int    keyCount  = 0;
                string extension = Path.GetExtension(path).ToLowerInvariant();
                if (extension == ".bms")
                {
                    keyCount = 6;
                }
                else if (extension == ".bme" || extension == ".bml")
                {
                    keyCount = 8;
                }
                else if (extension == ".pms")
                {
                    keyCount = 9;

                    if (p1KeyCount <= 5 && p2KeyCount <= 4)
                    {
                        // actually one player chart
                        p2KeyCount = 0;
                    }
                }

                if (keyCount != 0)
                {
                    if (p1KeyCount > 0)
                    {
                        p1KeyCount = keyCount;
                    }
                    if (p2KeyCount > 0)
                    {
                        p2KeyCount = keyCount;
                    }
                }
            }

            data.playerChannels = Math.Max(p1KeyCount, p2KeyCount);
            data.hasTurntable   = data.playerChannels == 6 || data.playerChannels == 8;

            if (p2KeyCount > 0)
            {
                data.players = 2;
            }
            else if (p1KeyCount > 0)
            {
                data.players = 1;
            }

            // find the most optimal resolution for this chart
            long       resolution    = 1;
            const long maxResolution = long.MaxValue / (1000 * 4);

            try
            {
                foreach (BMSMeasure measure in data.measureList)
                {
                    foreach (BMSChannel channel in measure.channelList)
                    {
                        if (resolution % channel.values.Count != 0)
                        {
                            resolution = Utility.lcm(resolution, channel.values.Count);
                        }
                    }
                }
            }
            catch (ArithmeticException)
            {
                resolution = 0;
            }
            finally
            {
                if (resolution <= 0 || resolution > maxResolution)
                {
                    resolution = maxResolution;
                    Log.Warning("Required object resolution is too high for accurate playback");
                }
            }

            data.resolution_ = resolution;

            return(data);
        }
Пример #2
0
        // maps BMS player channels to lane numbers, first lane is scratch
        public static int GetLaneIndex(int channel, int keyCount, int playerCount)
        {
            int lane = -1;

            // long note
            if (channel >= (int)BMSChannel.Type.P1LongFirst && channel <= (int)BMSChannel.Type.P2LongLast)
            {
                channel -= (int)BMSChannel.Type.P1LongFirst - (int)BMSChannel.Type.P1KeyFirst;
            }

            // landmine
            if (channel >= (int)BMSChannel.Type.P1LandmineFirst && channel <= (int)BMSChannel.Type.P2LandmineLast)
            {
                channel -= (int)BMSChannel.Type.P1LandmineFirst - (int)BMSChannel.Type.P1KeyFirst;
            }

            int offset = 0;

            if (keyCount != 9)
            {
                if (playerCount == 2 && BMSChannel.IsP2Key(channel))
                {
                    offset   = keyCount;
                    channel -= BMSChannel.KeyBMS.P1Key1 - BMSChannel.KeyBMS.P2Key1;
                }

                if (BMSChannel.IsP1Key(channel))
                {
                    if (channel >= (int)BMSChannel.KeyBMS.P1Key1 && channel <= (int)BMSChannel.KeyBMS.P1Key5)
                    {
                        lane = 1 + channel - (int)BMSChannel.KeyBMS.P1Key1;
                    }
                    else if (channel >= (int)BMSChannel.KeyBMS.P1Key6 && channel <= (int)BMSChannel.KeyBMS.P1Key7)
                    {
                        lane = 1 + 5 + channel - (int)BMSChannel.KeyBMS.P1Key6;
                    }
                    else if (channel == (int)BMSChannel.KeyBMS.P1Scratch)
                    {
                        lane = 0;
                    }
                }
            }
            else if (keyCount == 9)
            {
                if (playerCount == 1)
                {
                    if (channel >= (int)BMSChannel.KeyPMS.P1Key1 && channel <= (int)BMSChannel.KeyPMS.P1Key5)
                    {
                        lane = channel - (int)BMSChannel.KeyPMS.P1Key1;
                    }
                    else if (channel >= (int)BMSChannel.KeyPMS.P1Key6 && channel <= (int)BMSChannel.KeyPMS.P1Key9)
                    {
                        lane = 5 + (channel - (int)BMSChannel.KeyPMS.P1Key6);
                    }
                }
                else if (playerCount == 2)
                {
                    if (channel >= (int)BMSChannel.KeyPMS.P2DPKey1)
                    {
                        offset   = 9;
                        channel -= BMSChannel.KeyPMS.P2DPKey1 - BMSChannel.KeyPMS.P1DPKey1;
                    }
                    if (channel >= (int)BMSChannel.KeyPMS.P1DPKey1 && channel <= (int)BMSChannel.KeyPMS.P1DPKey5)
                    {
                        lane = channel - (int)BMSChannel.KeyPMS.P1DPKey1;
                    }
                }

                if (channel == (int)BMSChannel.KeyPMS.P1DPKey6)
                {
                    lane = 5;
                }
                else if (channel == (int)BMSChannel.KeyPMS.P1DPKey7)
                {
                    lane = 6;
                }
                else if (channel == (int)BMSChannel.KeyPMS.P1DPKey8)
                {
                    lane = 7;
                }
                else if (channel == (int)BMSChannel.KeyPMS.P1DPKey9)
                {
                    lane = 8;
                }
            }
            lane += offset;
            return(lane);
        }