/// <summary> /// Return the current note, split up as necessary to match the prev and next notes /// (Returns a new copy of all notes; the inputs are unchanged) /// /// </summary> /// <param name="prev"></param> /// <param name="curr"></param> /// <param name="next"></param> /// <returns></returns> public static List <UtauNote> GetConnectingNotes(UtauNote prev, UtauNote curr, UtauNote next) { Tuple <string, string> lyric_split = split_CVVC_Chinese(curr.Lyric); Tuple <string, string> nextlyric_split = split_CVVC_Chinese(next.Lyric); if (next.IsRest) { nextlyric_split = new Tuple <string, string>("R", null); } List <UtauNote> toReturn = new List <UtauNote>(); // add in the base note UtauNote CV = new UtauNote(curr); if (prev == null || prev.IsRest) { CV.Lyric = "- " + CV.Lyric; } toReturn.Add(CV); // if necessary, add in the connecting note string conn = GetConnectingLyric(lyric_split.Item1, lyric_split.Item2, nextlyric_split.Item1, nextlyric_split.Item2); if (conn != null) { UtauNote VC = new UtauNote(curr); VC.Lyric = conn; CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note VC.Length = 60; toReturn.Add(VC); } return(toReturn); }
/// <summary> /// Return the current note, split up as necessary to match the prev and next notes /// (Returns a new copy of all notes; the inputs are unchanged) /// /// </summary> /// <param name="prev"></param> /// <param name="curr"></param> /// <param name="next"></param> /// <returns></returns> public static List <UtauNote> GetConnectingNotes(UtauNote prev, UtauNote curr, UtauNote next) { Console.WriteLine("DOING CVVC+ FRENCH STUFF!"); Console.WriteLine("Note: this is not yet implemented."); Tuple <string, string, string> lyric_split = null; // split_CVVC_French(curr.Lyric); Tuple <string, string, string> nextlyric_split = null; // split_CVVC_French(next.Lyric); if (next.IsRest) { nextlyric_split = null;// new Tuple<string, string>("R", null); } List <UtauNote> toReturn = new List <UtauNote>(); // add in the base note UtauNote CV = new UtauNote(curr); if (prev == null || prev.IsRest) { CV.Lyric = "- " + CV.Lyric; } toReturn.Add(CV); // if necessary, add in the connecting note string conn = null;// GetConnectingLyric(lyric_split.Item1, lyric_split.Item2, nextlyric_split.Item1, nextlyric_split.Item2); if (conn != null) { UtauNote VC = new UtauNote(curr); VC.Lyric = conn; CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note VC.Length = 60; toReturn.Add(VC); } return(toReturn); }
/// <summary> /// Return the current note, split up as necessary to match the prev and next notes /// (Returns a new copy of all notes; the inputs are unchanged) /// /// </summary> /// <param name="prev"></param> /// <param name="curr"></param> /// <param name="next"></param> /// <returns></returns> public static List <UtauNote> GetConnectingNotes(UtauNote prev, UtauNote curr, UtauNote next) { VCCV_English_Syllable lyric_split = VCCV_English_Syllable.SplitSyllable(curr.Lyric); VCCV_English_Syllable nextlyric_split = VCCV_English_Syllable.SplitSyllable(next.Lyric); List <UtauNote> toReturn = new List <UtauNote>(); //if unrecognized, return the note untouched if (lyric_split.Onset[0] == null && lyric_split.Nucleus[0] == null) { return(new List <UtauNote> { new UtauNote(curr) }); } // add in the base note UtauNote CV = new UtauNote(curr); CV.Lyric = lyric_split.Onset[0] + lyric_split.Nucleus[0]; toReturn.Add(CV); // if necessary, add a blending vowel _CV string editedV = GetStartingBlendVowel(lyric_split.Onset[0], lyric_split.Nucleus[0]); if (editedV != null) { UtauNote _CV = new UtauNote(curr); _CV.Lyric = editedV; _CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note CV.Lyric = lyric_split.Onset[0]; CV.Length = 60; toReturn.Add(_CV); CV = _CV; //relabel references } // figure out the ending List <string> ending_split = EndingParser(lyric_split.Coda[0]); if (ending_split.Count == 0) { string newNote = GetConnectingSound(lyric_split.Nucleus[0], lyric_split.Coda[0], nextlyric_split.Onset[0], nextlyric_split.Nucleus[0]); UtauNote C_V = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note C_V.Lyric = newNote; C_V.Length = 60; toReturn.Add(C_V); } else if (nextlyric_split.Nucleus[0] == null) { UtauNote V_rest = new UtauNote(curr); CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note V_rest.Lyric = lyric_split.Nucleus[0]; V_rest.Length = 60; toReturn.Add(V_rest); } } else if (ending_split.Count == 1) { string newNote = GetEndingSound(lyric_split.Nucleus[0], lyric_split.Coda[0]); UtauNote VC = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note VC.Lyric = newNote; VC.Length = 60; if (Sonorant_Consonant_RE.IsMatch(lyric_split.Coda[0]) && !next.IsRest) { // on ending sonorants, add a dash before a C_C for blending // this doesn't apply if the next sound is a rest VC.Lyric = newNote + "-"; } toReturn.Add(VC); } newNote = GetConnectingSound(lyric_split.Nucleus[0], lyric_split.Coda[0], nextlyric_split.Onset[0], nextlyric_split.Nucleus[0]); UtauNote C_V = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note C_V.Lyric = newNote; C_V.Length = 60; toReturn.Add(C_V); } } else { // ending consonant cluster(s) of some sort // TODO: more than one consonant cluster is not yet supported // e.g. b6lbz, which should be [b6][6l-][lb-][bz] is currently just [b6][6l-][lbz] but lbz is not a single sound string newNote = GetEndingSound(lyric_split.Nucleus[0], ending_split[0]); UtauNote VC = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note VC.Lyric = newNote + "-"; VC.Length = 60; toReturn.Add(VC); } UtauNote VCC = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note VCC.Lyric = string.Join("", ending_split); VCC.Length = 60; toReturn.Add(VCC); } newNote = GetConnectingSound(ending_split[ending_split.Count - 2], ending_split[ending_split.Count - 1], nextlyric_split.Onset[0], nextlyric_split.Nucleus[0]); UtauNote C_V = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note C_V.Lyric = newNote; C_V.Length = 60; toReturn.Add(C_V); } } // adjust first sound if previous note is a rest if (prev == null || prev.IsRest) { toReturn[0].Lyric = "-" + toReturn[0].Lyric; } else if (lyric_split.Onset[0] == "") { // if it's not following a rest but it starts with a vowel toReturn[0].Lyric = "_" + toReturn[0].Lyric; } // adjust last sound if following note is a rest if (next == null || next.IsRest) { toReturn[toReturn.Count - 1].Lyric = toReturn[toReturn.Count - 1].Lyric + "-"; } foreach (UtauNote n in toReturn.Skip(1)) { n.MainValues.Remove("Tempo"); //Remove tempo marking from any except the first (which is where it was originally) } return(toReturn); }
public void VCCV_English_test() { Console.WriteLine("STARTING ARPASING ENGLISH GetConnectingNotes TEST"); //// reflection to test private stuff //var parent_type = typeof(VCCV_English); //var inner_type = parent_type.GetNestedType("VCCV_English_Syllable", BindingFlags.NonPublic); //PrivateType inner_type_private = new PrivateType(inner_type); //1 var prev_note = (UtauNote)null; var input_note = new UtauNote(new string[] { "[#0010]", "Length=380", "Lyric=f ay n", "NoteNum=50" }); var next_note = new UtauNote(new string[] { "[#0011]", "Length=240", "Lyric=R", "NoteNum=46" }); var result = Arpasing_English.GetConnectingNotes(prev_note, input_note, next_note); var expected = new List <UtauNote>(new UtauNote[] { new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=- f", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=200", "Lyric=f ay", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=ay n", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=n -", "NoteNum=50", }), }); CollectionAssert.AreEqual(expected.ConvertAll <string>(x => x.ToString()), result.ConvertAll <string>(x => x.ToString())); //2 prev_note = null; input_note = new UtauNote(new string[] { "[#0010]", "Length=380", "Lyric=ao r g", "NoteNum=50" }); next_note = new UtauNote(new string[] { "[#0011]", "Length=240", "Lyric=R", "NoteNum=46" }); result = Arpasing_English.GetConnectingNotes(prev_note, input_note, next_note); expected = new List <UtauNote>(new UtauNote[] { new UtauNote(new string[] { "[#0010]", "Length=200", "Lyric=- ao", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=ao r", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=r g", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=g -", "NoteNum=50", }), }); CollectionAssert.AreEqual(expected.ConvertAll <string>(x => x.ToString()), result.ConvertAll <string>(x => x.ToString())); //3 prev_note = new UtauNote(new string[] { "[#0009]", "Length=240", "Lyric=R", "NoteNum=46" }); input_note = new UtauNote(new string[] { "[#0010]", "Length=380", "Lyric=f l ay", "NoteNum=50" }); next_note = new UtauNote(new string[] { "[#0011]", "Length=240", "Lyric=m iy", "NoteNum=46" }); result = Arpasing_English.GetConnectingNotes(prev_note, input_note, next_note); expected = new List <UtauNote>(new UtauNote[] { new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=- f", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=f l", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=200", "Lyric=l ay", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=ay m", "NoteNum=50", }), }); CollectionAssert.AreEqual(expected.ConvertAll <string>(x => x.ToString()), result.ConvertAll <string>(x => x.ToString())); //4 prev_note = new UtauNote(new string[] { "[#0009]", "Length=380", "Lyric=y uw", "NoteNum=46" }); input_note = new UtauNote(new string[] { "[#0010]", "Length=380", "Lyric=m ah s t", "NoteNum=46" }); next_note = new UtauNote(new string[] { "[#0011]", "Length=380", "Lyric=b iy", "NoteNum=46" }); result = Arpasing_English.GetConnectingNotes(prev_note, input_note, next_note); expected = new List <UtauNote>(new UtauNote[] { new UtauNote(new string[] { "[#0010]", "Length=200", "Lyric=m ah", "NoteNum=46", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=ah s", "NoteNum=46", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=s t", "NoteNum=46", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=t b", "NoteNum=46", }), }); result.ForEach(x => Console.WriteLine(x)); CollectionAssert.AreEqual(expected.ConvertAll <string>(x => x.ToString()), result.ConvertAll <string>(x => x.ToString())); //5 prev_note = new UtauNote(new string[] { "[#0009]", "Length=380", "Lyric=y uw", "NoteNum=46" }); input_note = new UtauNote(new string[] { "[#0010]", "Length=380", "Lyric=aa r", "NoteNum=46" }); next_note = null; result = Arpasing_English.GetConnectingNotes(prev_note, input_note, next_note); expected = new List <UtauNote>(new UtauNote[] { new UtauNote(new string[] { "[#0010]", "Length=260", "Lyric=aa", "NoteNum=46", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=aa r", "NoteNum=46", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=r -", "NoteNum=46", }), }); result.ForEach(x => Console.WriteLine(x)); CollectionAssert.AreEqual(expected.ConvertAll <string>(x => x.ToString()), result.ConvertAll <string>(x => x.ToString())); //6 prev_note = new UtauNote(new string[] { "[#0009]", "Length=380", "Lyric=R", "NoteNum=46" }); input_note = new UtauNote(new string[] { "[#0010]", "Length=380", "Lyric=aa r", "NoteNum=46" }); next_note = null; result = Arpasing_English.GetConnectingNotes(prev_note, input_note, next_note); expected = new List <UtauNote>(new UtauNote[] { new UtauNote(new string[] { "[#0010]", "Length=260", "Lyric=- aa", "NoteNum=46", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=aa r", "NoteNum=46", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=r -", "NoteNum=46", }), }); result.ForEach(x => Console.WriteLine(x)); CollectionAssert.AreEqual(expected.ConvertAll <string>(x => x.ToString()), result.ConvertAll <string>(x => x.ToString())); Console.WriteLine("ENDING ARPASING ENGLISH GetConnectingNotes TEST"); }
public void VCCV_English_test() { Console.WriteLine("STARTING VCCV ENGLISH GetConnectingNotes TEST"); // reflection to test private stuff var parent_type = typeof(VCCV_English); var inner_type = parent_type.GetNestedType("VCCV_English_Syllable", BindingFlags.NonPublic); PrivateType inner_type_private = new PrivateType(inner_type); //1 var input_note = new UtauNote(new string[] { "[#0010]", "Length=229", "Lyric=fIn", "NoteNum=50" }); var next_note = new UtauNote(new string[] { "[#0011]", "Length=240", "Lyric=R", "NoteNum=46" }); var result = VCCV_English.GetConnectingNotes(null, input_note, next_note); var expected = new List <UtauNote>(new UtauNote[] { new UtauNote(new string[] { "[#0010]", "Length=169", "Lyric=-fI", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=In-", "NoteNum=50", }), }); CollectionAssert.AreEqual(expected.ConvertAll <string>(x => x.ToString()), result.ConvertAll <string>(x => x.ToString())); //2 input_note = new UtauNote(new string[] { "[#0010]", "Length=229", "Lyric=fIn", "NoteNum=50" }); next_note = new UtauNote(new string[] { "[#0011]", "Length=240", "Lyric=dhen", "NoteNum=46" }); result = VCCV_English.GetConnectingNotes(null, input_note, next_note); expected = new List <UtauNote>(new UtauNote[] { new UtauNote(new string[] { "[#0010]", "Length=109", "Lyric=-fI", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=In-", "NoteNum=50", }), new UtauNote(new string[] { "[#0010]", "Length=60", "Lyric=n dh", "NoteNum=50", }), }); CollectionAssert.AreEqual(expected.ConvertAll <string>(x => x.ToString()), result.ConvertAll <string>(x => x.ToString())); Console.WriteLine("ENDING VCCV ENGLISH GetConnectingNotes TEST"); }
/// <summary> /// Return the current note, split up as necessary to match the prev and next notes /// (Returns a new copy of all notes; the inputs are unchanged) /// /// </summary> /// <param name="prev"></param> /// <param name="curr"></param> /// <param name="next"></param> /// <returns></returns> public static List <UtauNote> GetConnectingNotes(UtauNote prev, UtauNote curr, UtauNote next) { VCCV_English_Syllable lyric_split = VCCV_English_Syllable.SplitSyllable(curr.Lyric); VCCV_English_Syllable nextlyric_split = VCCV_English_Syllable.SplitSyllable(next.Lyric); List <UtauNote> toReturn = new List <UtauNote>(); //if unrecognized, return the note untouched if (lyric_split.Onset[0] == null && lyric_split.Nucleus[0] == null) { return(new List <UtauNote> { new UtauNote(curr) }); } // add in the base note UtauNote CV = new UtauNote(curr); CV.Lyric = lyric_split.Onset[0] + lyric_split.Nucleus[0]; toReturn.Add(CV); // if necessary, add a blending vowel _CV string editedV = GetStartingBlendVowel(lyric_split.Onset[0], lyric_split.Nucleus[0]); if (editedV != null) { UtauNote _CV = new UtauNote(curr); _CV.Lyric = editedV; _CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note CV.Lyric = lyric_split.Onset[0]; CV.Length = 60; toReturn.Add(_CV); CV = _CV; //relabel references } // figure out the ending List <string> ending_split = EndingParser(lyric_split.Coda[0]); if (ending_split.Count == 0) { string newNote = GetConnectingSound(lyric_split.Nucleus[0], lyric_split.Coda[0], nextlyric_split.Onset[0], nextlyric_split.Nucleus[0]); UtauNote C_V = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note C_V.Lyric = newNote; C_V.Length = 60; toReturn.Add(C_V); } else if (nextlyric_split.Nucleus[0] == null) { UtauNote V_rest = new UtauNote(curr); CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note V_rest.Lyric = lyric_split.Nucleus[0]; V_rest.Length = 60; toReturn.Add(V_rest); } } else if (ending_split.Count == 1) { string newNote = GetEndingSound(lyric_split.Nucleus[0], lyric_split.Coda[0]); UtauNote VC = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note VC.Lyric = newNote; VC.Length = 60; toReturn.Add(VC); } newNote = GetConnectingSound(lyric_split.Nucleus[0], lyric_split.Coda[0], nextlyric_split.Onset[0], nextlyric_split.Nucleus[0]); UtauNote C_V = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note C_V.Lyric = newNote; C_V.Length = 60; toReturn.Add(C_V); } } else { // ending consonant cluster(s) of some sort // TODO: more than one consonant cluster is not yet supported // e.g. b6lbz, which should be [b6][6l-][lb-][bz] is just [b6][6l-][lbz] but lbz is not a single sound string newNote = GetEndingSound(lyric_split.Nucleus[0], ending_split[0]); UtauNote VC = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note VC.Lyric = newNote + "-"; VC.Length = 60; toReturn.Add(VC); } UtauNote VCC = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note VCC.Lyric = string.Join("", ending_split); VCC.Length = 60; toReturn.Add(VCC); } newNote = GetConnectingSound(ending_split[ending_split.Count - 2], ending_split[ending_split.Count - 1], nextlyric_split.Onset[0], nextlyric_split.Nucleus[0]); UtauNote C_V = new UtauNote(curr); if (newNote != null) { CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note C_V.Lyric = newNote; C_V.Length = 60; toReturn.Add(C_V); } } // adjust first sound if previous note is a rest if (prev == null || prev.IsRest) { toReturn[0].Lyric = "-" + toReturn[0].Lyric; } // adjust last sound if following note is a rest if (next == null || next.IsRest) { toReturn[toReturn.Count - 1].Lyric = toReturn[toReturn.Count - 1].Lyric + "-"; } return(toReturn); }
/// <summary> /// Return the current note, split up as necessary to match the prev and next notes /// (Returns a new copy of all notes; the inputs are unchanged) /// /// </summary> /// <param name="prev"></param> /// <param name="curr"></param> /// <param name="next"></param> /// <returns></returns> public static List <UtauNote> GetConnectingNotes(UtauNote prev, UtauNote curr, UtauNote next) { Arpasing_English_Syllable currsyllable = Arpasing_English_Syllable.SplitSyllable(curr.Lyric); //if unrecognized, return the note untouched if (currsyllable == null || curr.IsRest) { return(new List <UtauNote> { new UtauNote(curr) }); } //default to hyphen if the prev/next is a rest or doesn't exist string prevsyllable_end = "-"; string nextsyllable_start = "-"; if (prev != null && !prev.IsRest) { prevsyllable_end = null; } if (next != null && !next.IsRest) { var nextsyllable = Arpasing_English_Syllable.SplitSyllable(next.Lyric); nextsyllable_start = nextsyllable[0]; } // identify the vowel (if more than one, choose any - here, we arbitrarily choose the last one) // if none, default to first phoneme int nucleus_index = 0; for (var i = 0; i < currsyllable.Count; i++) { if (Vowels.Contains(currsyllable[i])) { nucleus_index = i; } } // build up the notes to return List <UtauNote> toReturn = new List <UtauNote>(); UtauNote note; if (prevsyllable_end != null) { // add in the note connecting to the previous note, if it exists note = new UtauNote(curr); note.Lyric = prevsyllable_end + " " + currsyllable[0]; note.Length = 60; //TODO: something more clever with lengths. For now, 60 is a 32nd note toReturn.Add(note); } else if (nucleus_index == 0) { // we start with a vowel, and we don't have a - to start from // so we add it in manually note = new UtauNote(curr); note.Lyric = currsyllable[0]; note.Length = 60; //TODO: something more clever with lengths. For now, 60 is a 32nd note toReturn.Add(note); } else { // we have no initial note, so decrement the nucleus_index nucleus_index -= 1; } for (var i = 0; i < currsyllable.Count - 1; i++) { note = new UtauNote(curr); note.Lyric = currsyllable[i] + " " + currsyllable[i + 1]; // set the note length to be 60 for now; we'll find the nucleus_index-th one and extend it at the end note.Length = 60; //TODO: something more clever with lengths. For now, 60 is a 32nd note toReturn.Add(note); } // add in the note connecting to the next note note = new UtauNote(curr); note.Lyric = currsyllable[currsyllable.Count - 1] + " " + nextsyllable_start; note.Length = 60; //TODO: something more clever with lengths. For now, 60 is a 32nd note toReturn.Add(note); toReturn[nucleus_index].Length = curr.Length - (toReturn.Count - 1) * 60; // TODO: does not handle the case when this ends up shorter than the original note return(toReturn); }
/*public static readonly List<string> vowels = new List<string>(new string[] * { * "a", "ai", "e", "eh", "en", "eu", "i", "in", "o", "on", "oo", "ou", "u", "ui", "oi" * }); * public static readonly List<string> consonants = new List<string>(new string[] * { * "b","d","f","g","j","k","l","m","n","p","r","s","sh","t","v","z" * }); * public static readonly List<string> starting_clusters = new List<string>(new string[] * { * "br", "bl", "bz", "dr", "dl", "fr", "fl", "gr", "gl", "gz", "jr", "jl", "kr", "kl", "ks", "mr", "ml", "nr", "nl", * "pr", "pl", "ps", "sr", "sl", "sk", "shr", "shl", "tr", "tl", "ts", "vr", "vl", "zr", "zl" * }); * public static readonly List<string> ending_clusters = new List<string>(new string[] * { * "rb", "lb", "zb", "rd", "ld", "rf", "lf", "rg", "lg", "zg", "rj", "lj", "rk", "lk", "sk", "rl", "rm", "lm", "zm", "sm", * "rn", "ln", "zn", "sn", "rp", "lp", "zp", "sp", "rs", "ls", "rsh", "lsh", "rt", "lt", "st", "rv", "lv", "rz", "lz" * });*/ /* * /// <summary> * /// split a French syllable into its onset, nucleus, and coda * /// or a (null, null, null) tuple if the lyric can't be recognized * /// </summary> * /// <param name="lyric"></param> * /// <returns></returns> * private static Tuple<List<string>, string, List<string>> split_CVVC_French(string lyric) * { * var toReturnOnset = new List<string>(); * var toReturnCoda = new List<string>(); * var toReturnNucleus = ""; * var all_starting_clusters = consonants.Concat(starting_clusters); * var max_starting_cluster_length = all_starting_clusters.Max(s => s.Length); * var all_ending_clusters = consonants.Concat(ending_clusters); * var next_lyric = lyric; * * // find onset * var continue_searching = true; * while (continue_searching) { * continue_searching = false; * // find a single onset * for (var i = 0; i < max_starting_cluster_length; i++) * { * if (all_starting_clusters.Any( * prefix => lyric.StartsWith(prefix) && prefix.Length == max_starting_cluster_length * )) * { * // iterates upwards, so at the end of the for loop, next_lyric is the maximum * next_lyric = lyric.Substring(i); * continue_searching = true; * } * } * // if (continue_searching) toReturnOnset.Add(lyric.Substring(0, i)); * lyric = next_lyric; * } * * // find a single onset * for (var i = 0; i < max_starting_cluster_length; i++) * { * if (all_starting_clusters.Any( * prefix => lyric.StartsWith(prefix) && prefix.Length == max_starting_cluster_length * )) * { * // iterates upwards, so at the end of the for loop, next_lyric is the maximum * toReturnNucleus = lyric.Substring(i); * next_lyric = lyric.Substring(i); * continue_searching = true; * } * } * lyric = next_lyric; * * // otherwise, return as expected * return new Tuple<List<string>, string, List<string>>(toReturnOnset,toReturnNucleus,toReturnCoda); * }*/ /// <summary> /// Return the current note, split up as necessary to match the prev and next notes /// (Returns a new copy of all notes; the inputs are unchanged) /// /// </summary> /// <param name="prev"></param> /// <param name="curr"></param> /// <param name="next"></param> /// <returns></returns> public static List <UtauNote> GetConnectingNotes(UtauNote prev, UtauNote curr, UtauNote next) { CVVCPlus_French_Syllable lyric_split = CVVCPlus_French_Syllable.SplitSyllable(curr.Lyric); string nextlyric_start = CVVCPlus_French_Syllable.StartingConsonant(next.Lyric); List <UtauNote> toReturn = new List <UtauNote>(); //if unrecognized, return the note untouched if (lyric_split.Onset == null && lyric_split.Nucleus == null) { return(new List <UtauNote> { new UtauNote(curr) }); } // add in the base note UtauNote CV = new UtauNote(curr); CV.Lyric = lyric_split.Onset + lyric_split.Nucleus; toReturn.Add(CV); // add in the VC note (first figuring out what C to add in) UtauNote VC = new UtauNote(curr); string VC_consonant; if (lyric_split.Coda != "") { VC_consonant = lyric_split.Coda; } else if (nextlyric_start != "") { VC_consonant = nextlyric_start; } else { VC_consonant = null; } if (VC_consonant != null) { var matches = not_to_be_confused_for_nasals_RE.IsMatch(lyric_split.Nucleus); if (matches && VC_consonant == the_nasal_consonant) { //SPECIAL CASE: handle non-nasals followed by n VC.Lyric = lyric_split.Nucleus + " " + VC_consonant; } else { //ORDINARY CASE VC.Lyric = lyric_split.Nucleus + VC_consonant; } VC.Length = 120; //TODO: something more clever with lengths. For now, 120 is a 16th note toReturn.Add(VC); CV.Length = CV.Length - 120; } // adjust first sound if previous note is a rest (and this note has no starting consonant) if (lyric_split.Onset == "" && (prev == null || prev.IsRest)) { toReturn[0].Lyric = "-" + toReturn[0].Lyric; } // adjust last sound if following note is a rest (and this note has no ending consonant) if (lyric_split.Coda == "" && (next == null || next.IsRest)) { VC.Lyric = lyric_split.Nucleus + "-"; VC.Length = 120; //TODO: something more clever with lengths. For now, 120 is a 16th note toReturn.Add(VC); CV.Length = CV.Length - 120; } //TODO: double-check what's going on with the UtauNote copy constructor and why the tempo is being copied from the next note or something //for now, hack: toReturn.ForEach(note => { //note.MainValues.Remove("Tempo"); //remove if exists }); return(toReturn); /*Tuple<string, string, string> lyric_split = null;// split_CVVC_French(curr.Lyric); * Tuple<string, string, string> nextlyric_split = null;// split_CVVC_French(next.Lyric); * if (next.IsRest) * { * nextlyric_split = null;// new Tuple<string, string>("R", null); * } * * List<UtauNote> toReturn = new List<UtauNote>(); * * // add in the base note * UtauNote CV = new UtauNote(curr); * if (prev == null || prev.IsRest) * { * CV.Lyric = "- " + CV.Lyric; * } * toReturn.Add(CV); * * // if necessary, add in the connecting note * string conn = null;// GetConnectingLyric(lyric_split.Item1, lyric_split.Item2, nextlyric_split.Item1, nextlyric_split.Item2); * * if (conn != null) * { * UtauNote VC = new UtauNote(curr); * VC.Lyric = conn; * CV.Length = CV.Length - 60; //TODO: something more clever with lengths. For now, 60 is a 32th note * VC.Length = 60; * toReturn.Add(VC); * } * * return toReturn;*/ }
/// Return the current note, split up as necessary to match the prev and next notes /// (Returns a new copy of all notes; the inputs are unchanged) public static List <UtauNote> GetConnectingNotes(UtauNote prev, UtauNote curr, UtauNote next) { CVVCEve_French_Syllable lyric_split = CVVCEve_French_Syllable.SplitSyllable(curr.Lyric); string nextlyric_start = CVVCEve_French_Syllable.StartingConsonant(next.Lyric); List <UtauNote> toReturn = new List <UtauNote>(); //if unrecognized, return the note untouched if (lyric_split.Onset == null && lyric_split.Nucleus == null) { return(new List <UtauNote> { new UtauNote(curr) }); } // add in the base note UtauNote CV = new UtauNote(curr); CV.Lyric = lyric_split.Onset + lyric_split.Nucleus; toReturn.Add(CV); // add in the VC note (first figuring out what C to add in) UtauNote VC = new UtauNote(curr); string VC_consonant; if (lyric_split.Coda != "") { VC_consonant = lyric_split.Coda; } else if (nextlyric_start != "") { VC_consonant = " " + nextlyric_start; } else { VC_consonant = null; } if (VC_consonant != null) { VC.Lyric = lyric_split.Nucleus + VC_consonant; VC.Length = 120; //TODO: something more clever with lengths. For now, 120 is a 16th note toReturn.Add(VC); CV.Length = CV.Length - 120; } // adjust first sound if previous note is a rest (and this note has no starting consonant) if (prev == null || prev.IsRest) { toReturn[0].Lyric = "- " + toReturn[0].Lyric; } //TODO: double-check what's going on with the UtauNote copy constructor and why the tempo is being copied from the next note or something //for now, hack: toReturn.ForEach(note => { //note.MainValues.Remove("Tempo"); //remove if exists }); return(toReturn); }
/// <summary> /// Return the current note, split up as necessary to match the prev and next notes /// (Returns a new copy of all notes; the inputs are unchanged) /// /// </summary> /// <param name="prev"></param> /// <param name="curr"></param> /// <param name="next"></param> /// <returns></returns> public static List <UtauNote> GetConnectingNotes(UtauNote prev, UtauNote curr, UtauNote next) { CVVC_English_Syllable lyric_split = CVVC_English_Syllable.SplitSyllable(curr.Lyric); string nextlyric_start = CVVC_English_Syllable.StartingConsonant(next.Lyric); List <UtauNote> toReturn = new List <UtauNote>(); //if unrecognized, return the note untouched if (lyric_split.Onset == null && lyric_split.Nucleus == null) { return(new List <UtauNote> { new UtauNote(curr) }); } // add in the base note UtauNote CV = new UtauNote(curr); CV.Lyric = lyric_split.Onset + lyric_split.Nucleus; toReturn.Add(CV); // add in the VC note (first figuring out what C to add in) UtauNote VC = new UtauNote(curr); string VC_consonant; if (lyric_split.Coda != "") { VC_consonant = lyric_split.Coda; } else if (nextlyric_start != "") { VC_consonant = nextlyric_start; } else { VC_consonant = null; } if (VC_consonant != null) { VC.Lyric = lyric_split.Nucleus + VC_consonant; VC.Length = 120; //TODO: something more clever with lengths. For now, 120 is a 16th note toReturn.Add(VC); CV.Length = CV.Length - 120; } // adjust first sound if previous note is a rest (and this note has no starting consonant) if (lyric_split.Onset == "" && (prev == null || prev.IsRest)) { toReturn[0].Lyric = "-" + toReturn[0].Lyric; } // adjust last sound if following note is a rest (and this note has no ending consonant) if (lyric_split.Coda == "" && (next == null || next.IsRest)) { VC.Lyric = lyric_split.Nucleus + "-"; VC.Length = 120; //TODO: something more clever with lengths. For now, 120 is a 16th note toReturn.Add(VC); CV.Length = CV.Length - 120; } //TODO: vowel-vowel sounds like V return(toReturn); }