From 7b7a982e08e158ec27ee8b0229aa0af498cc9a81 Mon Sep 17 00:00:00 2001 From: Fabrice Lacharme Date: Wed, 29 Jan 2025 18:08:41 +0100 Subject: [PATCH] lrc cut lines --- Karaboss/Lyrics/frmLrcOptions.cs | 48 ++- Karaboss/Lyrics/frmLyricsEdit.cs | 257 +------------- Karaboss/Utilities/Lyrics/LyricsUtilities.cs | 314 +++++++++++++++++- .../Utilities/MidiFile/CreateNewMidiFile.cs | 36 +- Karaboss/Utilities/Tempo/TempoUtilities.cs | 36 +- 5 files changed, 429 insertions(+), 262 deletions(-) diff --git a/Karaboss/Lyrics/frmLrcOptions.cs b/Karaboss/Lyrics/frmLrcOptions.cs index 1d424d4..2d11ed4 100644 --- a/Karaboss/Lyrics/frmLrcOptions.cs +++ b/Karaboss/Lyrics/frmLrcOptions.cs @@ -1,4 +1,38 @@ -using System; +#region License + +/* Copyright (c) 2025 Fabrice Lacharme + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#endregion + +#region Contact + +/* + * Fabrice Lacharme + * Email: fabrice.lacharme@gmail.com + */ + +#endregion + +using System; using System.Windows.Forms; using static Karaboss.Karaclass; @@ -52,7 +86,9 @@ public bool bCutLines #endregion properties - //public frmLrcOptions(Karaclass.LrcFormats LrcFormat, bool bRemoveAccents, bool bForceUpperCase, bool bRemoveNonAlphaNumeric) + /// + /// Constructor + /// public frmLrcOptions() { InitializeComponent(); @@ -139,16 +175,12 @@ private void OptFormatSyllabes_CheckedChanged(object sender, EventArgs e) chkCutLines.Visible = !OptFormatSyllabes.Checked; UpdCutLines.Visible = !OptFormatSyllabes.Checked; lblCutLines.Visible = !OptFormatSyllabes.Checked; - //UpdCutLines.Visible = chkCutLines.Visible && chkCutLines.Checked; - //lblCutLines.Visible = chkCutLines.Visible && chkCutLines.Checked; } private void OptFormatLines_CheckedChanged(object sender, EventArgs e) { - chkCutLines.Visible = OptFormatLines.Checked; - //UpdCutLines.Visible = chkCutLines.Visible && chkCutLines.Checked; - //lblCutLines.Visible = chkCutLines.Visible && chkCutLines.Checked; - + chkCutLines.Visible = OptFormatLines.Checked; } + } } diff --git a/Karaboss/Lyrics/frmLyricsEdit.cs b/Karaboss/Lyrics/frmLyricsEdit.cs index 7a50895..849b717 100644 --- a/Karaboss/Lyrics/frmLyricsEdit.cs +++ b/Karaboss/Lyrics/frmLyricsEdit.cs @@ -2231,7 +2231,7 @@ private void SaveLRCLines(string File, bool bRemoveAccents, bool bUpperCase, boo string cr = "\r\n"; string strSpaceBetween; bool bSpaceBetwwen = false; - bool bStartLine; + //bool bStartLine; //bool bControlLength = true; //int MaxLength = 38; @@ -2319,262 +2319,27 @@ private void SaveLRCLines(string File, bool bRemoveAccents, bool bUpperCase, boo } #endregion List of Lyrics - - #region List of Lines - - // Store lyrics in lines - - // List to store lines - List lstLines = new List(); - List lstTimeLines = new List(); - - bStartLine = true; - // sTime, sType, sLyric - for (int i = 0; i < lstLyricsItems.Count; i++) - { - sTime = lstLyricsItems[i].Item1; - sType = lstLyricsItems[i].Item2; - sLyric = lstLyricsItems[i].Item3; - - if (sType == "text") // Do not add empty lyrics to a line ? - { - - if (bStartLine) - { - if (sLyric.Length > 0 && sLyric.StartsWith(" ")) - sLyric = sLyric.Remove(0, 1); - sLine = sTime + strSpaceBetween + sLyric; // time + lyric for the beginning of a line - sTimeLine = sTime + strSpaceBetween + sLyric; - bStartLine = false; - } - else - { - // Line continuation - sLine += sLyric; // only lyric for the continuation of a line - sTimeLine += sTime + strSpaceBetween + sLyric; - } - } - else - { - - // Remove last space - if (sLine.Length > 0 && sLine.EndsWith(" ")) - sLine = sLine.Remove(sLine.Length - 1, 1); - - if (sTimeLine.Length > 0 && sTimeLine.EndsWith(" ")) - sTimeLine = sTimeLine.Remove(sTimeLine.Length - 1, 1); - - - // Save current line - if (sLine != "") - { - // Add new line - lstLines.Add(sLine); - } - - if (sTimeLine != "") - { - // Add new line - lstTimeLines.Add(sTimeLine); - } - - // Reset all - bStartLine = true; - sLine = string.Empty; - sTimeLine = string.Empty; - } - } - // Save last line - if (sLine != "") - { - lstLines.Add(sLine); - } - - // Save last line - if (sTimeLine != "") - { - // Remove last space - if (sTimeLine.Length > 0 && sTimeLine.EndsWith(" ")) - sTimeLine = sTimeLine.Remove(sTimeLine.Length - 1, 1); - lstTimeLines.Add(sTimeLine); - } - - - #region deleteme - /* - // Store lyrics in lines with cuts - bStartLine = true; - // sTime, sType, sLyric - for (int i = 0; i < lstLyricsItems.Count; i++) - { - sTime = lstLyricsItems[i].Item1; - sType = lstLyricsItems[i].Item2; - sLyric = lstLyricsItems[i].Item3; - - if (sType == "text") // Do not add empty lyrics to a line ? - { - // Length control: Can we add the next lyric to the current line ? - // Is it a cut inside a word ??????????????????????????????????????????????? - if (bControlLength && (strPartialLine + sLyric).Length > MaxLength) - { - // if not: save current line and start a new one with this lyric - // Remove last space - if (sLine.Length > 0 && sLine.EndsWith(" ")) - sLine = sLine.Remove(sLine.Length - 1, 1); - // Save current line - lrcs += sLine + cr; - - // Start a new line - if (sLyric.Length > 0 && sLyric.StartsWith(" ")) - sLyric = sLyric.Remove(0, 1); - sLine = sTime + strSpaceBetween + sLyric; - bStartLine = false; - strPartialLine = sLyric; - } - else - { - // No length control - strPartialLine += sLyric; - if (bStartLine) - { - if (sLyric.Length > 0 && sLyric.StartsWith(" ")) - sLyric = sLyric.Remove(0, 1); - sLine = sTime + strSpaceBetween + sLyric; // time + lyric for the beginning of a line - bStartLine = false; - } - else - { - // Line continuation - sLine += sLyric; // only lyric for the continuation of a line - } - } - } - else - { - - // Remove last space - if (sLine.Length > 0 && sLine.EndsWith(" ")) - sLine = sLine.Remove(sLine.Length - 1, 1); - - // Save current line - if (sLine != "") - { - // Add new line - lrcs += sLine + cr; - } - - // Reset all - bStartLine = true; - sLine = string.Empty; - strPartialLine = string.Empty; - } - } - // Save last line - if (sLine != "") - { - lrcs += sLine + cr; - } - */ - #endregion deleteme - - #endregion List of lines - - - #region List of lines cut - - List lstWords = new List(); - List lstTimes = new List(); - - string[] words; - string[] Times; - string removepattern = @"\[\d{2}[:]\d{2}[.]\d{3}\]"; - string replace = @""; - for (int i = 0; i < lstTimeLines.Count; i++) - { - sTimeLine = lstTimeLines[i]; - words = sTimeLine.Split(' '); - Times = new string[words.Length]; - for (int j = 0; j < words.Length; j++) - { - Times[j] = words[j].Substring(0, 11); - words[j] = Regex.Replace(words[j], removepattern, replace); - } - lstWords.Add(words); - lstTimes.Add(Times); - } + + // Store lyrics in lines + List lstLines = Utilities.LyricsUtilities.GetLrcLines(lstLyricsItems, strSpaceBetween); + // Store timestamps + lyrics in lines + List lstTimeLines = Utilities.LyricsUtilities.GetLrcTimeLines(lstLyricsItems, strSpaceBetween); - // Manage length - List lstLinesCut = new List(); - strPartialLine = string.Empty; - sLine = string.Empty; - string[] ItemsW; - string[] ItemsT; - for (int i = 0; i < lstWords.Count; i++) - { - ItemsT = lstTimes[i]; - ItemsW = lstWords[i]; - sLine = string.Empty; - - for (int j = 0; j < ItemsW.Count(); j++) - { - bStartLine = (j == 0); - sLyric = ItemsW[j]; - sTime = ItemsT[j]; - - if ( !bStartLine && (strPartialLine + " " + sLyric).Length > MaxLength) - { - // Too long - // Remove last space - if (sLine.Length > 0 && sLine.EndsWith(" ")) - sLine = sLine.Remove(sLine.Length - 1, 1); - lstLinesCut.Add(sLine); - - // Restart a new line - sLine = sTime + sLyric + " "; - strPartialLine = sLyric + " "; - - } - else - { - if (bStartLine) - { - sLine = sTime + sLyric + " "; - strPartialLine = sLyric + " "; - } - else - { - sLine += sLyric + " "; - strPartialLine += sLyric + " "; - } - } - } - - // Remove last space - if (sLine.Length > 0 && sLine.EndsWith(" ")) - sLine = sLine.Remove(sLine.Length - 1, 1); - lstLinesCut.Add(sLine); - sLine = string.Empty; - } - - if (sLine != string.Empty) - { - // Remove last space - if (sLine.Length > 0 && sLine.EndsWith(" ")) - sLine = sLine.Remove(sLine.Length - 1, 1); - lstLinesCut.Add(sLine); - } - - #endregion List of lines cut + // Store lyrics by line and cut lines to MaxLength characters using lstTimeLines + List lstLinesCut = Utilities.LyricsUtilities.GetLrcLinesCut(lstTimeLines, MaxLength); + #region send all to string + // Header lrcs = string.Empty; for (int i = 0; i < lstHeaderLines.Count; i++) { lrcs += lstHeaderLines[i] + cr; } + // Lines if (bControlLength) { for (int i = 0; i < lstLinesCut.Count; i++) diff --git a/Karaboss/Utilities/Lyrics/LyricsUtilities.cs b/Karaboss/Utilities/Lyrics/LyricsUtilities.cs index 4237513..1447da4 100644 --- a/Karaboss/Utilities/Lyrics/LyricsUtilities.cs +++ b/Karaboss/Utilities/Lyrics/LyricsUtilities.cs @@ -1,12 +1,42 @@ -using System; +#region License + +/* Copyright (c) 2025 Fabrice Lacharme + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#endregion + +#region Contact + +/* + * Fabrice Lacharme + * Email: fabrice.lacharme@gmail.com + */ + +#endregion + +using System; using System.Collections.Generic; -using System.Drawing; using System.Linq; -using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; using System.Windows.Forms; -using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrackBar; namespace Karaboss.Utilities { @@ -290,7 +320,279 @@ public static int TimeToTicks(string time, double Division, int max) return tic; } - + + #region LRC + + /// + /// Returns lyrics by lines + /// format [00:08.834]QUAND J'AI RENCONTRE JOSEPHINE" + /// + /// + /// + /// + public static List GetLrcLines(List<(string, string, string)> lstLyricsItems, string strSpaceBetween) + { + List lstLines = new List(); + + bool bStartLine; + string sTime; + string sType; + string sLyric; + string sLine = string.Empty; + + bStartLine = true; + + try + { + // sTime, sType, sLyric + for (int i = 0; i < lstLyricsItems.Count; i++) + { + sTime = lstLyricsItems[i].Item1; + sType = lstLyricsItems[i].Item2; + sLyric = lstLyricsItems[i].Item3; + + if (sType == "text") // Do not add empty lyrics to a line ? + { + + if (bStartLine) + { + if (sLyric.Length > 0 && sLyric.StartsWith(" ")) + sLyric = sLyric.Remove(0, 1); + sLine = sTime + strSpaceBetween + sLyric; // time + lyric for the beginning of a line + bStartLine = false; + } + else + { + // Line continuation + sLine += sLyric; // only lyric for the continuation of a line + } + } + else + { + // Remove last space + if (sLine.Length > 0 && sLine.EndsWith(" ")) + sLine = sLine.Remove(sLine.Length - 1, 1); + + // Save current line + if (sLine != "") + { + // Add new line + lstLines.Add(sLine); + } + + // Reset all + bStartLine = true; + sLine = string.Empty; + } + } + // Save last line + if (sLine != "") + { + lstLines.Add(sLine); + } + } + catch (Exception e) + { + MessageBox.Show(e.Message, "Karaboss", MessageBoxButtons.OK, MessageBoxIcon.Error); + //return null; + } + + return lstLines; + } + + + /// + /// Return lyrics by line with their timestamps + /// Format [00:08.834]QUAND [00:09.107]J'AI [00:09.196]REN[00:09.469]CON[00:09.558]TRE [00:09.926]JO[00:10.107]SE[00:10.307]PHI[00:10.656]NE + /// + /// + /// + /// + public static List GetLrcTimeLines(List<(string, string, string)> lstLyricsItems, string strSpaceBetween) + { + List lstTimeLines = new List(); + + bool bStartLine; + string sTime; + string sType; + string sLyric; + string sTimeLine = string.Empty; + bStartLine = true; + + try + { + // sTime, sType, sLyric + for (int i = 0; i < lstLyricsItems.Count; i++) + { + sTime = lstLyricsItems[i].Item1; + sType = lstLyricsItems[i].Item2; + sLyric = lstLyricsItems[i].Item3; + + if (sType == "text") // Do not add empty lyrics to a line ? + { + if (bStartLine) + { + if (sLyric.Length > 0 && sLyric.StartsWith(" ")) + sLyric = sLyric.Remove(0, 1); + sTimeLine = sTime + strSpaceBetween + sLyric; + bStartLine = false; + } + else + { + // Line continuation + + // Case of spaces at the left of the lyrics + // Add a space to the left to allow split by space + if (sLyric.Length > 0 && sLyric.StartsWith(" ")) + sTimeLine += " " + sTime + strSpaceBetween + sLyric.Remove(0, 1); + else + sTimeLine += sTime + strSpaceBetween + sLyric; + } + } + else + { + if (sTimeLine.Length > 0 && sTimeLine.EndsWith(" ")) + sTimeLine = sTimeLine.Remove(sTimeLine.Length - 1, 1); + + if (sTimeLine != "") + { + // Add new line + lstTimeLines.Add(sTimeLine); + } + + // Reset all + bStartLine = true; + sTimeLine = string.Empty; + } + } + + // Save last line + if (sTimeLine != "") + { + // Remove last space + if (sTimeLine.Length > 0 && sTimeLine.EndsWith(" ")) + sTimeLine = sTimeLine.Remove(sTimeLine.Length - 1, 1); + lstTimeLines.Add(sTimeLine); + } + } + catch (Exception e) { MessageBox.Show(e.Message, "Karaboss", MessageBoxButtons.OK, MessageBoxIcon.Error); } + + return lstTimeLines; + } + + + /// + /// Return lyrics by line and cut lines to MaxLength characters + /// + /// + /// + /// + public static List GetLrcLinesCut(List lstTimeLines, int MaxLength) + { + List lstWords = new List(); + List lstTimes = new List(); + + string sTimeLine; + string strPartialLine; + string sLine; + bool bStartLine; + string sLyric; + string sTime; + + string[] words; + string[] Times; + string removepattern = @"\[\d{2}[:]\d{2}[.]\d{3}\]"; + string replace = @""; + + List lstLinesCut = new List(); + + try + { + + for (int i = 0; i < lstTimeLines.Count; i++) + { + sTimeLine = lstTimeLines[i]; + words = sTimeLine.Split(' '); + Times = new string[words.Length]; + for (int j = 0; j < words.Length; j++) + { + Times[j] = words[j].Substring(0, 11); + words[j] = Regex.Replace(words[j], removepattern, replace); + } + lstWords.Add(words); + lstTimes.Add(Times); + } + + // Manage length + strPartialLine = string.Empty; + sLine = string.Empty; + string[] ItemsW; + string[] ItemsT; + for (int i = 0; i < lstWords.Count; i++) + { + ItemsT = lstTimes[i]; + ItemsW = lstWords[i]; + sLine = string.Empty; + + for (int j = 0; j < ItemsW.Count(); j++) + { + bStartLine = (j == 0); + sLyric = ItemsW[j]; + sTime = ItemsT[j]; + + if (!bStartLine && (strPartialLine + " " + sLyric).Length > MaxLength) + { + // Too long + // Remove last space + if (sLine.Length > 0 && sLine.EndsWith(" ")) + sLine = sLine.Remove(sLine.Length - 1, 1); + lstLinesCut.Add(sLine); + + // Restart a new line + sLine = sTime + sLyric + " "; + strPartialLine = sLyric + " "; + + } + else + { + if (bStartLine) + { + sLine = sTime + sLyric + " "; + strPartialLine = sLyric + " "; + } + else + { + sLine += sLyric + " "; + strPartialLine += sLyric + " "; + } + } + } + + // Remove last space + if (sLine.Length > 0 && sLine.EndsWith(" ")) + sLine = sLine.Remove(sLine.Length - 1, 1); + lstLinesCut.Add(sLine); + sLine = string.Empty; + } + + if (sLine != string.Empty) + { + // Remove last space + if (sLine.Length > 0 && sLine.EndsWith(" ")) + sLine = sLine.Remove(sLine.Length - 1, 1); + lstLinesCut.Add(sLine); + } + } + catch (Exception e) + { + MessageBox.Show(e.Message, "Karaboss", MessageBoxButtons.OK, MessageBoxIcon.Error); + //return null; + } + return lstLinesCut; + } + + + #endregion LRC } diff --git a/Karaboss/Utilities/MidiFile/CreateNewMidiFile.cs b/Karaboss/Utilities/MidiFile/CreateNewMidiFile.cs index b46456e..b75490c 100644 --- a/Karaboss/Utilities/MidiFile/CreateNewMidiFile.cs +++ b/Karaboss/Utilities/MidiFile/CreateNewMidiFile.cs @@ -1,4 +1,38 @@ -using System.Windows.Forms; +#region License + +/* Copyright (c) 2025 Fabrice Lacharme + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#endregion + +#region Contact + +/* + * Fabrice Lacharme + * Email: fabrice.lacharme@gmail.com + */ + +#endregion + +using System.Windows.Forms; namespace Karaboss.Utilities { diff --git a/Karaboss/Utilities/Tempo/TempoUtilities.cs b/Karaboss/Utilities/Tempo/TempoUtilities.cs index 8954a72..a6ab412 100644 --- a/Karaboss/Utilities/Tempo/TempoUtilities.cs +++ b/Karaboss/Utilities/Tempo/TempoUtilities.cs @@ -1,4 +1,38 @@ -using System; +#region License + +/* Copyright (c) 2025 Fabrice Lacharme + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#endregion + +#region Contact + +/* + * Fabrice Lacharme + * Email: fabrice.lacharme@gmail.com + */ + +#endregion + +using System; using System.Collections.Generic; using System.Windows.Forms; using Sanford.Multimedia.Midi;