public bool FinalizePosition(ScoreBook scoreBook) { if (scoreBook is null) { return(false); } for (int i = 0; i < Count; ++i) { if (this[i].Position.Lane == -1) { /* もう位置の校正は済んでますよ */ continue; } if (scoreBook.Find(x => x.StartTick <= this[i].Position.Tick && this[i].Position.Tick <= x.EndTick) is null) { /* あなたの属する小節ないみたいですけど…… */ return(false); } this[i].Relocate(new Position(-1, this[i].Position.Tick + scoreBook.At(this[i].Position.Lane).StartTick)); } Finalized = true; return(true); }
protected void LoadEmptyBook() { var book = new ScoreBook(); var events = book.Score.Events; events.BPMChangeEvents.Add(new BPMChangeEvent() { Tick = 0, BPM = 120 }); events.TimeSignatureChangeEvents.Add(new TimeSignatureChangeEvent() { Tick = 0, Numerator = 4, DenominatorExponent = 2 }); events.HighSpeedChangeEvents.Add(new HighSpeedChangeEvent() { Tick = 0, SpeedRatio = (decimal)1.00 }); bool[] vs = { false, false, false, false, false, false }; events.SplitLaneEvents.Add(new SplitLaneEvent() { Tick = 0, Lane = vs }); events.SplitLaneEvents.Add(new SplitLaneEvent() { Tick = 100000, Lane = vs }); LoadBook(book); }
protected void LoadFile(string filePath) { try { if (!ScoreBook.IsCompatible(filePath)) { MessageBox.Show(this, ErrorStrings.FileNotCompatible, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (ScoreBook.IsUpgradeNeeded(filePath)) { if (MessageBox.Show(this, ErrorStrings.FileUpgradeNeeded, Program.ApplicationName, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) { return; } } LoadBook(ScoreBook.LoadFile(filePath)); } catch (UnauthorizedAccessException) { MessageBox.Show(this, ErrorStrings.FileNotAccessible, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); LoadEmptyBook(); } catch (Exception ex) { MessageBox.Show(this, ErrorStrings.FileLoadError, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); Program.DumpExceptionTo(ex, "file_exception.json"); LoadEmptyBook(); } }
private void HandleExport(ScoreBook book, ExportContext context) { CommitChanges(); string message; bool hasError = true; try { context.Export(book); message = ErrorStrings.ExportComplete; hasError = false; ExportManager.CommitExported(context); } catch (UserCancelledException) { // Do nothing return; } catch (InvalidTimeSignatureException ex) { int beatAt = ex.Tick / ScoreBook.Score.TicksPerBeat + 1; message = string.Format(ErrorStrings.InvalidTimeSignature, beatAt); } catch (Exception ex) { Program.DumpExceptionTo(ex, "export_exception.json"); message = ErrorStrings.ExportFailed + Environment.NewLine + ex.Message; } ShowDiagnosticsResult(MainFormStrings.Export, message, hasError, context.Diagnostics); }
protected void LoadFile(string path) { try { if (!ScoreBook.IsCompatible(path)) { MessageBox.Show(this, "現在のバージョンでは開けないファイルです。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (ScoreBook.IsUpgradeNeeded(path)) { if (MessageBox.Show(this, "古いバージョンで作成されたファイルです。バージョンアップしてよろしいですか?\n(以前のバージョンでは開けなくなります。)", Program.ApplicationName, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) { return; } } LoadBook(ScoreBook.LoadFile(path)); } catch (Exception ex) { MessageBox.Show(this, "ファイルを読み込むことができませんでした。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); Program.DumpExceptionTo(ex, "file_exception.json"); LoadEmptyBook(); } }
protected void LoadFile(string filePath) { try { if (!ScoreBook.IsCompatible(filePath)) { MessageBox.Show(this, "現在のバージョンでは開けないファイルです。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (!ScoreBook.IsUpgradeNeeded(filePath)) { if (MessageBox.Show(this, "古いバージョンで作成されたファイルです。\nバージョンアップしてよろしいですか?\n(以前のバージョンでは開けなくなります。)", Program.ApplicationName, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) { return; } } LoadBook(ScoreBook.LoadFile(filePath)); } catch (Exception ex) { MessageBox.Show(this, "ファイルの読み込み中にエラーが発生しました。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); Program.DumpException(ex); LoadBook(new ScoreBook()); } }
public BookPropertiesForm(ScoreBook book, SoundSource musicSource) { InitializeComponent(); Text = "譜面プロパティ"; AcceptButton = buttonOK; CancelButton = buttonCancel; buttonOK.DialogResult = DialogResult.OK; buttonCancel.DialogResult = DialogResult.Cancel; titleBox.Text = book.Title; artistBox.Text = book.ArtistName; notesDesignerBox.Text = book.NotesDesignerName; if (musicSource != null) { musicSourceSelector.Value = musicSource; } buttonOK.Click += (s, e) => { book.Title = titleBox.Text; book.ArtistName = artistBox.Text; book.NotesDesignerName = notesDesignerBox.Text; Close(); }; }
public Model() { NoteBook = new NoteBook(); ScoreBook = new ScoreBook(); LaneBook = new LaneBook(); LaneBook.UpdateNoteLocation += NoteBook.UpdateNoteLocation; MusicInfo = new MusicInfo(); }
public ScoreBookExportPluginArgs(ScoreBook scoreBook, Stream stream, bool isQuick, Func <string> getCustomDataFunc, Action <string> setCustomDataFunc) { ScoreBook = scoreBook; Stream = stream; IsQuick = isQuick; this.getCustomDataFunc = getCustomDataFunc; this.setCustomDataFunc = setCustomDataFunc; }
public void Exchange(JsonObject json) { ScoreBook.Exchange(json["ScoreBook"]); NoteBook.Exchange(json["NoteBook"]); MadcaMusicData.Exchange(json["MusicData"]); FumenAuthor = json["FumenDesigner"]; FumenDifficulity = FumenData.FumenDifficulity.Parse(typeof(FumenDifficulity), json["FumenDifficulity"]); FumenConstant = double.Parse(json["FumenConstant"]); FumenLevel.Exchange(json["FumenLevel"]); StartBpm = double.Parse(json["StartBpm"]); }
public DeleteScoreWithNoteOperation( Model model, Score score, int count) { Score prev = model.ScoreBook.Prev(score); ScoreBook scoreList = new ScoreBook(); Score itrScore = score; for (int i = 0; i < count && itrScore != null; ++i) { scoreList.Add(itrScore); itrScore = model.ScoreBook.Next(itrScore); } var notesForDelete = model.NoteBook.GetNotesFromTickRange( scoreList.First().StartTick, scoreList.Last().EndTick); var longNotesForDelete = model.NoteBook.GetLongNotesFromTickRange( scoreList.First().StartTick, scoreList.Last().EndTick); int deleteScoreTickSize = scoreList.Last().EndTick - scoreList.First().StartTick + 1; List <Operation> operations = new List <Operation>(); notesForDelete.ForEach(x => { operations.Add(new DeleteNoteOperation( model, x)); }); longNotesForDelete.ForEach(x => { operations.Add(new DeleteLongNoteOperation( model, x)); }); Invoke += () => { model.LaneBook.DeleteScore(model.ScoreBook, scoreList.First(), count); operations.ForEach(x => x.Invoke()); model.NoteBook.RelocateNoteTickAfterScoreTick( scoreList.Last().EndTick + 1, -deleteScoreTickSize); model.LaneBook.OnUpdateNoteLocation(); }; Undo += () => { model.LaneBook.InsertScoreForwardWithNote( model.NoteBook, model.ScoreBook, prev, scoreList); operations.ForEach(x => x.Undo()); }; }
public BookPropertiesForm(ScoreBook book, SoundSource musicSource) { InitializeComponent(); AcceptButton = buttonOK; CancelButton = buttonCancel; buttonOK.DialogResult = DialogResult.OK; buttonCancel.DialogResult = DialogResult.Cancel; if (musicSource != null) { musicSourceSelector.Value = musicSource; } }
public ExportForm(ScoreBook book) { InitializeComponent(); Icon = Properties.Resources.MainIcon; ShowInTaskbar = false; if (!book.ExporterArgs.ContainsKey(ArgsKey) || !(book.ExporterArgs[ArgsKey] is SusArgs)) { book.ExporterArgs[ArgsKey] = new SusArgs(); } var args = book.ExporterArgs[ArgsKey] as SusArgs; browseButton.Click += (s, e) => { var dialog = new SaveFileDialog() { Filter = Filter }; if (dialog.ShowDialog(this) == DialogResult.OK) { outputBox.Text = dialog.FileName; } }; exportButton.Click += (s, e) => { if (string.IsNullOrEmpty(OutputPath)) { browseButton.PerformClick(); } if (string.IsNullOrEmpty(OutputPath)) { MessageBox.Show(this, ErrorStrings.OutputPathRequired, Program.ApplicationName); return; } try { exporter.CustomArgs = args; exporter.Export(OutputPath, book); DialogResult = DialogResult.OK; Close(); } catch (Exception ex) { MessageBox.Show(this, ErrorStrings.ExportFailed, Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); Program.DumpException(ex); } }; }
public void Export(ScoreBook scoreBook, NoteBook noteBook) { this.scoreBook = scoreBook; this.noteBook = noteBook; if (MusicInfo.HasExported) { Export(exportPathText.Text); SaveMusicInfo(true); } else { ShowDialog(); } }
protected void SaveFile() { if (string.IsNullOrEmpty(ScoreBook.Path)) { SaveAs(); return; } CommitChanges(); ScoreBook.Save(); OperationManager.CommitChanges(); SoundSettings.Default.ScoreSound[ScoreBook.Path] = CurrentMusicSource; SoundSettings.Default.Save(); }
public JsonObject Exchange() { return(new JsonObject() { ["ScoreBook"] = ScoreBook.Exchange(), ["NoteBook"] = NoteBook.Exchange(), ["MusicData"] = MadcaMusicData.Exchange(), ["FumenDesigner"] = FumenAuthor, ["FumenDifficulity"] = FumenDifficulity, ["FumenConstant"] = FumenConstant, ["FumenLevel"] = FumenLevel.Exchange(), ["StartBpm"] = StartBpm }); }
public void FinalizePosition(ScoreBook scoreBook, Dictionary <int, int> matching) { Dictionary <int, HighSpeedTimeLine> newBook = new Dictionary <int, HighSpeedTimeLine>(); int newDefNumber = 1; foreach (KeyValuePair <int, HighSpeedTimeLine> pair in book) { pair.Value.FinalizePosition(scoreBook); newBook.Add(newDefNumber, pair.Value); matching.Add(pair.Key, newDefNumber); ++newDefNumber; } book = newBook; }
public void Export(ScoreBook book) { using (var ms = new MemoryStream()) { var args = new ScoreBookExportPluginArgs(book, ms, IsQuick, GetCustomData, SetCustomData); Diagnostics = args.Diagnostics; ExportPlugin.Export(args); using (var fs = new FileStream(OutputPath, FileMode.Create, FileAccess.Write)) { var res = ms.ToArray(); fs.Write(res, 0, res.Length); } } }
protected void LoadEmptyBook() { var book = new ScoreBook(); var events = book.Score.Events; events.BpmChangeEvents.Add(new BpmChangeEvent() { Tick = 0, Bpm = 120 }); events.TimeSignatureChangeEvents.Add(new TimeSignatureChangeEvent() { Tick = 0, Numerator = 4, DenominatorExponent = 2 }); LoadBook(book); }
protected void LoadBook(ScoreBook book) { ScoreBook = book; NoteView.LoadScore(book.Score); NoteViewScrollBar.Value = NoteViewScrollBar.GetMaximumValue(); NoteViewScrollBar.Minimum = -Math.Max(NoteView.UnitBeatTick * 4 * 20, NoteView.Notes.GetLastTick()); UpdateThumbHeight(); SetText(book.Path); LastExportData = null; if (!string.IsNullOrEmpty(book.Path)) { SoundConfiguration.Default.ScoreSound.TryGetValue(book.Path, out CurrentMusicSource); } else { CurrentMusicSource = null; } }
public MadcaFumenData( ScoreBook scoreBook, NoteBook noteBook, MadcaMusicData madcaMusicData, string fumenAuthor, FumenDifficulity fumenDifficulity, double fumenConstant, FumenLevel fumenLevel, double startBpm) { ScoreBook = scoreBook; NoteBook = noteBook; MadcaMusicData = madcaMusicData; FumenAuthor = fumenAuthor; FumenDifficulity = fumenDifficulity; FumenConstant = fumenConstant; FumenLevel = fumenLevel; StartBpm = startBpm; }
protected void LoadBook(ScoreBook book) { LastExportCache = null; ScoreBook = book; OperationManager.Clear(); NoteView.Load(book.Score); InitializeScrollBar(book.Score.GetLastTick()); UpdateThumbHeight(); SetText(book.Path); if (!string.IsNullOrEmpty(book.Path)) { SoundSettings.Default.ScoreSounds.TryGetValue(book.Path, out CurrentSoundSource); } else { CurrentSoundSource = null; } }
protected void LoadBook(ScoreBook book) { ScoreBook = book; OperationManager.Clear(); NoteView.Initialize(book.Score); NoteViewScrollBar.Value = NoteViewScrollBar.GetMaximumValue(); NoteViewScrollBar.Minimum = -Math.Max(NoteView.UnitBeatTick * 4 * 20, NoteView.Notes.GetLastTick()); NoteViewScrollBar.SmallChange = NoteView.UnitBeatTick; UpdateThumbHeight(); SetText(book.Path); LastExportData = null; if (!string.IsNullOrEmpty(book.Path)) { SoundSettings.Default.ScoreSound.TryGetValue(book.Path, out CurrentMusicSource); } else { CurrentMusicSource = null; } }
protected void LoadEmptyBook() { var book = new ScoreBook(); var score = book.Score; score.Events.TimeSignatureChangeEvents.Add(new TimeSignatureChangeEvent() { Tick = 0, Numerator = 4, DenominatorExponent = 2 }); score.Events.BPMChangeEvents.Add(new BPMChangeEvent() { Tick = 0, BPM = 120 }); score.Field.Left.FieldWall.Points.Add(new FieldPoint() { Tick = 0, LaneOffset = -score.HalfHorizontalResolution }); score.Field.Right.FieldWall.Points.Add(new FieldPoint() { Tick = 0, LaneOffset = score.HalfHorizontalResolution }); LoadBook(book); }
public DeleteScoreOperation( Model model, Score score, int count) { Score prev = model.ScoreBook.Prev(score); ScoreBook scoreList = new ScoreBook(); Score itrScore = score; for (int i = 0; i < count; ++i) { scoreList.Add(itrScore); itrScore = model.ScoreBook.Next(itrScore); } Invoke += () => { model.DeleteScore(scoreList.First(), count); }; Undo += () => { model.LaneBook.InsertScoreForward( model.ScoreBook, prev, scoreList); }; }
public ExportForm(MusicInfo musicInfo) { InitializeComponent(); scoreBook = null; noteBook = null; saveFileDialog = new SaveFileDialog() { FileName = "NewScore.sus", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Filter = "Seaurchin譜面ファイル(*.sus)|*.sus", FilterIndex = 0, Title = "エクスポート", RestoreDirectory = true }; musicSelectDialog = new OpenFileDialog() { FileName = "", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Filter = "音楽ファイル(*.wav;*.mp3;*.ogg)|*.wav;*.mp3;*.ogg", FilterIndex = 0, Title = "楽曲ファイル選択", RestoreDirectory = true }; jacketSelectDialog = new OpenFileDialog() { FileName = "", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Filter = "画像ファイル(*.bmp;*.jpg;*.png)|*.bmp;*.jpg;*.png", FilterIndex = 0, Title = "ジャケットファイル選択", RestoreDirectory = true }; exportButton.Click += ExportButton_Click; exportCancelButton.Click += (s, e) => { SaveMusicInfo(false); Close(); }; exportPathButton.Click += (s, e) => { saveFileDialog.InitialDirectory = Status.ExportDialogDirectory; if (saveFileDialog.ShowDialog() == DialogResult.OK) { exportPathText.Text = saveFileDialog.FileName; Status.ExportDialogDirectory = Directory.GetParent(saveFileDialog.FileName).ToString(); } }; musicPathButton.Click += (s, e) => { musicSelectDialog.InitialDirectory = Status.MusicDialogDirectory; if (musicSelectDialog.ShowDialog() == DialogResult.OK) { musicPathText.Text = Path.GetFileName(musicSelectDialog.FileName); Status.MusicDialogDirectory = Directory.GetParent(musicSelectDialog.FileName).ToString(); } }; jacketPathButton.Click += (s, e) => { jacketSelectDialog.InitialDirectory = Status.JacketDialogDirectory; if (jacketSelectDialog.ShowDialog() == DialogResult.OK) { JacketPathText.Text = Path.GetFileName(jacketSelectDialog.FileName); Status.JacketDialogDirectory = Directory.GetParent(jacketSelectDialog.FileName).ToString(); } }; pathClearButton.Click += (s, e) => exportPathText.Text = ""; musicPathClearButton.Click += (s, e) => musicPathText.Text = ""; jacketPathClearButton.Click += (s, e) => JacketPathText.Text = ""; DifficultyBox.SelectedIndexChanged += (s, e) => { if (DifficultyBox.SelectedIndex == 4) { weText.Enabled = weStarUpDown.Enabled = true; playLevelBox.Enabled = false; } else { weText.Enabled = weStarUpDown.Enabled = false; playLevelBox.Enabled = true; } }; DifficultyBox.SelectedIndex = 0; metoronomeBox.SelectedIndex = 0; LoadMusicInfo(musicInfo); }
public void ShowDialog(ScoreBook scoreBook, NoteBook noteBook) { this.scoreBook = scoreBook; this.noteBook = noteBook; ShowDialog(); }
public ExportForm(ScoreBook book) { InitializeComponent(); Icon = Properties.Resources.MainIcon; ShowInTaskbar = false; levelDropDown.Items.AddRange(Enumerable.Range(1, 14).SelectMany(p => new string[] { p.ToString(), p + "+" }).ToArray()); difficultyDropDown.Items.AddRange(new string[] { "BASIC", "ADVANCED", "EXPERT", "MASTER", "WORLD'S END" }); if (!book.ExporterArgs.ContainsKey(ArgsKey) || !(book.ExporterArgs[ArgsKey] is SusArgs)) { book.ExporterArgs[ArgsKey] = new SusArgs(); } var args = book.ExporterArgs[ArgsKey] as SusArgs; titleBox.Text = book.Title; artistBox.Text = book.ArtistName; notesDesignerBox.Text = book.NotesDesignerName; difficultyDropDown.SelectedIndex = (int)args.PlayDifficulty; levelDropDown.Text = args.PlayLevel; songIdBox.Text = args.SongId; soundFileBox.Text = args.SoundFileName; soundOffsetBox.Value = args.SoundOffset; jacketFileBox.Text = args.JacketFilePath; hasPaddingBarBox.Checked = args.HasPaddingBar; browseButton.Click += (s, e) => { var dialog = new SaveFileDialog() { Filter = Filter }; if (dialog.ShowDialog(this) == DialogResult.OK) { outputBox.Text = dialog.FileName; } }; exportButton.Click += (s, e) => { if (string.IsNullOrEmpty(OutputPath)) { browseButton.PerformClick(); } if (string.IsNullOrEmpty(OutputPath)) { MessageBox.Show(this, "出力先を指定してください。", Program.ApplicationName); return; } book.Title = titleBox.Text; book.ArtistName = artistBox.Text; book.NotesDesignerName = notesDesignerBox.Text; args.PlayDifficulty = (SusArgs.Difficulty)difficultyDropDown.SelectedIndex; args.PlayLevel = levelDropDown.Text; args.SongId = songIdBox.Text; args.SoundFileName = soundFileBox.Text; args.SoundOffset = soundOffsetBox.Value; args.JacketFilePath = jacketFileBox.Text; args.HasPaddingBar = hasPaddingBarBox.Checked; try { exporter.CustomArgs = args; exporter.Export(OutputPath, book); DialogResult = DialogResult.OK; Close(); } catch (Exception ex) { MessageBox.Show(this, "エクスポートに失敗しました。", Program.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); Program.DumpException(ex); } }; }
public MusicScore() { scoreBook = new ScoreBook(); noteBook = new NoteBook(); }
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)); });