Пример #1
0
        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);
            }
        }
Пример #2
0
        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);
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }