예제 #1
0
        public ITask CreateDecodeSsq()
        {
            return(Build("Decode SSQ", task =>
            {
                var files = GetInputFiles(task);
                if (!files.Any())
                {
                    task.Message = "No input files.";
                    return false;
                }

                ParallelProgress(task, files, file =>
                {
                    using (var inFile = OpenRead(task, file))
                    {
                        var chunks = _ssqStreamReader.Read(inFile);
                        var charts = _ssqDecoder.Decode(chunks);
                        var aggregatedInfo = _metadataAggregator.Aggregate(charts);
                        var title = Path.GetFileNameWithoutExtension(file.Name);
                        var globalOffset = Args.Options.ContainsKey("-offset")
                            ? BigRationalParser.ParseString(Args.Options["-offset"].FirstOrDefault() ?? "0")
                            : BigRational.Zero;

                        // This is a temporary hack to make building sets easier for right now
                        // TODO: make this optional via command line switch
                        if (title.EndsWith("_all", StringComparison.InvariantCultureIgnoreCase))
                        {
                            title = title.Substring(0, title.Length - 4);
                        }

                        var encoded = _smEncoder.Encode(new ChartSet
                        {
                            Metadata = new Metadata
                            {
                                [StringData.Title] = aggregatedInfo[StringData.Title] ?? title,
                                [StringData.Subtitle] = aggregatedInfo[StringData.Subtitle],
                                [StringData.Artist] = aggregatedInfo[StringData.Artist],
                                [ChartTag.MusicTag] = aggregatedInfo[StringData.Music] ?? $"{title}.ogg",
                                [ChartTag.PreviewTag] = aggregatedInfo[StringData.Music] ?? $"{title}-preview.ogg",
                                [ChartTag.OffsetTag] = $"{(decimal) (-aggregatedInfo[NumericData.LinearOffset] + globalOffset)}"
                            },
                            Charts = charts
                        });

                        using (var outFile = OpenWriteSingle(task, file, i => $"{i}.sm"))
                        {
                            _smStreamWriter.Write(outFile, encoded);
                            outFile.Flush();
                        }
                    }
                });

                return true;
            }));
        }
예제 #2
0
 private void AddSingularMetadata(IMetadata chart, IList <BmsCommand> commandList,
                                  IDictionary <string, NumericData> metadataMap)
 {
     foreach (var kv in metadataMap)
     {
         var command = commandList
                       .LastOrDefault(c => kv.Key.Equals(c.Name, StringComparison.InvariantCultureIgnoreCase));
         if (command != null)
         {
             chart[kv.Value] = BigRationalParser.ParseString(command.Value);
         }
     }
 }
예제 #3
0
        public ITask CreateDecodeStep1()
        {
            return(Build("Decode STEP", task =>
            {
                var inputFiles = GetInputFiles(task);
                if (!inputFiles.Any())
                {
                    task.Message = "No input files.";
                    return false;
                }

                foreach (var inputFile in inputFiles)
                {
                    using (var inFile = OpenRead(task, inputFile))
                    {
                        var chunks = _step1StreamReader.Read(inFile);
                        var charts = _step1Decoder.Decode(chunks);
                        var aggregatedInfo = _metadataAggregator.Aggregate(charts);
                        var title = aggregatedInfo[StringData.Title] ?? Path.GetFileNameWithoutExtension(inputFile.Name);
                        var globalOffset = Args.Options.ContainsKey("-offset")
                            ? BigRationalParser.ParseString(Args.Options["-offset"].FirstOrDefault() ?? "0")
                            : BigRational.Zero;
                        var encoded = _smEncoder.Encode(new ChartSet
                        {
                            Metadata = new Metadata
                            {
                                [StringData.Title] = title,
                                [StringData.Subtitle] = aggregatedInfo[StringData.Subtitle],
                                [StringData.Artist] = aggregatedInfo[StringData.Artist],
                                [ChartTag.MusicTag] = aggregatedInfo[StringData.Music] ?? $"{title}.ogg",
                                [ChartTag.PreviewTag] = aggregatedInfo[StringData.Music] ?? $"{title}-preview.ogg",
                                [ChartTag.OffsetTag] = $"{(decimal) (-aggregatedInfo[NumericData.LinearOffset] + globalOffset)}"
                            },
                            Charts = charts
                        });

                        using (var outFile = OpenWriteSingle(task, inputFile, i => $"{i}.sm"))
                        {
                            _smStreamWriter.Write(outFile, encoded);
                            outFile.Flush();
                        }
                    }
                }

                return true;
            }));
        }
