protected override void OnRender(DrawingContext drawingContext) { int note = UIConstants.MaxNoteNum - 1 - (int)(OffsetY / TrackHeight); double top = TrackHeight * (UIConstants.MaxNoteNum - note - 1) - OffsetY; while (top < _size.Height) { drawingContext.DrawRectangle( MusicMath.IsBlackKey(note) ? ThemeManager.BlackKeyBrushNormal : MusicMath.IsCenterKey(note) ? ThemeManager.CenterKeyBrushNormal : ThemeManager.WhiteKeyBrushNormal, null, new Rect(0, (int)top, _size.Width, TrackHeight)); if (TrackHeight >= 12) { FormattedText text = new FormattedText( MusicMath.GetNoteString(note), System.Threading.Thread.CurrentThread.CurrentUICulture, FlowDirection.LeftToRight, SystemFonts.CaptionFontFamily.GetTypefaces().First(), 12, MusicMath.IsBlackKey(note) ? ThemeManager.BlackKeyNameBrushNormal : MusicMath.IsCenterKey(note) ? ThemeManager.CenterKeyNameBrushNormal : ThemeManager.WhiteKeyNameBrushNormal, VisualTreeHelper.GetDpi(this).PixelsPerDip ); drawingContext.DrawText(text, new Point(42 - text.Width, (int)(top + (TrackHeight - text.Height) / 2))); } top += TrackHeight; note--; } }
protected override void OnRender(DrawingContext drawingContext) { int firstTrack = (int)(OffsetY / TrackHeight); int alt = firstTrack; double top = TrackHeight * firstTrack - OffsetY; while (top < _size.Height) { drawingContext.DrawRectangle( MusicMath.IsBlackKey(alt) ? ThemeManager.BlackKeyBrushNormal : MusicMath.IsCenterKey(alt) ? ThemeManager.CenterKeyBrushNormal : ThemeManager.WhiteKeyBrushNormal, null, new Rect(0, (int)top, _size.Width, TrackHeight)); if (TrackHeight >= 12) { FormattedText text = new FormattedText( MusicMath.GetNoteString(UIConstants.MaxNoteNum - alt - 1), System.Threading.Thread.CurrentThread.CurrentUICulture, FlowDirection.LeftToRight, SystemFonts.CaptionFontFamily.GetTypefaces().First(), 12, MusicMath.IsBlackKey(alt) ? ThemeManager.BlackKeyNameBrushNormal : MusicMath.IsCenterKey(alt) ? ThemeManager.CenterKeyNameBrushNormal : ThemeManager.WhiteKeyNameBrushNormal ); drawingContext.DrawText(text, new Point(42 - text.Width, (int)(top + (TrackHeight - text.Height) / 2))); } top += TrackHeight; alt++; } }
public void DrawNote(Graphics g, PlayingData pd, Note n, object color = null, int dx = 0, int dy = 0) { Color c; if (color == null) { switch (n.type) {//set color for default case NoteType.ShortNote: c = Color.White; break; case NoteType.SlideLongNote: c = Color.GreenYellow; break; default: c = Color.Red; break; } } else { c = (Color)color; } g.DrawRectangle(new Pen(c, 2), MusicMath.RectFromNote(n, pd, dx, dy)); }
public void Begin(IPointer pointer, Point point) { pointer.Capture(element); var tone = vm.NotesViewModel.PointToTone(point); sineGen = PlaybackManager.Inst.PlayTone(MusicMath.ToneToFreq(tone)); }
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 HandleTicked(double tickTime, int midiNoteNumber, double duration) { float pitch = MusicMath.MidiNoteToPitch(midiNoteNumber, MusicMath.MidiNoteC4); _samplerVoices[_nextVoiceIndex].Play(_audioClip, pitch, tickTime, _attackTime, duration, _releaseTime); _nextVoiceIndex = (_nextVoiceIndex + 1) % _samplerVoices.Length; }
public void Update(IPointer pointer, Point point) { var tone = vm.NotesViewModel.PointToTone(point); if (sineGen != null) { sineGen.Freq = MusicMath.ToneToFreq(tone); } }
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); } }
/// <summary> /// Utility method to map a phoneme alias to proper pitch using prefixmap. /// For example, MapPhoneme("あ", 72, singer) may return "あC5". /// </summary> /// <param name="phoneme">Alias before pitch mapping.</param> /// <param name="tone">Music tone of note. C4 = 60.</param> /// <param name="singer">The singer.</param> /// <returns>Mapped alias.</returns> public static string MapPhoneme(string phoneme, int tone, USinger singer) { var toneName = MusicMath.GetToneName(tone); if (singer.PrefixMap.TryGetValue(toneName, out var prefix)) { var phonemeMapped = prefix.Item1 + phoneme + prefix.Item2; if (singer.FindOto(phonemeMapped) != null) { phoneme = phonemeMapped; } } return(phoneme); }
public void DrawImaginaryNote(Graphics g, PlayingData pd, Note DraggingNote, Note SelectedNote, bool dragging, Point draggingDelta) { //draw dragging note ///todo: draggingnote delta beat if (dragging) { DrawNote(g, pd, DraggingNote, Color.Gray, draggingDelta.X, draggingDelta.Y); } //draw selected note if (SelectedNote != null) { g.DrawRectangle(new Pen(Color.Yellow, 1), MusicMath.RectFromNote(SelectedNote, pd)); } }
protected override void OnRender(DrawingContext drawingContext) { int note = UIConstants.MaxNoteNum - 1 - (int)(OffsetY / TrackHeight); double top = TrackHeight * (UIConstants.MaxNoteNum - note - 1) - OffsetY; while (top < _size.Height) { drawingContext.DrawRectangle( MusicMath.IsBlackKey(note) ? ThemeManager.TrackBackgroundBrushAlt : ThemeManager.TrackBackgroundBrush, null, new Rect(0, (int)top, _size.Width, TrackHeight)); top += TrackHeight; note--; } }
protected override void OnRender(DrawingContext drawingContext) { int firstTrack = (int)(OffsetY / TrackHeight); int alt = firstTrack % 12; double top = TrackHeight * firstTrack - OffsetY; while (top < _size.Height) { drawingContext.DrawRectangle( MusicMath.IsBlackKey(alt) ? ThemeManager.TrackBackgroundBrushAlt : ThemeManager.TrackBackgroundBrush, null, new Rect(0, (int)top, _size.Width, TrackHeight)); top += TrackHeight; alt = (alt + 1) % 12; } }
public EngineInput ToEngineInput() { return(new EngineInput { inputWaveFile = SourceFile, NoteString = MusicMath.GetNoteString(NoteNum), Velocity = Velocity, StrFlags = StrFlags, Offset = Oto.Offset, RequiredLength = RequiredLength, Consonant = Oto.Consonant, Cutoff = Oto.Cutoff, Volume = Volume, Modulation = 0, pitchBend = PitchData.ToArray(), nPitchBend = PitchData.Count, Tempo = Tempo }); }
public string GetResamplerExeArgs() { // fresamp.exe <infile> <outfile> <tone> <velocity> <flags> <offset> <length_req> // <fixed_length> <endblank> <volume> <modulation> <pitch> return(string.Format( "{0} {1:D} {2} {3} {4:D} {5} {6} {7:D} {8:D} {9} {10}", MusicMath.GetNoteString(NoteNum), Velocity, StrFlags, Oto.Offset, RequiredLength, Oto.Consonant, Oto.Cutoff, Volume, 0, Tempo, String.Join(",", PitchData))); }
protected override void OnRender(DrawingContext drawingContext) { double zoomRatio = MusicMath.getZoomRatio(QuarterWidth, BeatPerBar, BeatUnit, MinTickWidth); double interval = zoomRatio * QuarterWidth; int tick = (int)((OffsetX + QuarterOffset * QuarterWidth) / interval) + 1; double left = tick * interval - OffsetX - QuarterOffset * QuarterWidth; while (left < _size.Width) { double snappedLeft = Math.Round(left) + 0.5; if ((tick * zoomRatio * BeatUnit) % (BeatPerBar * 4) == 0) { drawingContext.DrawLine(darkPen, new Point(snappedLeft, -0.5), new Point(snappedLeft, ActualHeight + 0.5)); } else if ((tick * zoomRatio * BeatUnit) % 4 == 0) { if (TickMode == 1) { drawingContext.DrawLine(darkPen, new Point(snappedLeft, -0.5), new Point(snappedLeft, ActualHeight + 0.5)); } else { drawingContext.DrawLine(lightPen, new Point(snappedLeft, -0.5), new Point(snappedLeft, ActualHeight + 0.5)); } } else if ((tick * zoomRatio * BeatUnit) % 1 == 0) { if (TickMode == 1) { drawingContext.DrawLine(lightPen, new Point(snappedLeft, -0.5), new Point(snappedLeft, ActualHeight + 0.5)); } else { drawingContext.DrawLine(dashedPen, new Point(snappedLeft, -0.5), new Point(snappedLeft, ActualHeight + 0.5)); } } else { drawingContext.DrawLine(dashedPen, new Point(snappedLeft, -0.5), new Point(snappedLeft, ActualHeight + 0.5)); } left += interval; tick++; } }
/// <summary> /// 从RenderItem初始化过程 /// </summary> /// <returns></returns> internal static EngineInput CreateInputModel(RenderItem renderItem, double Modulation) { EngineInput Ret = new EngineInput(); Ret.inputWaveFile = renderItem.RawFile; Ret.NoteString = MusicMath.GetNoteString(renderItem.NoteNum); Ret.Velocity = renderItem.Velocity; Ret.StrFlags = renderItem.StrFlags; Ret.Offset = renderItem.Oto.Offset; Ret.RequiredLength = renderItem.RequiredLength; Ret.Consonant = renderItem.Oto.Consonant; Ret.Cutoff = renderItem.Oto.Cutoff; Ret.Volume = renderItem.Volume; Ret.Modulation = Modulation; Ret.pitchBend = renderItem.PitchData.ToArray(); Ret.nPitchBend = renderItem.PitchData.Count; Ret.Tempo = renderItem.Tempo; return(Ret); }
public bool TryGetMappedOto(string phoneme, int tone, out UOto oto) { oto = default; string toneName = MusicMath.GetToneName(tone); if (PrefixMap.TryGetValue(toneName, out var mapped)) { string phonemeMapped = mapped.Item1 + phoneme + mapped.Item2; if (TryGetOto(phonemeMapped, out oto)) { return(true); } } if (TryGetOto(phoneme, out oto)) { return(true); } return(false); }
protected override void OnRender(DrawingContext drawingContext) { double zoomRatio = MusicMath.getZoomRatio(QuarterWidth, BeatPerBar, BeatUnit, MinTickWidth); double interval = zoomRatio * QuarterWidth; int tick = (int)((OffsetX + QuarterOffset * QuarterWidth) / interval); double left = tick * interval - OffsetX - QuarterOffset * QuarterWidth; bool first_tick = true; while (left < _size.Width) { double snappedLeft = Math.Round(left) + 0.5; if ((tick * zoomRatio * BeatUnit) % (BeatPerBar * 4) == 0) { if (!first_tick) { drawingContext.DrawLine(darkPen, new Point(snappedLeft, -0.5), new Point(snappedLeft, ActualHeight + 0.5)); } int barNumber = (int)((tick * zoomRatio * BeatUnit) / BeatPerBar / 4 + 1); FormattedText fText; if (!fTextPool.ContainsKey(barNumber)) { fText = new FormattedText( barNumber.ToString(), System.Threading.Thread.CurrentThread.CurrentUICulture, FlowDirection.LeftToRight, SystemFonts.CaptionFontFamily.GetTypefaces().First(), 12, darkPen.Brush, VisualTreeHelper.GetDpi(this).PixelsPerDip); fTextPool.Add(barNumber, fText); } else { fText = fTextPool[barNumber]; } drawingContext.DrawText(fText, new Point(snappedLeft + 3, 3)); } left += interval; tick++; first_tick = false; } }
/// <summary> /// 从RenderItem初始化过程 /// </summary> /// <returns></returns> internal static EngineInput CreateInputModel(RenderItem renderItem, double Modulation) { EngineInput Ret = new EngineInput { inputWaveFile = renderItem.SourceFile, NoteString = MusicMath.GetNoteString(renderItem.NoteNum), Velocity = renderItem.Velocity, StrFlags = renderItem.StrFlags, Offset = renderItem.Oto.Offset, RequiredLength = renderItem.RequiredLength, Consonant = renderItem.Oto.Consonant, Cutoff = renderItem.Oto.Cutoff, Volume = renderItem.Volume, Modulation = Modulation, pitchBend = renderItem.PitchData.ToArray(), nPitchBend = renderItem.PitchData.Count, Tempo = renderItem.Tempo }; return(Ret); }
}//*/ public void DrawGuideLine(Graphics g, PlayingData pd) { Pen borderlinedrawer = new Pen(Color.White, 0.5f); for (int i = 0; i < pd.hsnapcnt; i++)//Horizontal guideline { int x = this.Width * (i + 1) / ((int)pd.hsnapcnt + 1); g.DrawLine(borderlinedrawer, x, 0, x, this.Height); }//Horizontal guideline int beat = ((int)(pd.now * 48 / pd.bsnapcnt)) * pd.bsnapcnt; double l = beat / 48d; while (beat < 0) { beat += 48; } for (; l < pd.now + pd.scale; l += 1d / 48d) { Pen linedrawer; beat %= 48;//detect beat if (beat % (48 / pd.bsnapcnt) != 0) { beat++; continue; } if (beat == 0 && ((l + 12.1) % 4) < 0.4)//thick line every large beat(4 small beat) { linedrawer = new Pen(Editor.BeatSnapColor.col[beat], 3); } else { linedrawer = new Pen(Editor.BeatSnapColor.col[beat], 1); } int y = MusicMath.TimingToY(l, pd); g.DrawLine(linedrawer, 0, y, pd.width, y); beat++; }//vertical(beat)guideline }
public double TickToMillisecond(double tick) { return(MusicMath.TickToMillisecond(tick, BPM, BeatUnit, Resolution)); }
public int MillisecondToTick(double ms) { return(MusicMath.MillisecondToTick(ms, BPM, BeatUnit, Resolution)); }
/// <summary> /// Utility method to convert milliseconds to ticks. /// </summary> protected int MsToTick(double ms) { return(MusicMath.MillisecondToTick(ms, bpm, beatUnit, resolution)); }
/// <summary> /// Utility method to convert ticks to milliseconds. /// </summary> protected double TickToMs(int tick) { return(MusicMath.TickToMillisecond(tick, bpm, beatUnit, resolution)); }
public string GetResamplerExeArgs() { // fresamp.exe <infile> <outfile> <tone> <velocity> <flags> <offset> <length_req> // <fixed_length> <endblank> <volume> <modulation> <pitch> return($"{MusicMath.GetNoteString(NoteNum)} {Velocity:D} {StrFlags} {Oto.Offset} {RequiredLength:D} {Oto.Consonant} {Oto.Cutoff} {Volume:D} {0:D} {Tempo} {string.Join(",", PitchData)}"); }
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 string GetResamplerExeArgs() { // fresamp.exe <infile> <outfile> <tone> <velocity> <flags> <offset> <length_req> // <fixed_length> <endblank> <volume> <modulation> <pitch> return(FormattableString.Invariant($"{MusicMath.GetNoteString(NoteNum)} {Velocity:D} \"{StrFlags}\" {Oto.Offset} {RequiredLength:D} {Oto.Consonant} {Oto.Cutoff} {Volume:D} {Modulation:D} {Tempo} {Base64.Base64EncodeInt12(PitchData.ToArray())}")); }
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); }
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); }
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); }