private void DrawPitchBend(UNote note, DrawingContext cxt) { var _pitchExp = note.PitchBend as PitchBendExpression; var _pts = _pitchExp.Data as List <PitchPoint>; if (_pts.Count < 2) { return; } double pt0Tick = note.PosTick + MusicMath.MillisecondToTick(_pts[0].X, DocManager.Inst.Project.BPM, DocManager.Inst.Project.BeatUnit, DocManager.Inst.Project.Resolution); double pt0X = midiVM.QuarterWidth * pt0Tick / DocManager.Inst.Project.Resolution; double pt0Pit = note.NoteNum + _pts[0].Y / 10.0; double pt0Y = TrackHeight * ((double)UIConstants.MaxNoteNum - 1.0 - pt0Pit) + TrackHeight / 2; if (note.PitchBend.SnapFirst) { cxt.DrawEllipse(ThemeManager.WhiteKeyNameBrushNormal, penPit, new Point(pt0X, pt0Y), 2.5, 2.5); } else { cxt.DrawEllipse(null, penPit, new Point(pt0X, pt0Y), 2.5, 2.5); } for (int i = 1; i < _pts.Count; i++) { double pt1Tick = note.PosTick + MusicMath.MillisecondToTick(_pts[i].X, DocManager.Inst.Project.BPM, DocManager.Inst.Project.BeatUnit, DocManager.Inst.Project.Resolution); double pt1X = midiVM.QuarterWidth * pt1Tick / DocManager.Inst.Project.Resolution; double pt1Pit = note.NoteNum + _pts[i].Y / 10.0; double pt1Y = TrackHeight * ((double)UIConstants.MaxNoteNum - 1.0 - pt1Pit) + TrackHeight / 2; // Draw arc double _x = pt0X; double _x2 = pt0X; double _y = pt0Y; double _y2 = pt0Y; if (pt1X - pt0X < 5) { cxt.DrawLine(penPit, new Point(pt0X, pt0Y), new Point(pt1X, pt1Y)); } else { while (_x2 < pt1X) { _x = Math.Min(_x + 4, pt1X); _y = MusicMath.InterpolateShape(pt0X, pt1X, pt0Y, pt1Y, _x, _pts[i - 1].Shape); cxt.DrawLine(penPit, new Point(_x, _y), new Point(_x2, _y2)); _x2 = _x; _y2 = _y; } } pt0Tick = pt1Tick; pt0X = pt1X; pt0Pit = pt1Pit; pt0Y = pt1Y; cxt.DrawEllipse(null, penPit, new Point(pt0X, pt0Y), 2.5, 2.5); } }
private void DrawPitchBend(UNote note, DrawingContext cxt) { var _pitchExp = note.pitch; var _pts = _pitchExp.data; if (_pts.Count < 2) { return; } double pt0Tick = note.position + MusicMath.MillisecondToTick(_pts[0].X, DocManager.Inst.Project.bpm, DocManager.Inst.Project.beatUnit, DocManager.Inst.Project.resolution); double pt0X = midiVM.QuarterWidth * pt0Tick / DocManager.Inst.Project.resolution; double pt0Pit = note.tone + _pts[0].Y / 10.0; double pt0Y = TrackHeight * (UIConstants.MaxNoteNum - 1.0 - pt0Pit) + TrackHeight / 2; cxt.DrawEllipse(note.pitch.snapFirst ? penPit.Brush : null, penPit, new Point(pt0X, pt0Y), 2.5, 2.5); for (int i = 1; i < _pts.Count; i++) { double pt1Tick = note.position + MusicMath.MillisecondToTick(_pts[i].X, DocManager.Inst.Project.bpm, DocManager.Inst.Project.beatUnit, DocManager.Inst.Project.resolution); double pt1X = midiVM.QuarterWidth * pt1Tick / DocManager.Inst.Project.resolution; double pt1Pit = note.tone + _pts[i].Y / 10.0; double pt1Y = TrackHeight * (UIConstants.MaxNoteNum - 1.0 - pt1Pit) + TrackHeight / 2; // Draw arc double _x = pt0X; double _x2 = pt0X; double _y = pt0Y; double _y2 = pt0Y; if (pt1X - pt0X < 5) { cxt.DrawLine(penPit, new Point(pt0X, pt0Y), new Point(pt1X, pt1Y)); } else { while (_x2 < pt1X) { _x = Math.Min(_x + 4, pt1X); _y = MusicMath.InterpolateShape(pt0X, pt1X, pt0Y, pt1Y, _x, _pts[i - 1].shape); cxt.DrawLine(penPit, new Point(_x, _y), new Point(_x2, _y2)); _x2 = _x; _y2 = _y; } } pt0Tick = pt1Tick; pt0X = pt1X; pt0Pit = pt1Pit; pt0Y = pt1Y; cxt.DrawEllipse(null, penPit, new Point(pt0X, pt0Y), 2.5, 2.5); } }
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); }
public PitchPointHitInfo HitTestPitchPoint(Point mousePos) { if (!midiVM.ShowPitch) { return(null); } foreach (var note in midiVM.Part.notes) { // FIXME pitch point maybe in view while note is not. if (midiVM.NoteIsInView(note) && !note.Error) { double lastX = 0, lastY = 0; PitchPointShape lastShape = PitchPointShape.l; for (int i = 0; i < note.pitch.data.Count; i++) { var pit = note.pitch.data[i]; int posTick = note.position + Project.MillisecondToTick(pit.X); double noteNum = note.tone + pit.Y / 10; double x = midiVM.TickToCanvas(posTick); double y = midiVM.NoteNumToCanvas(noteNum) + midiVM.TrackHeight / 2; if (Math.Abs(mousePos.X - x) < 4 && Math.Abs(mousePos.Y - y) < 4) { return new PitchPointHitInfo() { Note = note, Index = i, OnPoint = true } } ; else if (mousePos.X < x && i > 0 && mousePos.X > lastX) { // Hit test curve double castY = MusicMath.InterpolateShape(lastX, x, lastY, y, mousePos.X, lastShape) - mousePos.Y; if (y >= lastY) { if (mousePos.Y - y > 3 || lastY - mousePos.Y > 3) { break; } } else { if (y - mousePos.Y > 3 || mousePos.Y - lastY > 3) { break; } } double castX = MusicMath.InterpolateShapeX(lastX, x, lastY, y, mousePos.Y, lastShape) - mousePos.X; double dis = double.IsNaN(castX) ? Math.Abs(castY) : Math.Cos(Math.Atan2(Math.Abs(castY), Math.Abs(castX))) * Math.Abs(castY); if (dis < 3) { double msX = DocManager.Inst.Project.TickToMillisecond(midiVM.CanvasToQuarter(mousePos.X) * DocManager.Inst.Project.resolution - note.position); double msY = (midiVM.CanvasToPitch(mousePos.Y) - note.tone) * 10; return(new PitchPointHitInfo() { Note = note, Index = i - 1, OnPoint = false, X = (float)msX, Y = (float)msY }); } else { break; } } lastX = x; lastY = y; lastShape = pit.shape; } } } return(null); }
public PitchPointHitTestResult HitTestPitchPoint(Point mousePos) { foreach (var note in midiVM.Part.Notes) { if (midiVM.NoteIsInView(note)) // FIXME this is not enough { if (note.Error) { continue; } double lastX = 0, lastY = 0; PitchPointShape lastShape = PitchPointShape.l; for (int i = 0; i < note.PitchBend.Points.Count; i++) { var pit = note.PitchBend.Points[i]; int posTick = note.PosTick + Project.MillisecondToTick(pit.X); double noteNum = note.NoteNum + pit.Y / 10; double x = midiVM.TickToCanvas(posTick); double y = midiVM.NoteNumToCanvas(noteNum) + midiVM.TrackHeight / 2; if (Math.Abs(mousePos.X - x) < 4 && Math.Abs(mousePos.Y - y) < 4) { return new PitchPointHitTestResult() { Note = note, Index = i, OnPoint = true } } ; else if (mousePos.X < x && i > 0 && mousePos.X > lastX) { // Hit test curve var lastPit = note.PitchBend.Points[i - 1]; double castY = MusicMath.InterpolateShape(lastX, x, lastY, y, mousePos.X, lastShape) - mousePos.Y; if (y >= lastY) { if (mousePos.Y - y > 3 || lastY - mousePos.Y > 3) { break; } } else { if (y - mousePos.Y > 3 || mousePos.Y - lastY > 3) { break; } } double castX = MusicMath.InterpolateShapeX(lastX, x, lastY, y, mousePos.Y, lastShape) - mousePos.X; double dis = double.IsNaN(castX) ? Math.Abs(castY) : Math.Cos(Math.Atan2(Math.Abs(castY), Math.Abs(castX))) * Math.Abs(castY); if (dis < 3) { double msX = DocManager.Inst.Project.TickToMillisecond(midiVM.CanvasToQuarter(mousePos.X) * DocManager.Inst.Project.Resolution - note.PosTick); double msY = (midiVM.CanvasToPitch(mousePos.Y) - note.NoteNum) * 10; return(new PitchPointHitTestResult() { Note = note, Index = i - 1, OnPoint = false, X = msX, Y = msY }); } else { break; } } lastX = x; lastY = y; lastShape = pit.Shape; } } } return(null); }
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); }