예제 #4
0
        public void AdjustGapForFolder(string path, double amount)
        {
            var smReader = Resolve <ISmStreamReader>();
            var smWriter = Resolve <ISmStreamWriter>();

            var files = Directory.GetFiles(path, "*.sm", SearchOption.AllDirectories);

            foreach (var file in files)
            {
                IList <Command> commands;
                using (var stream = File.OpenRead(file))
                    commands = smReader.Read(stream).ToList();

                foreach (var offsetCommand in commands.Where(c =>
                                                             c.Name.Equals("offset", StringComparison.OrdinalIgnoreCase)))
                {
                    var value = offsetCommand.Values.SingleOrDefault();
                    if (value == null)
                    {
                        offsetCommand.Values.Add($"{amount}");
                    }
                    else if (value == string.Empty)
                    {
                        offsetCommand.Values[0] = $"{amount}";
                    }
                    else
                    {
                        var numValue = BigRationalParser.ParseString(offsetCommand.Values.Single());
                        numValue += amount;
                        offsetCommand.Values[0] = $"{(double) numValue}";
                    }
                }

                using (var stream = File.Open(file, FileMode.Create, FileAccess.Write))
                {
                    smWriter.Write(stream, commands);
                    stream.Flush();
                }
            }
        }
예제 #5
0
        private (Dictionary <int, BigRational> Map, IList <BmsCommand> Commands) GetNumericMap(
            IEnumerable <BmsCommand> commands, string mapName)
        {
            var map = new Dictionary <int, BigRational>();
            var processedCommands = new List <BmsCommand>();

            foreach (var command in commands
                     .Where(c => c.Value != null &&
                            !c.Name.Equals(mapName, StringComparison.InvariantCultureIgnoreCase) &&
                            c.Name.StartsWith(mapName, StringComparison.InvariantCultureIgnoreCase)))
            {
                var index = Alphabet.DecodeAlphanumeric(command.Name.AsSpan(mapName.Length));
                var bpm   = BigRationalParser.ParseString(command.Value);
                if (bpm != null)
                {
                    map[index] = bpm.Value;
                }
                processedCommands.Add(command);
            }

            return(map, processedCommands);
        }
예제 #6
0
        public BmsChart Decode(IEnumerable <BmsCommand> commands)
        {
            var commandList = commands.AsList();
            var chart       = new Chart
            {
                Events = GetEvents(commandList).ToList()
            };

            var initialBpm = chart.Events
                             .Where(c => c[NumericData.MetricOffset] == 0 && c[NumericData.Bpm] != null)
                             .Select(c => c[NumericData.Bpm])
                             .FirstOrDefault();

            if (initialBpm == null)
            {
                initialBpm = commandList.Where(c => "bpm".Equals(c.Name, StringComparison.OrdinalIgnoreCase))
                             .Select(c => BigRationalParser.ParseString(c.Value))
                             .First();

                if (initialBpm != null)
                {
                    chart.Events.Add(new Event {
                        [NumericData.Bpm] = initialBpm, [NumericData.MetricOffset] = 0
                    });
                }
            }

            AddSingularMetadata(chart, commandList, SingularNumericTags);
            AddSingularMetadata(chart, commandList, SingularStringTags);
            AddMultiMetadata(chart, commandList, MultiStringTags);

            return(new BmsChart
            {
                Chart = chart,
                SoundMap = GetStringMap(commandList, "WAV").Map
            });
        }
