public void Export(string path, ScoreBook book) { SusArgs args = CustomArgs; var notes = book.Score.Notes; using (var writer = new StreamWriter(path)) { 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(); writer.WriteLine("#REQUEST \"ticks_per_beat {0}\"", book.Score.TicksPerBeat); writer.WriteLine(); int barTick = book.Score.TicksPerBeat * 4; var barIndexCalculator = new BarIndexCalculator(barTick, book.Score.Events.TimeSignatureChangeEvents, args.HasPaddingBar); foreach (var item in barIndexCalculator.TimeSignatures) { writer.WriteLine("#{0:000}02: {1}", item.StartBarIndex + (args.HasPaddingBar && item.StartBarIndex == 1 ? -1 : 0), 4f * item.TimeSignature.Numerator / item.TimeSignature.Denominator); } 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).Skip(1).Take(bpmlist.Count).ToList(); foreach (var item in bpmlist) { writer.WriteLine("#BPM{0}: {1}", bpmIdentifiers[item.Index], item.Value.BPM); } if (args.HasPaddingBar) { writer.WriteLine("#{0:000}08: {1:x2}", 0, bpmIdentifiers[bpmlist.OrderBy(p => p.Value.Tick).First().Index]); } foreach (var eventInBar in bpmlist.GroupBy(p => p.BarPosition.BarIndex)) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(eventInBar.Key); int barLength = barTick * sig.Numerator / sig.Denominator; var dic = eventInBar.ToDictionary(p => p.BarPosition.TickOffset, p => p); int gcd = eventInBar.Select(p => p.BarPosition.TickOffset).Aggregate(barLength, (p, q) => GetGcd(p, q)); writer.Write("#{0:000}08: ", eventInBar.Key); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; writer.Write(dic.ContainsKey(tickOffset) ? bpmIdentifiers[dic[tickOffset].Index] : "00"); } writer.WriteLine(); } writer.WriteLine(); var speeds = book.Score.Events.HighSpeedChangeEvents.Select(p => { var barPos = barIndexCalculator.GetBarPositionFromTick(p.Tick); return(string.Format("{0}'{1}:{2}", args.HasPaddingBar && barPos.BarIndex == 1 && barPos.TickOffset == 0 ? 0 : barPos.BarIndex, barPos.TickOffset, p.SpeedRatio)); }); writer.WriteLine("#TIL00: \"{0}\"", string.Join(", ", speeds)); writer.WriteLine("#HISPEED 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 => new { BarPosition = barIndexCalculator.GetBarPositionFromTick(p.Note.Tick), LaneIndex = p.Note.LaneIndex, Width = p.Note.Width, Type = p.Type }); foreach (var notesInBar in shortNotes.GroupBy(p => p.BarPosition.BarIndex)) { foreach (var notesInLane in notesInBar.GroupBy(p => p.LaneIndex)) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(notesInBar.Key); int barLength = barTick * sig.Numerator / sig.Denominator; var offsetList = notesInLane.GroupBy(p => p.BarPosition.TickOffset).Select(p => p.ToList()); var separatedNotes = Enumerable.Range(0, offsetList.Max(p => p.Count)).Select(p => offsetList.Where(q => q.Count >= p + 1).Select(q => q[p])); foreach (var dic in separatedNotes.Select(p => p.ToDictionary(q => q.BarPosition.TickOffset, q => q))) { int gcd = dic.Values.Select(p => p.BarPosition.TickOffset).Aggregate(barLength, (p, q) => GetGcd(p, q)); writer.Write("#{0:000}1{1}:", notesInBar.Key, notesInLane.Key.ToString("x")); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; writer.Write(dic.ContainsKey(tickOffset) ? dic[tickOffset].Type + ToLaneWidthString(dic[tickOffset].Width) : "00"); } 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(new { BarPosition = barIndexCalculator.GetBarPositionFromTick(p.Tick), LaneIndex = p.LaneIndex, Type = type, Width = p.Width }); }); foreach (var airsInBar in airs.GroupBy(p => p.BarPosition.BarIndex)) { foreach (var airsInLane in airsInBar.GroupBy(p => p.LaneIndex)) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(airsInBar.Key); int barLength = barTick * sig.Numerator / sig.Denominator; var offsetList = airsInLane.GroupBy(p => p.BarPosition.TickOffset).Select(p => p.ToList()); var separatedNotes = Enumerable.Range(0, offsetList.Max(p => p.Count)).Select(p => offsetList.Where(q => q.Count >= p + 1).Select(q => q[p])); foreach (var dic in separatedNotes.Select(p => p.ToDictionary(q => q.BarPosition.TickOffset, q => q))) { int gcd = dic.Values.Select(p => p.BarPosition.TickOffset).Aggregate(barLength, (p, q) => GetGcd(p, q)); writer.Write("#{0:000}5{1}:", airsInBar.Key, airsInLane.Key.ToString("x")); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; writer.Write(dic.ContainsKey(tickOffset) ? dic[tickOffset].Type + ToLaneWidthString(dic[tickOffset].Width) : "00"); } 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 }); foreach (var hold in holds) { var startBarPosition = barIndexCalculator.GetBarPositionFromTick(hold.StartTick); var endBarPosition = barIndexCalculator.GetBarPositionFromTick(hold.EndTick); if (startBarPosition.BarIndex == endBarPosition.BarIndex) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(startBarPosition.BarIndex); int barLength = barTick * sig.Numerator / sig.Denominator; writer.Write("#{0:000}2{1}{2}:", startBarPosition.BarIndex, hold.LaneIndex.ToString("x"), hold.Identifier); int gcd = GetGcd(GetGcd(startBarPosition.TickOffset, endBarPosition.TickOffset), barLength); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; if (startBarPosition.TickOffset == tickOffset) { writer.Write("1" + ToLaneWidthString(hold.Width)); } else if (endBarPosition.TickOffset == tickOffset) { writer.Write("2" + ToLaneWidthString(hold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } else { var startSig = barIndexCalculator.GetTimeSignatureFromBarIndex(startBarPosition.BarIndex); int startBarLength = barTick * startSig.Numerator / startSig.Denominator; writer.Write("#{0:000}2{1}{2}:", startBarPosition.BarIndex, hold.LaneIndex.ToString("x"), hold.Identifier); int gcd = GetGcd(startBarPosition.TickOffset, startBarLength); for (int i = 0; i *gcd < startBarLength; i++) { int tickOffset = i * gcd; if (startBarPosition.TickOffset == tickOffset) { writer.Write("1" + ToLaneWidthString(hold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); var endSig = barIndexCalculator.GetTimeSignatureFromBarIndex(endBarPosition.BarIndex); int endBarLength = barTick * endSig.Numerator / endSig.Denominator; writer.Write("#{0:000}2{1}{2}:", endBarPosition.BarIndex, hold.LaneIndex.ToString("x"), hold.Identifier); gcd = GetGcd(endBarPosition.TickOffset, endBarLength); for (int i = 0; i *gcd < endBarLength; i++) { int tickOffset = i * gcd; if (endBarPosition.TickOffset == tickOffset) { writer.Write("2" + ToLaneWidthString(hold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } } identifier.Clear(); var slides = notes.Slides .OrderBy(p => p.StartTick) .Select(p => new { Identifier = identifier.Allocate(p.StartTick, p.GetDuration()), Note = p }); foreach (var slide in slides) { var start = new[] { new { TickOffset = 0, BarPosition = barIndexCalculator.GetBarPositionFromTick(slide.Note.StartTick), LaneIndex = slide.Note.StartLaneIndex, Width = slide.Note.StartWidth, Type = "1" } }; var steps = slide.Note.StepNotes.OrderBy(p => p.TickOffset).Select(p => new { TickOffset = p.TickOffset, BarPosition = barIndexCalculator.GetBarPositionFromTick(p.Tick), LaneIndex = p.LaneIndex, Width = p.Width, Type = p.IsVisible ? "3" : "5" }).Take(slide.Note.StepNotes.Count - 1); var endNote = slide.Note.StepNotes.OrderBy(p => p.TickOffset).Last(); var end = new[] { new { TickOffset = endNote.TickOffset, BarPosition = barIndexCalculator.GetBarPositionFromTick(endNote.Tick), LaneIndex = endNote.LaneIndex, Width = endNote.Width, Type = "2" } }; var slideNotes = start.Concat(steps).Concat(end); foreach (var notesInBar in slideNotes.GroupBy(p => p.BarPosition.BarIndex)) { foreach (var notesInLane in notesInBar.GroupBy(p => p.LaneIndex)) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(notesInBar.Key); int barLength = barTick * sig.Numerator / sig.Denominator; int gcd = notesInLane.Select(p => p.BarPosition.TickOffset).Aggregate(barLength, (p, q) => GetGcd(p, q)); var dic = notesInLane.ToDictionary(p => p.BarPosition.TickOffset, p => p); writer.Write("#{0:000}3{1}{2}:", notesInBar.Key, notesInLane.Key.ToString("x"), slide.Identifier); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; writer.Write(dic.ContainsKey(tickOffset) ? dic[tickOffset].Type + ToLaneWidthString(dic[tickOffset].Width) : "00"); } writer.WriteLine(); } } } identifier.Clear(); var airActions = notes.AirActions .OrderBy(p => p.StartTick) .Select(p => new { Identifier = identifier.Allocate(p.StartTick, p.GetDuration()), Note = p }); foreach (var airAction in airActions) { var start = new[] { new { TickOffset = 0, BarPosition = barIndexCalculator.GetBarPositionFromTick(airAction.Note.StartTick), Type = "1" } }; var actions = airAction.Note.ActionNotes.OrderBy(p => p.Offset).Select(p => new { TickOffset = p.Offset, BarPosition = barIndexCalculator.GetBarPositionFromTick(p.ParentNote.StartTick + p.Offset), Type = "3" }).Take(airAction.Note.ActionNotes.Count - 1); var endNote = airAction.Note.ActionNotes.OrderBy(p => p.Offset).Last(); var end = new[] { new { TickOffset = endNote.Offset, BarPosition = barIndexCalculator.GetBarPositionFromTick(airAction.Note.StartTick + endNote.Offset), Type = "2" } }; var actionNotes = start.Concat(actions).Concat(end); foreach (var airActionsInBar in actionNotes.GroupBy(p => p.BarPosition.BarIndex)) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(airActionsInBar.Key); int barLength = barTick * sig.Numerator / sig.Denominator; writer.Write("#{0:000}4{1}{2}:", airActionsInBar.Key, airAction.Note.ParentNote.LaneIndex.ToString("x"), airAction.Identifier); int gcd = airActionsInBar.Select(p => p.BarPosition.TickOffset).Aggregate(barLength, (p, q) => GetGcd(p, q)); var dic = airActionsInBar.ToDictionary(p => p.BarPosition.TickOffset, p => p); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; if (dic.ContainsKey(tickOffset)) { writer.Write("{0}{1}", dic[tickOffset].Type, ToLaneWidthString(airAction.Note.ParentNote.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } } } }
public void Export(string path, ScoreBook book) { // TODO: コンストラクタに移してreadonlyにする ScoreBook = book; BarIndexCalculator = new BarIndexCalculator(book.Score.TicksPerBeat, book.Score.Events.TimeSignatureChangeEvents); SusArgs args = CustomArgs; BarIndexOffset = args.HasPaddingBar ? 1 : 0; var notes = book.Score.Notes; using (var writer = new StreamWriter(path)) { 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).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)); });
public void Export(string path, ScoreBook book) { SusArgs args = CustomArgs; var notes = book.Score.Notes; notes.Taps = notes.Taps.Distinct().ToList(); notes.DTaps = notes.DTaps.Distinct().ToList(); notes.HTaps = notes.HTaps.Distinct().ToList(); notes.LTaps = notes.LTaps.Distinct().ToList(); notes.Traces = notes.Traces.Distinct().ToList(); notes.DTraces = notes.DTraces.Distinct().ToList(); notes.HTraces = notes.HTraces.Distinct().ToList(); notes.LTraces = notes.LTraces.Distinct().ToList(); notes.Holds = notes.Holds.Distinct().ToList(); notes.DHolds = notes.DHolds.Distinct().ToList(); notes.HHolds = notes.HHolds.Distinct().ToList(); notes.LHolds = notes.LHolds.Distinct().ToList(); using (var writer = new StreamWriter(path)) { 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("#WAVE \"{0}\"", args.SoundFileName); writer.WriteLine("#WAVEOFFSET {0}", args.SoundOffset); writer.WriteLine(); int barTick = book.Score.TicksPerBeat * 4; var barIndexCalculator = new BarIndexCalculator(barTick, book.Score.Events.TimeSignatureChangeEvents, args.HasPaddingBar); foreach (var item in barIndexCalculator.TimeSignatures) { writer.WriteLine("#{0:000}02: {1}", item.StartBarIndex + (args.HasPaddingBar && item.StartBarIndex == 1 ? -1 : 0), 4f * item.TimeSignature.Numerator / item.TimeSignature.Denominator); } 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).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); } if (args.HasPaddingBar) { writer.WriteLine("#{0:000}08: {1:x2}", 0, bpmIdentifiers[bpmlist.OrderBy(p => p.Value.Tick).First().Index]); } foreach (var eventInBar in bpmlist.GroupBy(p => p.BarPosition.BarIndex)) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(eventInBar.Key); int barLength = barTick * sig.Numerator / sig.Denominator; var dic = eventInBar.ToDictionary(p => p.BarPosition.TickOffset, p => p); int gcd = eventInBar.Select(p => p.BarPosition.TickOffset).Aggregate(barLength, (p, q) => GetGcd(p, q)); writer.Write("#{0:000}08: ", eventInBar.Key); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; writer.Write(dic.ContainsKey(tickOffset) ? bpmIdentifiers[dic[tickOffset].Index] : "00"); } writer.WriteLine(); } writer.WriteLine(); foreach (var EventVar in book.Score.Events.HighSpeedChangeEvents) { var barPos = barIndexCalculator.GetBarPositionFromTick(EventVar.Tick); writer.Write("#{0:000}07: ", barPos.BarIndex); writer.WriteLine(EventVar.SpeedRatio); } foreach (var EventVar in book.Score.Events.SplitLaneEvents) { var barPos = barIndexCalculator.GetBarPositionFromTick(EventVar.Tick); writer.Write("#{0:000}05: ", barPos.BarIndex); writer.WriteLine(EventVar.ToString().ToCharArray()); } writer.WriteLine(); var shortNotes = notes.Taps.Cast <TappableBase>().Select(p => new { Type = '1', Note = p }) .Concat(notes.DTaps.Cast <TappableBase>().Select(p => new { Type = '2', Note = p })) .Concat(notes.HTaps.Cast <TappableBase>().Select(p => new { Type = '3', Note = p })) .Concat(notes.LTaps.Cast <TappableBase>().Select(p => new { Type = '4', Note = p })) .Concat(notes.Traces.Cast <TappableBase>().Select(p => new { Type = '5', Note = p })) .Concat(notes.DTraces.Cast <TappableBase>().Select(p => new { Type = '6', Note = p })) .Concat(notes.HTraces.Cast <TappableBase>().Select(p => new { Type = '7', Note = p })) .Concat(notes.LTraces.Cast <TappableBase>().Select(p => new { Type = '8', Note = p })) .Concat(notes.Flicks.Cast <TappableBase>().Select(p => new { Type = '9', Note = p })) .Concat(notes.Damages.Cast <TappableBase>().Select(p => new { Type = 'A', Note = p })) .Select(p => new { BarPosition = barIndexCalculator.GetBarPositionFromTick(p.Note.Tick), LaneIndex = p.Note.LaneIndex, Width = p.Note.Width, Type = p.Type }); foreach (var notesInBar in shortNotes.GroupBy(p => p.BarPosition.BarIndex)) { foreach (var notesInLane in notesInBar.GroupBy(p => p.LaneIndex)) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(notesInBar.Key); int barLength = barTick * sig.Numerator / sig.Denominator; var offsetList = notesInLane.GroupBy(p => p.BarPosition.TickOffset).Select(p => p.ToList()); var separatedNotes = Enumerable.Range(0, offsetList.Max(p => p.Count)).Select(p => offsetList.Where(q => q.Count >= p + 1).Select(q => q[p])); foreach (var dic in separatedNotes.Select(p => p.ToDictionary(q => q.BarPosition.TickOffset, q => q))) { int gcd = dic.Values.Select(p => p.BarPosition.TickOffset).Aggregate(barLength, (p, q) => GetGcd(p, q)); writer.Write("#{0:000}1{1}:", notesInBar.Key, notesInLane.Key.ToString("x")); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; writer.Write(dic.ContainsKey(tickOffset) ? dic[tickOffset].Type + ToLaneWidthString(dic[tickOffset].Width) : "00"); } 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 }); foreach (var hold in holds) { var startBarPosition = barIndexCalculator.GetBarPositionFromTick(hold.StartTick); var endBarPosition = barIndexCalculator.GetBarPositionFromTick(hold.EndTick); if (startBarPosition.BarIndex == endBarPosition.BarIndex) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(startBarPosition.BarIndex); int barLength = barTick * sig.Numerator / sig.Denominator; writer.Write("#{0:000}2{1}{2}:", startBarPosition.BarIndex, hold.LaneIndex.ToString("x"), hold.Identifier); int gcd = GetGcd(GetGcd(startBarPosition.TickOffset, endBarPosition.TickOffset), barLength); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; if (startBarPosition.TickOffset == tickOffset) { writer.Write("1" + ToLaneWidthString(hold.Width)); } else if (endBarPosition.TickOffset == tickOffset) { writer.Write("2" + ToLaneWidthString(hold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } else { var startSig = barIndexCalculator.GetTimeSignatureFromBarIndex(startBarPosition.BarIndex); int startBarLength = barTick * startSig.Numerator / startSig.Denominator; writer.Write("#{0:000}2{1}{2}:", startBarPosition.BarIndex, hold.LaneIndex.ToString("x"), hold.Identifier); int gcd = GetGcd(startBarPosition.TickOffset, startBarLength); for (int i = 0; i *gcd < startBarLength; i++) { int tickOffset = i * gcd; if (startBarPosition.TickOffset == tickOffset) { writer.Write("1" + ToLaneWidthString(hold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); var endSig = barIndexCalculator.GetTimeSignatureFromBarIndex(endBarPosition.BarIndex); int endBarLength = barTick * endSig.Numerator / endSig.Denominator; writer.Write("#{0:000}2{1}{2}:", endBarPosition.BarIndex, hold.LaneIndex.ToString("x"), hold.Identifier); gcd = GetGcd(endBarPosition.TickOffset, endBarLength); for (int i = 0; i *gcd < endBarLength; i++) { int tickOffset = i * gcd; if (endBarPosition.TickOffset == tickOffset) { writer.Write("2" + ToLaneWidthString(hold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } } var identifier2 = new IdentifierAllocationManager(); var dholds = book.Score.Notes.DHolds .OrderBy(p => p.StartTick) .Select(p => new { Identifier2 = identifier2.Allocate(p.StartTick, p.Duration), StartTick = p.StartTick, EndTick = p.StartTick + p.Duration, Width = p.Width, LaneIndex = p.LaneIndex }); foreach (var dhold in dholds) { var startBarPosition = barIndexCalculator.GetBarPositionFromTick(dhold.StartTick); var endBarPosition = barIndexCalculator.GetBarPositionFromTick(dhold.EndTick); if (startBarPosition.BarIndex == endBarPosition.BarIndex) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(startBarPosition.BarIndex); int barLength = barTick * sig.Numerator / sig.Denominator; writer.Write("#{0:000}3{1}{2}:", startBarPosition.BarIndex, dhold.LaneIndex.ToString("x"), dhold.Identifier2); int gcd = GetGcd(GetGcd(startBarPosition.TickOffset, endBarPosition.TickOffset), barLength); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; if (startBarPosition.TickOffset == tickOffset) { writer.Write("1" + ToLaneWidthString(dhold.Width)); } else if (endBarPosition.TickOffset == tickOffset) { writer.Write("2" + ToLaneWidthString(dhold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } else { var startSig = barIndexCalculator.GetTimeSignatureFromBarIndex(startBarPosition.BarIndex); int startBarLength = barTick * startSig.Numerator / startSig.Denominator; writer.Write("#{0:000}3{1}{2}:", startBarPosition.BarIndex, dhold.LaneIndex.ToString("x"), dhold.Identifier2); int gcd = GetGcd(startBarPosition.TickOffset, startBarLength); for (int i = 0; i *gcd < startBarLength; i++) { int tickOffset = i * gcd; if (startBarPosition.TickOffset == tickOffset) { writer.Write("1" + ToLaneWidthString(dhold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); var endSig = barIndexCalculator.GetTimeSignatureFromBarIndex(endBarPosition.BarIndex); int endBarLength = barTick * endSig.Numerator / endSig.Denominator; writer.Write("#{0:000}3{1}{2}:", endBarPosition.BarIndex, dhold.LaneIndex.ToString("x"), dhold.Identifier2); gcd = GetGcd(endBarPosition.TickOffset, endBarLength); for (int i = 0; i *gcd < endBarLength; i++) { int tickOffset = i * gcd; if (endBarPosition.TickOffset == tickOffset) { writer.Write("2" + ToLaneWidthString(dhold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } } var identifier3 = new IdentifierAllocationManager(); var hholds = book.Score.Notes.DHolds .OrderBy(p => p.StartTick) .Select(p => new { Identifier3 = identifier3.Allocate(p.StartTick, p.Duration), StartTick = p.StartTick, EndTick = p.StartTick + p.Duration, Width = p.Width, LaneIndex = p.LaneIndex }); foreach (var hhold in hholds) { var startBarPosition = barIndexCalculator.GetBarPositionFromTick(hhold.StartTick); var endBarPosition = barIndexCalculator.GetBarPositionFromTick(hhold.EndTick); if (startBarPosition.BarIndex == endBarPosition.BarIndex) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(startBarPosition.BarIndex); int barLength = barTick * sig.Numerator / sig.Denominator; writer.Write("#{0:000}4{1}{2}:", startBarPosition.BarIndex, hhold.LaneIndex.ToString("x"), hhold.Identifier3); int gcd = GetGcd(GetGcd(startBarPosition.TickOffset, endBarPosition.TickOffset), barLength); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; if (startBarPosition.TickOffset == tickOffset) { writer.Write("1" + ToLaneWidthString(hhold.Width)); } else if (endBarPosition.TickOffset == tickOffset) { writer.Write("2" + ToLaneWidthString(hhold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } else { var startSig = barIndexCalculator.GetTimeSignatureFromBarIndex(startBarPosition.BarIndex); int startBarLength = barTick * startSig.Numerator / startSig.Denominator; writer.Write("#{0:000}4{1}{2}:", startBarPosition.BarIndex, hhold.LaneIndex.ToString("x"), hhold.Identifier3); int gcd = GetGcd(startBarPosition.TickOffset, startBarLength); for (int i = 0; i *gcd < startBarLength; i++) { int tickOffset = i * gcd; if (startBarPosition.TickOffset == tickOffset) { writer.Write("1" + ToLaneWidthString(hhold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); var endSig = barIndexCalculator.GetTimeSignatureFromBarIndex(endBarPosition.BarIndex); int endBarLength = barTick * endSig.Numerator / endSig.Denominator; writer.Write("#{0:000}4{1}{2}:", endBarPosition.BarIndex, hhold.LaneIndex.ToString("x"), hhold.Identifier3); gcd = GetGcd(endBarPosition.TickOffset, endBarLength); for (int i = 0; i *gcd < endBarLength; i++) { int tickOffset = i * gcd; if (endBarPosition.TickOffset == tickOffset) { writer.Write("2" + ToLaneWidthString(hhold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } identifier.Clear(); } var identifier4 = new IdentifierAllocationManager(); var lholds = book.Score.Notes.DHolds .OrderBy(p => p.StartTick) .Select(p => new { Identifier4 = identifier4.Allocate(p.StartTick, p.Duration), StartTick = p.StartTick, EndTick = p.StartTick + p.Duration, Width = p.Width, LaneIndex = p.LaneIndex }); foreach (var lhold in lholds) { var startBarPosition = barIndexCalculator.GetBarPositionFromTick(lhold.StartTick); var endBarPosition = barIndexCalculator.GetBarPositionFromTick(lhold.EndTick); if (startBarPosition.BarIndex == endBarPosition.BarIndex) { var sig = barIndexCalculator.GetTimeSignatureFromBarIndex(startBarPosition.BarIndex); int barLength = barTick * sig.Numerator / sig.Denominator; writer.Write("#{0:000}5{1}{2}:", startBarPosition.BarIndex, lhold.LaneIndex.ToString("x"), lhold.Identifier4); int gcd = GetGcd(GetGcd(startBarPosition.TickOffset, endBarPosition.TickOffset), barLength); for (int i = 0; i *gcd < barLength; i++) { int tickOffset = i * gcd; if (startBarPosition.TickOffset == tickOffset) { writer.Write("1" + ToLaneWidthString(lhold.Width)); } else if (endBarPosition.TickOffset == tickOffset) { writer.Write("2" + ToLaneWidthString(lhold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } else { var startSig = barIndexCalculator.GetTimeSignatureFromBarIndex(startBarPosition.BarIndex); int startBarLength = barTick * startSig.Numerator / startSig.Denominator; writer.Write("#{0:000}5{1}{2}:", startBarPosition.BarIndex, lhold.LaneIndex.ToString("x"), lhold.Identifier4); int gcd = GetGcd(startBarPosition.TickOffset, startBarLength); for (int i = 0; i *gcd < startBarLength; i++) { int tickOffset = i * gcd; if (startBarPosition.TickOffset == tickOffset) { writer.Write("1" + ToLaneWidthString(lhold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); var endSig = barIndexCalculator.GetTimeSignatureFromBarIndex(endBarPosition.BarIndex); int endBarLength = barTick * endSig.Numerator / endSig.Denominator; writer.Write("#{0:000}5{1}{2}:", endBarPosition.BarIndex, lhold.LaneIndex.ToString("x"), lhold.Identifier4); gcd = GetGcd(endBarPosition.TickOffset, endBarLength); for (int i = 0; i *gcd < endBarLength; i++) { int tickOffset = i * gcd; if (endBarPosition.TickOffset == tickOffset) { writer.Write("2" + ToLaneWidthString(lhold.Width)); } else { writer.Write("00"); } } writer.WriteLine(); } } identifier.Clear(); identifier2.Clear(); identifier3.Clear(); identifier4.Clear(); } }