private RenderItem BuildRenderItem(UPhoneme phoneme, UVoicePart part, UProject project) { USinger singer = project.Tracks[part.TrackNo].Singer; string rawfile = Lib.EncodingUtil.ConvertEncoding(singer.FileEncoding, singer.PathEncoding, phoneme.Oto.File); rawfile = Path.Combine(singer.Path, rawfile); double strechRatio = Math.Pow(2, 1.0 - (double)(int)phoneme.Parent.Expressions["velocity"].Data / 100); double length = phoneme.Oto.Preutter * strechRatio + phoneme.Envelope.Points[4].X; double requiredLength = Math.Ceiling(length / 50 + 1) * 50; double lengthAdjustment = phoneme.TailIntrude == 0 ? phoneme.Preutter : phoneme.Preutter - phoneme.TailIntrude + phoneme.TailOverlap; RenderItem item = new RenderItem() { // For resampler RawFile = rawfile, NoteNum = phoneme.Parent.NoteNum, Velocity = (int)phoneme.Parent.Expressions["velocity"].Data, Volume = (int)phoneme.Parent.Expressions["volume"].Data, StrFlags = phoneme.Parent.GetResamplerFlags(), PitchData = BuildPitchData(phoneme, part, project), RequiredLength = (int)requiredLength, Oto = phoneme.Oto, Tempo = project.BPM, // For connector SkipOver = phoneme.Oto.Preutter * strechRatio - phoneme.Preutter, PosMs = project.TickToMillisecond(part.PosTick + phoneme.Parent.PosTick + phoneme.PosTick) - phoneme.Preutter, DurMs = project.TickToMillisecond(phoneme.DurTick) + lengthAdjustment, Envelope = phoneme.Envelope.Points }; return(item); }
public override object Deserialize(IDictionary <string, object> dictionary, Type type, JavaScriptSerializer serializer) { UPhoneme result = new UPhoneme() { PosTick = Convert.ToInt32(dictionary["pos"]), Phoneme = dictionary["pho"] as string, AutoEnvelope = Convert.ToBoolean(dictionary["autoenv"]), AutoRemapped = Convert.ToBoolean(dictionary["remap"]) }; if (!result.AutoEnvelope) { var env = dictionary["env"] as ArrayList; for (int i = 0; i < 10; i++) { if (i % 2 == 0) { result.Envelope.Points[i / 2].X = Convert.ToDouble(env[i]); } else { result.Envelope.Points[i / 2].Y = Convert.ToDouble(env[i]); } } } return(result); }
public RenderItem(UPhoneme phoneme, UVoicePart part, UProject project) { var singer = project.Tracks[part.TrackNo].Singer; SourceFile = phoneme.Oto.File; SourceFile = Path.Combine(PathManager.Inst.InstalledSingersPath, SourceFile); var strechRatio = Math.Pow(2, 1.0 - (double)(int)phoneme.Parent.Expressions["velocity"].Data / 100); var length = phoneme.Oto.Preutter * strechRatio + phoneme.Envelope.Points[4].X; var requiredLength = Math.Ceiling(length / 50 + 1) * 50; var lengthAdjustment = phoneme.TailIntrude == 0 ? phoneme.Preutter : phoneme.Preutter - phoneme.TailIntrude + phoneme.TailOverlap; NoteNum = phoneme.Parent.NoteNum; Velocity = (int)phoneme.Parent.Expressions["velocity"].Data; Volume = (int)phoneme.Parent.Expressions["volume"].Data; StrFlags = phoneme.Parent.GetResamplerFlags(); PitchData = BuildPitchData(phoneme, part, project); RequiredLength = (int)requiredLength; Oto = phoneme.Oto; Tempo = project.BPM; SkipOver = phoneme.Oto.Preutter * strechRatio - phoneme.Preutter; PosMs = project.TickToMillisecond(part.PosTick + phoneme.Parent.PosTick + phoneme.PosTick) - phoneme.Preutter; DurMs = project.TickToMillisecond(phoneme.DurTick) + lengthAdjustment; Envelope = phoneme.Envelope.Points; phonemeName = phoneme.Phoneme; }
public PhonemeChangeOverlapState(Canvas canvas, PianoRollViewModel vm, UNote leadingNote, UPhoneme phoneme, int index) : base(canvas, vm) { this.leadingNote = leadingNote; this.phoneme = phoneme; this.index = index; }
public SetPhonemeExpressionCommand(UProject project, UPhoneme phoneme, string abbr, float value) { this.project = project; this.phoneme = phoneme; Key = abbr; newValue = value; oldValue = phoneme.GetExpression(project, abbr).Item1; }
private void UpdateOverlapAdjustment(UVoicePart part) { UPhoneme lastPhoneme = null; UNote lastNote = null; foreach (UNote note in part.Notes) { foreach (UPhoneme phoneme in note.Phonemes) { if (lastPhoneme != null) { int gapTick = phoneme.Parent.PosTick + phoneme.PosTick - lastPhoneme.Parent.PosTick - lastPhoneme.EndTick; double gapMs = DocManager.Inst.Project.TickToMillisecond(gapTick); if (gapMs < phoneme.Preutter) { phoneme.Overlapped = true; double lastDurMs = DocManager.Inst.Project.TickToMillisecond(lastPhoneme.DurTick); double correctionRatio = (lastDurMs + Math.Min(0, gapMs)) / 2 / (phoneme.Preutter - phoneme.Overlap); if (phoneme.Preutter - phoneme.Overlap > gapMs + lastDurMs / 2) { phoneme.OverlapCorrection = true; phoneme.Preutter = gapMs + (phoneme.Preutter - gapMs) * correctionRatio; phoneme.Overlap *= correctionRatio; } else if (phoneme.Preutter > gapMs + lastDurMs) { phoneme.OverlapCorrection = true; phoneme.Overlap *= correctionRatio; phoneme.Preutter = gapMs + lastDurMs; } else { phoneme.OverlapCorrection = false; } lastPhoneme.TailIntrude = phoneme.Preutter - gapMs; lastPhoneme.TailOverlap = phoneme.Overlap; } else { phoneme.Overlapped = false; lastPhoneme.TailIntrude = 0; lastPhoneme.TailOverlap = 0; } } else { phoneme.Overlapped = false; } lastPhoneme = phoneme; } lastNote = note; } }
public RenderItem(UPhoneme phoneme, UVoicePart part, UTrack track, UProject project, string resamplerName) { SourceFile = phoneme.oto.File; SourceFile = Path.Combine(PathManager.Inst.InstalledSingersPath, SourceFile); ResamplerName = resamplerName; if (project.expressions.TryGetValue("eng", out var descriptor)) { int index = (int)phoneme.GetExpression(project, "eng").Item1; string resampler = descriptor.options[index]; if (!string.IsNullOrEmpty(resampler)) { ResamplerName = resampler; } } string ext = Path.GetExtension(SourceFile); SourceTemp = Path.Combine(PathManager.Inst.GetCachePath(null), $"{HashHex(track.Singer.Id)}-{HashHex(phoneme.oto.Set)}-{HashHex(SourceFile)}{ext}"); Velocity = (int)phoneme.GetExpression(project, "vel").Item1; Volume = (int)phoneme.GetExpression(project, "vol").Item1; Modulation = (int)phoneme.GetExpression(project, "mod").Item1; var strechRatio = Math.Pow(2, 1.0 - Velocity / 100.0); var length = phoneme.oto.Preutter * strechRatio + phoneme.envelope.data[4].X; var requiredLength = Math.Ceiling(length / 50 + 1) * 50; var lengthAdjustment = phoneme.tailIntrude == 0 ? phoneme.preutter : phoneme.preutter - phoneme.tailIntrude + phoneme.tailOverlap; NoteNum = phoneme.Parent.tone; StrFlags = phoneme.GetResamplerFlags(project); PitchData = BuildPitchData(phoneme, part, project); RequiredLength = (int)requiredLength; Oto = phoneme.oto; Tempo = project.bpm; SkipOver = phoneme.oto.Preutter * strechRatio - phoneme.preutter; PosMs = project.TickToMillisecond(part.position + phoneme.Parent.position + phoneme.position) - phoneme.preutter; DurMs = project.TickToMillisecond(phoneme.Duration) + lengthAdjustment; Envelope = phoneme.envelope.data; phonemeName = phoneme.phoneme; }
private void UpdatePhonemeDurTick(UVoicePart part) { UNote lastNote = null; UPhoneme lastPhoneme = null; foreach (UNote note in part.Notes) { foreach (UPhoneme phoneme in note.Phonemes) { phoneme.DurTick = phoneme.Parent.DurTick - phoneme.PosTick; if (lastPhoneme != null) { if (lastPhoneme.Parent == phoneme.Parent) { lastPhoneme.DurTick = phoneme.PosTick - lastPhoneme.PosTick; } } lastPhoneme = phoneme; } lastNote = note; } }
private List <int> BuildPitchData(UPhoneme phoneme, UVoicePart part, UProject project) { var pitches = new List <int>(); var lastNote = part.Notes.OrderByDescending(x => x).Where(x => x.CompareTo(phoneme.Parent) < 0).FirstOrDefault(); var nextNote = part.Notes.Where(x => x.CompareTo(phoneme.Parent) > 0).FirstOrDefault(); // Get relevant pitch points var pps = new List <PitchPoint>(); var lastNoteInvolved = lastNote != null && phoneme.Overlapped; var nextNoteInvolved = nextNote != null && nextNote.Phonemes[0].Overlapped; double lastVibratoStartMs = 0; double lastVibratoEndMs = 0; double vibratoStartMs = 0; double vibratoEndMs = 0; if (lastNoteInvolved) { var offsetMs = DocManager.Inst.Project.TickToMillisecond(phoneme.Parent.PosTick - lastNote.PosTick); foreach (var pp in lastNote.PitchBend.Points) { var newpp = pp.Clone(); newpp.X -= offsetMs; newpp.Y -= (phoneme.Parent.NoteNum - lastNote.NoteNum) * 10; pps.Add(newpp); } if (lastNote.Vibrato.Depth != 0) { lastVibratoStartMs = -DocManager.Inst.Project.TickToMillisecond(lastNote.DurTick) * lastNote.Vibrato.Length / 100; lastVibratoEndMs = 0; } } foreach (var pp in phoneme.Parent.PitchBend.Points) { pps.Add(pp); } if (phoneme.Parent.Vibrato.Depth != 0) { vibratoEndMs = DocManager.Inst.Project.TickToMillisecond(phoneme.Parent.DurTick); vibratoStartMs = vibratoEndMs * (1 - phoneme.Parent.Vibrato.Length / 100); } if (nextNoteInvolved) { var offsetMs = DocManager.Inst.Project.TickToMillisecond(phoneme.Parent.PosTick - nextNote.PosTick); foreach (var pp in nextNote.PitchBend.Points) { var newpp = pp.Clone(); newpp.X -= offsetMs; newpp.Y -= (phoneme.Parent.NoteNum - nextNote.NoteNum) * 10; pps.Add(newpp); } } var startMs = DocManager.Inst.Project.TickToMillisecond(phoneme.PosTick) - phoneme.Oto.Preutter; var endMs = DocManager.Inst.Project.TickToMillisecond(phoneme.DurTick) - (nextNote != null && nextNote.Phonemes[0].Overlapped ? nextNote.Phonemes[0].Preutter - nextNote.Phonemes[0].Overlap : 0); if (pps.Count > 0) { if (pps.First().X > startMs) { pps.Insert(0, new PitchPoint(startMs, pps.First().Y)); } if (pps.Last().X < endMs) { pps.Add(new PitchPoint(endMs, pps.Last().Y)); } } else { throw new Exception("Zero pitch points."); } // Interpolation const int intervalTick = 5; var intervalMs = DocManager.Inst.Project.TickToMillisecond(intervalTick); var currMs = startMs; var i = 0; while (currMs < endMs) { while (pps[i + 1].X < currMs) { i++; } var pit = MusicMath.InterpolateShape(pps[i].X, pps[i + 1].X, pps[i].Y, pps[i + 1].Y, currMs, pps[i].Shape); pit *= 10; // Apply vibratos if (currMs < lastVibratoEndMs && currMs >= lastVibratoStartMs) { pit += InterpolateVibrato(lastNote.Vibrato, currMs - lastVibratoStartMs); } if (currMs < vibratoEndMs && currMs >= vibratoStartMs) { pit += InterpolateVibrato(phoneme.Parent.Vibrato, currMs - vibratoStartMs); } pitches.Add((int)pit); currMs += intervalMs; } return(pitches); }
private List <int> BuildPitchData(UPhoneme phoneme, UVoicePart part, UProject project) { int leftBound = phoneme.Parent.position + phoneme.position - project.MillisecondToTick(phoneme.preutter); int rightBound = phoneme.Parent.position + phoneme.position + phoneme.Duration - project.MillisecondToTick(phoneme.tailIntrude - phoneme.tailOverlap); var leftNote = phoneme.Parent; var rightNote = phoneme.Parent; bool oneMore = true; while ((leftBound < leftNote.RightBound || oneMore) && leftNote.Prev != null && leftNote.Prev.End == leftNote.position) { leftNote = leftNote.Prev; if (leftBound >= leftNote.RightBound) { oneMore = false; } } oneMore = true; while ((rightBound > rightNote.LeftBound || oneMore) && rightNote.Next != null && rightNote.Next.position == rightNote.End) { rightNote = rightNote.Next; if (rightBound <= rightNote.LeftBound) { oneMore = false; } } // Collect pitch curve and vibratos. var points = new List <PitchPoint>(); var vibratos = new List <Tuple <double, double, UVibrato> >(); var note = leftNote; float vel = Velocity; var strechRatio = Math.Pow(2, 1.0 - vel / 100); float correction = (float)(phoneme.oto.Preutter * (strechRatio - 1)); while (true) { var offsetMs = (float)project.TickToMillisecond(note.position - phoneme.Parent.position); foreach (var point in note.pitch.data) { var newpp = point.Clone(); newpp.X += offsetMs + correction; newpp.Y -= (phoneme.Parent.tone - note.tone) * 10; points.Add(newpp); } if (note.vibrato.length != 0) { double vibratoStartMs = project.TickToMillisecond(note.position + note.duration * (1 - note.vibrato.length / 100) - phoneme.Parent.position); double vibratoEndMs = project.TickToMillisecond(note.End - phoneme.Parent.position); vibratos.Add(Tuple.Create(vibratoStartMs, vibratoEndMs, note.vibrato)); } if (note == rightNote) { break; } note = note.Next; } // Expand curve if necessary. float startMs = (float)(project.TickToMillisecond(phoneme.position) - phoneme.oto.Preutter); float endMs = (float)(project.TickToMillisecond(phoneme.End) - phoneme.tailIntrude + phoneme.tailOverlap); if (points.First().X > startMs) { points.Insert(0, new PitchPoint(startMs, points.First().Y)); } if (points.Last().X < endMs) { points.Add(new PitchPoint(endMs, points.Last().Y)); } // Interpolation. var pitches = new List <int>(); const int intervalTick = 5; float intervalMs = (float)project.TickToMillisecond(intervalTick); float currMs = startMs; int i = 0; int vibrato = 0; while (currMs < endMs) { while (points[i + 1].X < currMs) { i++; } var pit = MusicMath.InterpolateShape(points[i].X, points[i + 1].X, points[i].Y, points[i + 1].Y, currMs, points[i].shape) * 10; while (vibrato < vibratos.Count - 1 && vibratos[vibrato].Item2 < currMs) { vibrato++; } if (vibrato < vibratos.Count && vibratos[vibrato].Item1 <= currMs && currMs < vibratos[vibrato].Item2) { pit += InterpolateVibrato(vibratos[vibrato].Item3, currMs - vibratos[vibrato].Item1, vibratos[vibrato].Item2 - vibratos[vibrato].Item1, project); } pitches.Add((int)pit); currMs += intervalMs; } return(pitches); }