예제 #7
0
        private IEnumerable <IEvent> GetMeasureEvents(BmsCommand command, IDictionary <int, BigRational> bpmMap)
        {
            var measure = Alphabet.DecodeNumeric(command.Name.AsSpan(0, 3));
            var lane    = Alphabet.DecodeHex(command.Name.AsSpan(3, 2));

            switch (lane)
            {
            case 0x02:
            {
                return(new[]
                    {
                        new Event
                        {
                            [NumericData.MeasureLength] = BigRationalParser.ParseString(command.Value),
                            [NumericData.MetricOffset] = measure
                        }
                    });
            }
            }

            var events = new List <Event>();
            var total  = command.Value.Length / 2;

            for (var index = 0; index < total; index++)
            {
                var valueMemory = command.Value.AsMemory(index << 1, 2);
                var value       = valueMemory.Span;
                if (value[0] == '0' && value[1] == '0')
                {
                    continue;
                }

                void AddEvent(Event ev)
                {
                    ev[NumericData.MetricOffset] = new BigRational(new BigInteger(measure), new BigInteger(index),
                                                                   new BigInteger(total));
                    ev[NumericData.SourceData]    = Alphabet.DecodeAlphanumeric(valueMemory.Span);
                    ev[NumericData.SourceCommand] = lane;
                    events.Add(ev);
                }

                switch (lane)
                {
                case 0x01:
                {
                    AddEvent(new Event
                        {
                            [NumericData.PlaySound] = Alphabet.DecodeAlphanumeric(value)
                        });
                    break;
                }

                case 0x03:
                {
                    AddEvent(new Event
                        {
                            [NumericData.Bpm] = Alphabet.DecodeHex(value)
                        });
                    break;
                }

                case 0x04:
                {
                    AddEvent(new Event
                        {
                            [NumericData.BgaBase] = Alphabet.DecodeAlphanumeric(value)
                        });
                    break;
                }

                case 0x05:
                {
                    AddEvent(new Event
                        {
                            [NumericData.BgaObject] = Alphabet.DecodeAlphanumeric(value)
                        });
                    break;
                }

                case 0x06:
                {
                    AddEvent(new Event
                        {
                            [NumericData.BgaPoor] = Alphabet.DecodeAlphanumeric(value)
                        });
                    break;
                }

                case 0x07:
                {
                    AddEvent(new Event
                        {
                            [NumericData.BgaLayer] = Alphabet.DecodeAlphanumeric(value)
                        });
                    break;
                }

                case 0x08:
                {
                    var number = Alphabet.DecodeAlphanumeric(value);
                    if (bpmMap.ContainsKey(number))
                    {
                        AddEvent(new Event
                            {
                                [NumericData.Bpm] = bpmMap[number]
                            });
                    }

                    break;
                }

                case 0x11:
                case 0x12:
                case 0x13:
                case 0x14:
                case 0x15:
                case 0x21:
                case 0x22:
                case 0x23:
                case 0x24:
                case 0x25:
                {
                    AddEvent(new Event
                        {
                            [NumericData.Player] = (lane & 0x20) >> 5,
                            [FlagData.Note]      = true,
                            [NumericData.Column] = lane & 0x0F
                        });
                    break;
                }

                case 0x18:
                case 0x19:
                case 0x28:
                case 0x29:
                {
                    AddEvent(new Event
                        {
                            [NumericData.Player] = (lane & 0x20) >> 5,
                            [FlagData.Note]      = true,
                            [NumericData.Column] = (lane & 0x0F) - 2
                        });
                    break;
                }

                case 0x16:
                case 0x26:
                {
                    AddEvent(new Event
                        {
                            [NumericData.Player] = (lane & 0x20) >> 5,
                            [FlagData.Scratch]   = true,
                            [FlagData.Note]      = true
                        });
                    break;
                }

                case 0x17:
                case 0x27:
                {
                    AddEvent(new Event
                        {
                            [NumericData.Player] = (lane & 0x20) >> 5,
                            [FlagData.FreeZone]  = true,
                            [FlagData.Note]      = true
                        });
                    break;
                }

                case 0x31:
                case 0x32:
                case 0x33:
                case 0x34:
                case 0x35:
                case 0x41:
                case 0x42:
                case 0x43:
                case 0x44:
                case 0x45:
                {
                    AddEvent(new Event
                        {
                            [NumericData.Player]    = (lane & 0x20) >> 5,
                            [NumericData.Column]    = lane & 0x0F,
                            [NumericData.LoadSound] = Alphabet.DecodeAlphanumeric(value)
                        });
                    break;
                }

                case 0x38:
                case 0x39:
                case 0x48:
                case 0x49:
                {
                    AddEvent(new Event
                        {
                            [NumericData.Player]    = (lane & 0x20) >> 5,
                            [NumericData.Column]    = (lane & 0x0F) - 2,
                            [NumericData.LoadSound] = Alphabet.DecodeAlphanumeric(value)
                        });
                    break;
                }

                case 0x36:
                case 0x37:
                case 0x46:
                case 0x47:
                {
                    AddEvent(new Event
                        {
                            [NumericData.Player]    = (lane & 0x20) >> 5,
                            [FlagData.Scratch]      = true,
                            [NumericData.LoadSound] = Alphabet.DecodeAlphanumeric(value)
                        });
                    break;
                }
                }
            }

            return(events);
        }
        public ITask CreateDecode1()
        {
            return(Build("Decode 1", task =>
            {
                var rate = new BigRational(1000, 1);
                var files = GetInputFiles(task);
                if (!files.Any())
                {
                    task.Message = "No input files.";
                    return false;
                }

                if (Args.Options.ContainsKey("rate"))
                {
                    rate = BigRationalParser.ParseString(Args.Options["rate"].Last())
                           ?? throw new RhythmCodexException($"Invalid rate.");
                }

                ParallelProgress(task, files, file =>
                {
                    using (var stream = OpenRead(task, file))
                    {
                        var charts = _beatmaniaPc1StreamReader.Read(stream, stream.Length).ToList();
                        var decoded = charts.Select(c =>
                        {
                            var newChart = _beatmaniaPc1ChartDecoder.Decode(c.Data, rate);
                            newChart[NumericData.Id] = c.Index;

                            switch (c.Index)
                            {
                            case 0:
                            case 6:
                                {
                                    newChart[NumericData.Difficulty] = BeatmaniaDifficultyConstants.NormalId;
                                    break;
                                }

                            case 1:
                            case 7:
                                {
                                    newChart[NumericData.Difficulty] = BeatmaniaDifficultyConstants.LightId;
                                    break;
                                }

                            case 2:
                            case 8:
                                {
                                    newChart[NumericData.Difficulty] = BeatmaniaDifficultyConstants.AnotherId;
                                    break;
                                }

                            case 3:
                            case 9:
                                {
                                    newChart[NumericData.Difficulty] = BeatmaniaDifficultyConstants.BeginnerId;
                                    break;
                                }
                            }

                            newChart[StringData.Title] = Path.GetFileNameWithoutExtension(file.Name);
                            return newChart;
                        }).ToList();

                        if (!EnableExportingCharts)
                        {
                            return;
                        }

                        foreach (var chart in decoded)
                        {
                            chart.PopulateMetricOffsets();
                            var encoded = _bmsEncoder.Encode(chart);
                            using (var outStream =
                                       OpenWriteMulti(task, file,
                                                      i => $"{Alphabet.EncodeNumeric((int) chart[NumericData.Id], 2)}.bme"))
                            {
                                _bmsStreamWriter.Write(outStream, encoded);
                            }
                        }
                    }
                });

                return true;
            }));
        }