Beispiel #1
0
        public void Export(Stream stream)
        {
            var     book  = ScoreBook;
            SusArgs args  = CustomArgs;
            var     notes = book.Score.Notes;

            using (var writer = new StreamWriter(stream))
            {
                writer.WriteLine("This file was generated by Ched {0}.", System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString());

                writer.WriteLine("#TITLE \"{0}\"", book.Title);
                writer.WriteLine("#ARTIST \"{0}\"", book.ArtistName);
                writer.WriteLine("#DESIGNER \"{0}\"", book.NotesDesignerName);
                writer.WriteLine("#DIFFICULTY {0}", (int)args.PlayDifficulty + (string.IsNullOrEmpty(args.ExtendedDifficulty) ? "" : ":" + args.ExtendedDifficulty));
                writer.WriteLine("#PLAYLEVEL {0}", args.PlayLevel);
                writer.WriteLine("#SONGID \"{0}\"", args.SongId);
                writer.WriteLine("#WAVE \"{0}\"", args.SoundFileName);
                writer.WriteLine("#WAVEOFFSET {0}", args.SoundOffset);
                writer.WriteLine("#JACKET \"{0}\"", args.JacketFilePath);
                writer.WriteLine();

                if (!string.IsNullOrEmpty(args.AdditionalData))
                {
                    writer.WriteLine(args.AdditionalData);
                    writer.WriteLine();
                }

                writer.WriteLine("#REQUEST \"ticks_per_beat {0}\"", book.Score.TicksPerBeat);
                writer.WriteLine();

                var timeSignatures = BarIndexCalculator.TimeSignatures.Select(p => new SusDataLine(p.StartBarIndex, barIndex => string.Format("#{0:000}02: {1}", barIndex, 4f * p.TimeSignature.Numerator / p.TimeSignature.Denominator), p.StartBarIndex == 0));
                WriteLinesWithOffset(writer, timeSignatures);
                writer.WriteLine();

                var bpmlist = book.Score.Events.BpmChangeEvents
                              .GroupBy(p => p.Bpm)
                              .SelectMany((p, i) => p.Select(q => new { Index = i, Value = q, BarPosition = BarIndexCalculator.GetBarPositionFromTick(q.Tick) }))
                              .ToList();

                if (bpmlist.Count >= 36 * 36)
                {
                    throw new ArgumentException("BPM定義数が上限を超えました。");
                }

                var bpmIdentifiers = EnumerateIdentifiers(2, NumChars.Concat(AlphaChars)).Skip(1).Take(bpmlist.Count).ToList();
                foreach (var item in bpmlist.GroupBy(p => p.Index).Select(p => p.First()))
                {
                    writer.WriteLine("#BPM{0}: {1}", bpmIdentifiers[item.Index], item.Value.Bpm);
                }

                // 小節オフセット追加用に初期BPM定義だけ1行に分離
                var bpmChanges = bpmlist.GroupBy(p => p.Value.Tick == 0).SelectMany(p => p.GroupBy(q => q.BarPosition.BarIndex).Select(eventInBar =>
                {
                    var sig       = BarIndexCalculator.GetTimeSignatureFromBarIndex(eventInBar.Key);
                    int barLength = StandardBarTick * sig.Numerator / sig.Denominator;
                    var items     = eventInBar.Select(q => (q.BarPosition.TickOffset, bpmIdentifiers[q.Index]));
                    return(new SusDataLine(eventInBar.Key, barIndex => string.Format("#{0:000}08: {1}", barIndex, GenerateLineData(barLength, items)), p.Key));
                }));
                WriteLinesWithOffset(writer, bpmChanges);
                writer.WriteLine();

                var speeds = book.Score.Events.HighSpeedChangeEvents.Select(p =>
                {
                    var barPos = BarIndexCalculator.GetBarPositionFromTick(p.Tick);
                    return(string.Format("{0}'{1}:{2}", barPos.BarIndex + (p.Tick == 0 ? 0 : BarIndexOffset), barPos.TickOffset, p.SpeedRatio));
                });
                writer.WriteLine("#TIL00: \"{0}\"", string.Join(", ", speeds));
                writer.WriteLine("#HISPEED 00");
                writer.WriteLine("#MEASUREHS 00");
                writer.WriteLine();

                var shortNotes = notes.Taps.Cast <TappableBase>().Select(p => new { Type = '1', Note = p })
                                 .Concat(notes.ExTaps.Cast <TappableBase>().Select(p => new { Type = '2', Note = p }))
                                 .Concat(notes.Flicks.Cast <TappableBase>().Select(p => new { Type = '3', Note = p }))
                                 .Concat(notes.Damages.Cast <TappableBase>().Select(p => new { Type = '4', Note = p }))
                                 .Select(p => (p.Note.Tick, p.Note.LaneIndex, p.Type + ToLaneWidthString(p.Note.Width)));
                WriteLinesWithOffset(writer, GetShortNoteLines("1", shortNotes));
                writer.WriteLine();

                var airs = notes.Airs.Select(p =>
                {
                    string type = "";
                    switch (p.HorizontalDirection)
                    {
                    case HorizontalAirDirection.Center:
                        type = p.VerticalDirection == VerticalAirDirection.Up ? "1" : "2";
                        break;

                    case HorizontalAirDirection.Left:
                        type = p.VerticalDirection == VerticalAirDirection.Up ? "3" : "5";
                        break;

                    case HorizontalAirDirection.Right:
                        type = p.VerticalDirection == VerticalAirDirection.Up ? "4" : "6";
                        break;
                    }

                    return(p.Tick, p.LaneIndex, type + ToLaneWidthString(p.Width));
                });
                WriteLinesWithOffset(writer, GetShortNoteLines("5", airs));
                writer.WriteLine();

                var identifier = new IdentifierAllocationManager();

                var holds = book.Score.Notes.Holds
                            .OrderBy(p => p.StartTick)
                            .Select(p => new
                {
                    Identifier = identifier.Allocate(p.StartTick, p.Duration),
                    StartTick  = p.StartTick,
                    EndTick    = p.StartTick + p.Duration,
                    Width      = p.Width,
                    LaneIndex  = p.LaneIndex
                })
                            .SelectMany(hold =>
                {
                    var items = new[]
                    {
                        (hold.StartTick, hold.LaneIndex, "1" + ToLaneWidthString(hold.Width)),
                        (hold.EndTick, hold.LaneIndex, "2" + ToLaneWidthString(hold.Width))
                    };
                    return(GetLongNoteLines("2", hold.Identifier.ToString(), items));
                });
Beispiel #2
0
 public SusExporter(ScoreBook book, SusArgs susArgs)
 {
     ScoreBook          = book;
     CustomArgs         = susArgs;
     BarIndexCalculator = new BarIndexCalculator(book.Score.TicksPerBeat, book.Score.Events.TimeSignatureChangeEvents);
 }