private void AddPart() { var res = ShowRenamePartDialog(null); if (res.DialogResult.HasValue && res.DialogResult.Value) { var newPart = song.AddPart(res.PartName); this.StructureTree.SelectItem(newPart.Slides.First()); song.AddPartToOrder(newPart); } }
/// <summary> /// Helper function to process the imported properties after the actual song content is loaded. /// </summary> /// <param name="song">The imported song.</param> /// <param name="properties">A dictionary with properties.</param> private static void PostProcessSongBeamerProperties(Song song, Dictionary <string, string> properties) { if (properties.ContainsKey("verseorder")) { song.SetOrder(properties["verseorder"].Split(','), ignoreMissing: true); } else { // if no verseorder is specified, add each part once in order foreach (SongPart part in song.Parts) { song.AddPartToOrder(part); } } }
public void Read(Song song, Stream stream) { if (song == null) throw new ArgumentNullException("song"); if (stream == null) throw new ArgumentNullException("stream"); var doc = XDocument.Load(stream); if (doc.Root.Name != "song") { throw new SongFormatException("File is not a valid OpenSong song."); } var root = doc.Root; song.Title = root.Elements("title").Single().Value; song.Copyright = root.Elements("author").Any() ? root.Elements("author").Single().Value : String.Empty; if (root.Elements("copyright").Any()) { var copyright = root.Element("copyright").Value; if (!copyright.StartsWith("©") && !copyright.StartsWith("(c)")) copyright = "© " + copyright; song.Copyright = String.IsNullOrEmpty(song.Copyright) ? copyright : song.Copyright + "\n" + copyright; } song.Category = root.Elements("theme").Any() ? root.Element("theme").Value : String.Empty; song.CcliNumber = root.Elements("ccli").Any() ? int.Parse(root.Element("ccli").Value) : (int?)null; var lines = root.Elements("lyrics").Single().Value.Split('\n'); string partKey = null; LineGroup currentLineGroup = null; List<LineGroup> partLineGroups = null; for (int l = 0; l < lines.Length; l++) { var line = lines[l]; if (line.StartsWith("[")) // next part (or group of parts) { if (partKey != null) FinishPart(song, partKey, partLineGroups, currentLineGroup); var i = line.IndexOf("]"); if (i < 0) throw new SongFormatException("File is not a valid OpenSong song: Invalid part declaration."); partKey = line.Substring(1, i - 1).Trim(); partLineGroups = new List<LineGroup>(); currentLineGroup = null; } else // not the start of a new part { if (line.Trim() == String.Empty || line[0] == ';' || line.StartsWith("---")) { // ignore empty line, comments, '---' breaks (whatever they mean) continue; } if (partKey == null) // no part has been started -> create an anonymous one { partKey = "Unnamed"; partLineGroups = new List<LineGroup>(); } if (line[0] == '.') { // chord line -> always start new line group and set chords property if (currentLineGroup != null) partLineGroups.Add(currentLineGroup); currentLineGroup = new LineGroup { Chords = line.Substring(1) }; } else if (line[0] == ' ') { // lyrics line -> set lyrics to current LineGroup if (currentLineGroup == null || currentLineGroup.Lines.Count == 0) { if (currentLineGroup == null) { currentLineGroup = new LineGroup(); } currentLineGroup.Lines.Add(new Line { Text = line.Substring(1) }); partLineGroups.Add(currentLineGroup); currentLineGroup = null; } else { throw new SongFormatException("File is not a valid OpenSong song: Expected verse number."); } } else if (char.IsDigit(line[0])) { int vnum = int.Parse(line[0].ToString()); if (currentLineGroup == null) { currentLineGroup = new LineGroup(); } else if (currentLineGroup.Lines.Count > 0 && vnum <= currentLineGroup.Lines.Last().Number) { partLineGroups.Add(currentLineGroup); currentLineGroup = new LineGroup(); } currentLineGroup.Lines.Add(new Line { Text = line.Substring(1), Number = vnum }); } else { throw new SongFormatException("File is not a valid OpenSong song: Expected one of ' ', '.', ';' , '[0-9]'"); } } } if (partKey != null) FinishPart(song, partKey, partLineGroups, currentLineGroup); // parse order if (root.Elements("presentation").Any() && root.Elements("presentation").Single().Value.Trim() != String.Empty) { var val = root.Elements("presentation").Single().Value.Trim(); var split = wordRegex.Matches(val).Cast<Match>(); song.SetOrder(split.Select(m => GetPartName(m.Value)), ignoreMissing: true); } else { // if no order is specified, add each part once in order foreach (SongPart part in song.Parts) { song.AddPartToOrder(part); } } }
/// <summary> /// Helper function to process the imported properties after the actual song content is loaded. /// </summary> /// <param name="song">The imported song.</param> /// <param name="properties">A dictionary with properties.</param> private static void PostProcessSongBeamerProperties(Song song, Dictionary<string, string> properties) { if (properties.ContainsKey("verseorder")) { song.SetOrder(properties["verseorder"].Split(','), ignoreMissing: true); } else { // if no verseorder is specified, add each part once in order foreach (SongPart part in song.Parts) { song.AddPartToOrder(part); } } }
public override void Read(Song song, Stream stream) { if (song == null) { throw new ArgumentNullException("song"); } if (stream == null) { throw new ArgumentNullException("stream"); } using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) { string line; int lineType = 0; List <string> verseLineList = null; string verseType = null; bool checkFirstLine = false; string copyright = null; while ((line = reader.ReadLine()) != null) { var cleanLine = line.Trim(); if (String.IsNullOrEmpty(cleanLine)) { if (lineType == 0) { continue; } else if (verseLineList != null) // empty line and there were lyrics before -> create part { var part = new SongPart(song, verseType); var slide = new SongSlide(song); slide.Text = String.Join("\n", verseLineList.ToArray()); part.AddSlide(slide); song.AddPart(part); song.AddPartToOrder(part); verseLineList = null; } } else // not an empty line { if (lineType == 0) // very first line -> song title { song.Title = cleanLine; lineType++; } else if (lineType == 1) // lyrics/parts { if (cleanLine.StartsWith("CCLI")) // end of lyrics, start of copyright information { lineType++; string num = cleanLine.Split(' ').Last(); song.CcliNumber = int.Parse(num); } else if (verseLineList == null) { verseType = GetPartName(cleanLine, out checkFirstLine); verseLineList = new List <string>(); } else { if (checkFirstLine) { if (!CheckFirstLine(cleanLine, ref verseType)) { // add text if it was not a part name verseLineList.Add(line); } checkFirstLine = false; } else { verseLineList.Add(line); } } } else if (lineType == 2) // copyright information { if (copyright == null) { copyright = cleanLine; } else { copyright += "\n" + cleanLine; } } } } song.Copyright = copyright; } }
// documentation taken from http://bazaar.launchpad.net/~openlp-core/openlp/trunk/view/head:/openlp/plugins/songs/lib/cclifileimport.py // [File] // USR file format first line // Type= // Indicates the file type // e.g. Type=SongSelect Import File // Version=3.0 // File format version // [S A2672885] // Contains the CCLI Song number e.g. 2672885 // Title= // Contains the song title (e.g. Title=Above All) // Author= // Contains a | delimited list of the song authors // e.g. Author=LeBlanc, Lenny | Baloche, Paul // Copyright= // Contains a | delimited list of the song copyrights // e.g. Copyright=1999 Integrity's Hosanna! Music | // LenSongs Publishing (Verwaltet von Gerth Medien // Musikverlag) // Admin= // Contains the song administrator // e.g. Admin=Gerth Medien Musikverlag // Themes= // Contains a /t delimited list of the song themes // e.g. Themes=Cross/tKingship/tMajesty/tRedeemer // Keys= // Contains the keys in which the music is played?? // e.g. Keys=A // Fields= // Contains a list of the songs fields in order /t delimited // e.g. Fields=Vers 1/tVers 2/tChorus 1/tAndere 1 // Words= // Contains the songs various lyrics in order as shown by the // Fields description // e.g. Words=Above all powers.... [/n = CR, /n/t = CRLF] public override void Read(Song song, Stream stream) { if (song == null) throw new ArgumentNullException("song"); if (stream == null) throw new ArgumentNullException("stream"); using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) { string line; string authors = null; string copyright = null; string[] fieldsList = null; string[] wordsList = null; while ((line = reader.ReadLine()) != null) { if (line.StartsWith("[S ")) { // CCLI Song number int end = line.IndexOf(']'); if (end > 1) { string num = line.Substring(3, end - 3); if (num.StartsWith("A")) num = num.Substring(1); song.CcliNumber = int.Parse(num); } } else if (line.StartsWith("Title=")) { song.Title = line.Substring("Title=".Length).Trim(); } else if (line.StartsWith("Author=")) { var authorList = line.Substring("Author=".Length).Trim().Split('|').Select(s => s.Trim()).ToArray(); authors = String.Join(", ", authorList); } else if (line.StartsWith("Copyright=")) { copyright = line.Substring("Copyright=".Length).Trim(); } else if (line.StartsWith("Themes=")) { var themesList = line.Substring("Themes=".Length).Trim().Replace(" | ", "/t"). Split(new string[] { "/t" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray(); song.Category = String.Join(", ", themesList); } else if (line.StartsWith("Fields=")) { fieldsList = line.Substring("Fields=".Length).Trim().Split(new string[] {"/t"}, StringSplitOptions.None).Select(s => s.Trim()).ToArray(); } else if (line.StartsWith("Words=")) { wordsList = line.Substring("Words=".Length).Trim().Split(new string[] { "/t" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray(); } // Unhandled usr keywords: Type, Version, Admin, Keys } if (fieldsList == null || wordsList == null || authors == null || copyright == null) { throw new SongFormatException("Missing field in USR file."); } var partNum = (fieldsList.Length < wordsList.Length) ? fieldsList.Length : wordsList.Length; for (int i = 0; i < partNum; i++) { bool checkFirstLine; var partName = GetPartName(fieldsList[i], out checkFirstLine); string text = wordsList[i].Replace("/n", "\n").Replace(" | ", "\n").TrimEnd(); if (checkFirstLine) { var lines = text.Split('\n'); var firstLine = lines[0].Trim(); if (CheckFirstLine(firstLine, ref partName)) { text = text.Substring(text.IndexOf('\n') + 1); } } var part = new SongPart(song, partName); var slide = new SongSlide(song); slide.Text = text; part.AddSlide(slide); song.AddPart(part); song.AddPartToOrder(part); } song.Copyright = authors + "\n© " + copyright; } }
// documentation taken from http://bazaar.launchpad.net/~openlp-core/openlp/trunk/view/head:/openlp/plugins/songs/lib/cclifileimport.py // [File] // USR file format first line // Type= // Indicates the file type // e.g. Type=SongSelect Import File // Version=3.0 // File format version // [S A2672885] // Contains the CCLI Song number e.g. 2672885 // Title= // Contains the song title (e.g. Title=Above All) // Author= // Contains a | delimited list of the song authors // e.g. Author=LeBlanc, Lenny | Baloche, Paul // Copyright= // Contains a | delimited list of the song copyrights // e.g. Copyright=1999 Integrity's Hosanna! Music | // LenSongs Publishing (Verwaltet von Gerth Medien // Musikverlag) // Admin= // Contains the song administrator // e.g. Admin=Gerth Medien Musikverlag // Themes= // Contains a /t delimited list of the song themes // e.g. Themes=Cross/tKingship/tMajesty/tRedeemer // Keys= // Contains the keys in which the music is played?? // e.g. Keys=A // Fields= // Contains a list of the songs fields in order /t delimited // e.g. Fields=Vers 1/tVers 2/tChorus 1/tAndere 1 // Words= // Contains the songs various lyrics in order as shown by the // Fields description // e.g. Words=Above all powers.... [/n = CR, /n/t = CRLF] public override void Read(Song song, Stream stream) { if (song == null) { throw new ArgumentNullException("song"); } if (stream == null) { throw new ArgumentNullException("stream"); } using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) { string line; string authors = null; string copyright = null; string[] fieldsList = null; string[] wordsList = null; while ((line = reader.ReadLine()) != null) { if (line.StartsWith("[S ")) { // CCLI Song number int end = line.IndexOf(']'); if (end > 1) { string num = line.Substring(3, end - 3); if (num.StartsWith("A")) { num = num.Substring(1); } song.CcliNumber = int.Parse(num); } } else if (line.StartsWith("Title=")) { song.Title = line.Substring("Title=".Length).Trim(); } else if (line.StartsWith("Author=")) { var authorList = line.Substring("Author=".Length).Trim().Split('|').Select(s => s.Trim()).ToArray(); authors = String.Join(", ", authorList); } else if (line.StartsWith("Copyright=")) { copyright = line.Substring("Copyright=".Length).Trim(); } else if (line.StartsWith("Themes=")) { var themesList = line.Substring("Themes=".Length).Trim().Replace(" | ", "/t"). Split(new string[] { "/t" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray(); song.Category = String.Join(", ", themesList); } else if (line.StartsWith("Fields=")) { fieldsList = line.Substring("Fields=".Length).Trim().Split(new string[] { "/t" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray(); } else if (line.StartsWith("Words=")) { wordsList = line.Substring("Words=".Length).Trim().Split(new string[] { "/t" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray(); } // Unhandled usr keywords: Type, Version, Admin, Keys } if (fieldsList == null || wordsList == null || authors == null || copyright == null) { throw new SongFormatException("Missing field in USR file."); } var partNum = (fieldsList.Length < wordsList.Length) ? fieldsList.Length : wordsList.Length; for (int i = 0; i < partNum; i++) { bool checkFirstLine; var partName = GetPartName(fieldsList[i], out checkFirstLine); string text = wordsList[i].Replace("/n", "\n").Replace(" | ", "\n").TrimEnd(); if (checkFirstLine) { var lines = text.Split('\n'); var firstLine = lines[0].Trim(); if (CheckFirstLine(firstLine, ref partName)) { text = text.Substring(text.IndexOf('\n') + 1); } } var part = new SongPart(song, partName); var slide = new SongSlide(song); slide.Text = text; part.AddSlide(slide); song.AddPart(part); song.AddPartToOrder(part); } song.Copyright = authors + "\n© " + copyright; } }
public override void Read(Song song, Stream stream) { if (song == null) throw new ArgumentNullException("song"); if (stream == null) throw new ArgumentNullException("stream"); using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) { string line; int lineType = 0; List<string> verseLineList = null; string verseType = null; bool checkFirstLine = false; string copyright = null; while ((line = reader.ReadLine()) != null) { var cleanLine = line.Trim(); if (String.IsNullOrEmpty(cleanLine)) { if (lineType == 0) { continue; } else if (verseLineList != null) // empty line and there were lyrics before -> create part { var part = new SongPart(song, verseType); var slide = new SongSlide(song); slide.Text = String.Join("\n", verseLineList.ToArray()); part.AddSlide(slide); song.AddPart(part); song.AddPartToOrder(part); verseLineList = null; } } else // not an empty line { if (lineType == 0) // very first line -> song title { song.Title = cleanLine; lineType++; } else if (lineType == 1) // lyrics/parts { if (cleanLine.StartsWith("CCLI")) // end of lyrics, start of copyright information { lineType++; string num = cleanLine.Split(' ').Last(); song.CcliNumber = int.Parse(num); } else if (verseLineList == null) { verseType = GetPartName(cleanLine, out checkFirstLine); verseLineList = new List<string>(); } else { if (checkFirstLine) { if (!CheckFirstLine(cleanLine, ref verseType)) { // add text if it was not a part name verseLineList.Add(line); } checkFirstLine = false; } else { verseLineList.Add(line); } } } else if (lineType == 2) // copyright information { if (copyright == null) { copyright = cleanLine; } else { copyright += "\n" + cleanLine; } } } } song.Copyright = copyright; } }
public void Read(Song song, Stream stream) { if (song == null) { throw new ArgumentNullException("song"); } if (stream == null) { throw new ArgumentNullException("stream"); } var doc = XDocument.Load(stream); if (doc.Root.Name != "song") { throw new SongFormatException("File is not a valid OpenSong song."); } var root = doc.Root; song.Title = root.Elements("title").Single().Value; song.Copyright = root.Elements("author").Any() ? root.Elements("author").Single().Value : String.Empty; if (root.Elements("copyright").Any()) { var copyright = root.Element("copyright").Value; if (!copyright.StartsWith("©") && !copyright.StartsWith("(c)")) { copyright = "© " + copyright; } song.Copyright = String.IsNullOrEmpty(song.Copyright) ? copyright : song.Copyright + "\n" + copyright; } song.Category = root.Elements("theme").Any() ? root.Element("theme").Value : String.Empty; song.CcliNumber = root.Elements("ccli").Any() ? int.Parse(root.Element("ccli").Value) : (int?)null; var lines = root.Elements("lyrics").Single().Value.Split('\n'); string partKey = null; LineGroup currentLineGroup = null; List <LineGroup> partLineGroups = null; for (int l = 0; l < lines.Length; l++) { var line = lines[l]; if (line.StartsWith("[")) // next part (or group of parts) { if (partKey != null) { FinishPart(song, partKey, partLineGroups, currentLineGroup); } var i = line.IndexOf("]"); if (i < 0) { throw new SongFormatException("File is not a valid OpenSong song: Invalid part declaration."); } partKey = line.Substring(1, i - 1).Trim(); partLineGroups = new List <LineGroup>(); currentLineGroup = null; } else // not the start of a new part { if (line.Trim() == String.Empty || line[0] == ';' || line.StartsWith("---")) { // ignore empty line, comments, '---' breaks (whatever they mean) continue; } if (partKey == null) // no part has been started -> create an anonymous one { partKey = "Unnamed"; partLineGroups = new List <LineGroup>(); } if (line[0] == '.') { // chord line -> always start new line group and set chords property if (currentLineGroup != null) { partLineGroups.Add(currentLineGroup); } currentLineGroup = new LineGroup { Chords = line.Substring(1) }; } else if (line[0] == ' ') { // lyrics line -> set lyrics to current LineGroup if (currentLineGroup == null || currentLineGroup.Lines.Count == 0) { if (currentLineGroup == null) { currentLineGroup = new LineGroup(); } currentLineGroup.Lines.Add(new Line { Text = line.Substring(1) }); partLineGroups.Add(currentLineGroup); currentLineGroup = null; } else { throw new SongFormatException("File is not a valid OpenSong song: Expected verse number."); } } else if (char.IsDigit(line[0])) { int vnum = int.Parse(line[0].ToString()); if (currentLineGroup == null) { currentLineGroup = new LineGroup(); } else if (currentLineGroup.Lines.Count > 0 && vnum <= currentLineGroup.Lines.Last().Number) { partLineGroups.Add(currentLineGroup); currentLineGroup = new LineGroup(); } currentLineGroup.Lines.Add(new Line { Text = line.Substring(1), Number = vnum }); } else { throw new SongFormatException("File is not a valid OpenSong song: Expected one of ' ', '.', ';' , '[0-9]'"); } } } if (partKey != null) { FinishPart(song, partKey, partLineGroups, currentLineGroup); } // parse order if (root.Elements("presentation").Any() && root.Elements("presentation").Single().Value.Trim() != String.Empty) { var val = root.Elements("presentation").Single().Value.Trim(); var split = wordRegex.Matches(val).Cast <Match>(); song.SetOrder(split.Select(m => GetPartName(m.Value)), ignoreMissing: true); } else { // if no order is specified, add each part once in order foreach (SongPart part in song.Parts) { song.AddPartToOrder(part); } } }
public void Read(Song song, Stream stream) { if (song == null) { throw new ArgumentNullException("song"); } if (stream == null) { throw new ArgumentNullException("stream"); } using (StreamReader reader = new StreamReader(stream, Encoding.Default, true)) { string line; bool inTab = false; SongPart chorusPart = null; string currentText = null; string nextPartName = null; string currentPartName = null; while ((line = reader.ReadLine()) != null) { var trimmed = line.Trim(); if (trimmed.StartsWith("#")) { continue; // ignore comment line } if (trimmed.StartsWith("{") && trimmed.EndsWith("}")) { var tag = trimmed.Substring(1, trimmed.Length - 2); if (tag.StartsWith("title:") || tag.StartsWith("t:")) { song.Title = tag.Substring(tag.IndexOf(':') + 1); nextPartName = null; continue; } else if (tag.StartsWith("subtitle:") || tag.StartsWith("st:")) { song.Copyright = tag.Substring(tag.IndexOf(':') + 1); nextPartName = null; continue; } else if (tag.StartsWith("comment:") || tag.StartsWith("c:") || tag.StartsWith("comment_italic:") || tag.StartsWith("ci:") || tag.StartsWith("comment_box:") || tag.StartsWith("cb:")) { if (tag.EndsWith(":") && chorusPart == null) { // we found a comment that might be a part name and we're not in the chorus // -> remember it for later use var name = tag.Substring(tag.IndexOf(':') + 1); nextPartName = name.Substring(0, name.Length - 1); } continue; } else if (tag.StartsWith("start_of_tab") || tag.StartsWith("sot")) { inTab = true; nextPartName = null; continue; } else if (tag.StartsWith("end_of_tab") || tag.StartsWith("eot")) { inTab = false; nextPartName = null; continue; } else if (tag.StartsWith("start_of_chorus") || tag.StartsWith("soc")) { var chorusName = "Chorus"; if (song.FindPartByName(chorusName) != null) { int i = 2; while (song.FindPartByName(chorusName + " " + i.ToString()) != null) { i++; } chorusName = chorusName + " " + i.ToString(); } chorusPart = new SongPart(song, chorusName); nextPartName = null; continue; } else if (tag.StartsWith("end_of_chorus") || tag.StartsWith("eoc")) { if (chorusPart != null) { // commit slide and part if (currentText != null) { chorusPart.AddSlide(new SongSlide(song) { Text = currentText }); currentText = null; } song.AddPart(chorusPart); chorusPart = null; } nextPartName = null; continue; } else if (tag.StartsWith("define")) { // ignore nextPartName = null; continue; } // else accept {...} as normal text } if (!inTab) { if (trimmed == String.Empty) { nextPartName = null; if (currentText != null) { if (chorusPart != null) // in chorus { // commit slide chorusPart.AddSlide(new SongSlide(song) { Text = currentText }); currentText = null; } else { // commit part var partName = currentPartName == null?FindUnusedPartName(song) : currentPartName; var part = new SongPart(song, partName); part.AddSlide(new SongSlide(song) { Text = currentText }); song.AddPart(part); currentText = null; } } } else { // actual text/chord line -> add to current text // need no further parsing because chords are already in correct format (square brackets) if (currentText == null) { currentText = trimmed; // use previously remembered part name for this part currentPartName = nextPartName; nextPartName = null; } else { currentText += "\n" + trimmed; } } } } // TODO: get rid of code duplication if (currentText != null) { if (chorusPart != null) // in chorus { // commit slide and part chorusPart.AddSlide(new SongSlide(song) { Text = currentText }); currentText = null; song.AddPart(chorusPart); } else { // commit part var partName = currentPartName == null?FindUnusedPartName(song) : currentPartName; var part = new SongPart(song, partName); part.AddSlide(new SongSlide(song) { Text = currentText }); song.AddPart(part); currentText = null; } } } // add each part to order foreach (SongPart part in song.Parts) { song.AddPartToOrder(part); } }
public void Read(Song song, Stream stream) { if (song == null) throw new ArgumentNullException("song"); if (stream == null) throw new ArgumentNullException("stream"); using (StreamReader reader = new StreamReader(stream, Encoding.Default, true)) { string line; bool inTab = false; SongPart chorusPart = null; string currentText = null; string nextPartName = null; string currentPartName = null; while ((line = reader.ReadLine()) != null) { var trimmed = line.Trim(); if (trimmed.StartsWith("#")) { continue; // ignore comment line } if (trimmed.StartsWith("{") && trimmed.EndsWith("}")) { var tag = trimmed.Substring(1, trimmed.Length - 2); if (tag.StartsWith("title:") || tag.StartsWith("t:")) { song.Title = tag.Substring(tag.IndexOf(':') + 1); nextPartName = null; continue; } else if (tag.StartsWith("subtitle:") || tag.StartsWith("st:")) { song.Copyright = tag.Substring(tag.IndexOf(':') + 1); nextPartName = null; continue; } else if (tag.StartsWith("comment:") || tag.StartsWith("c:") || tag.StartsWith("comment_italic:") || tag.StartsWith("ci:") || tag.StartsWith("comment_box:") || tag.StartsWith("cb:")) { if (tag.EndsWith(":") && chorusPart == null) { // we found a comment that might be a part name and we're not in the chorus // -> remember it for later use var name = tag.Substring(tag.IndexOf(':') + 1); nextPartName = name.Substring(0, name.Length - 1); } continue; } else if (tag.StartsWith("start_of_tab") || tag.StartsWith("sot")) { inTab = true; nextPartName = null; continue; } else if (tag.StartsWith("end_of_tab") || tag.StartsWith("eot")) { inTab = false; nextPartName = null; continue; } else if (tag.StartsWith("start_of_chorus") || tag.StartsWith("soc")) { var chorusName = "Chorus"; if (song.FindPartByName(chorusName) != null) { int i = 2; while (song.FindPartByName(chorusName + " " + i.ToString()) != null) { i++; } chorusName = chorusName + " " + i.ToString(); } chorusPart = new SongPart(song, chorusName); nextPartName = null; continue; } else if (tag.StartsWith("end_of_chorus") || tag.StartsWith("eoc")) { if (chorusPart != null) { // commit slide and part if (currentText != null) { chorusPart.AddSlide(new SongSlide(song) { Text = currentText }); currentText = null; } song.AddPart(chorusPart); chorusPart = null; } nextPartName = null; continue; } else if (tag.StartsWith("define")) { // ignore nextPartName = null; continue; } // else accept {...} as normal text } if (!inTab) { if (trimmed == String.Empty) { nextPartName = null; if (currentText != null) { if (chorusPart != null) // in chorus { // commit slide chorusPart.AddSlide(new SongSlide(song) { Text = currentText }); currentText = null; } else { // commit part var partName = currentPartName == null ? FindUnusedPartName(song) : currentPartName; var part = new SongPart(song, partName); part.AddSlide(new SongSlide(song) { Text = currentText }); song.AddPart(part); currentText = null; } } } else { // actual text/chord line -> add to current text // need no further parsing because chords are already in correct format (square brackets) if (currentText == null) { currentText = trimmed; // use previously remembered part name for this part currentPartName = nextPartName; nextPartName = null; } else { currentText += "\n" + trimmed; } } } } // TODO: get rid of code duplication if (currentText != null) { if (chorusPart != null) // in chorus { // commit slide and part chorusPart.AddSlide(new SongSlide(song) { Text = currentText }); currentText = null; song.AddPart(chorusPart); } else { // commit part var partName = currentPartName == null ? FindUnusedPartName(song) : currentPartName; var part = new SongPart(song, partName); part.AddSlide(new SongSlide(song) { Text = currentText }); song.AddPart(part); currentText = null; } } } // add each part to order foreach (SongPart part in song.Parts) { song.AddPartToOrder(part); } }