JD2022-TU1/main/tools/framework/JD.Application.TeaBox/View/Tracks/BeatsGrid.cs

100 lines
No EOL
3.8 KiB
C#

using System;
using System.Drawing;
using JD.Application.View.Timeline;
using JD.Audio.Annotations;
using JD.Kernel.Structs;
using TeaBox;
using Signature = JD.Audio.Annotations.Signature;
namespace JD.Application.View.Tracks
{
/// <summary>
/// Paints a grid as helper to position elements on the beats / measures.
/// </summary>
public class BeatsGrid
{
/// <summary>
/// Paints a dotted line on each beat in the specified bounds.
/// </summary>
public static void PaintMeasure(Graphics graphics, Rectangle bounds, global::JD.Sequencers.Times.Timeline timeline, Color color = default(Color))
{
const int minimumPixelPerLine = 12;
if (color == default(Color))
{
color = Color.FromArgb(120, 255, 255, 255);
}
float measureSize = timeline.PixelFromBeatDuration(new BeatUnit(Signature.Default.BeatsPerMeasure));
if (measureSize < 16)
{
return;
}
int drawMeasureOnEach = Math.Max(1, (int)Math.Round(minimumPixelPerLine / measureSize));
using (var p = new Pen(color))
{
Range<int> paintBounds = new Range<int>(bounds.Left, bounds.Right);
var timeRange = timeline.VisibleTimeRange;
for (int i = (int)timeRange.Min; i < (int)timeRange.Max; i++)
{
var beat = new BeatUnit(i);
var signature = timeline.Wave().Annotations.GetSignature(beat);
if (signature.ComputeIndexInMeasure(beat) == 1)
{
int pixel = timeline.TimeToPixel(beat);
if (paintBounds.Contains(pixel) && (beat.EntireValue / signature.BeatsPerMeasure) % drawMeasureOnEach == 0)
{
graphics.DrawLine(p, pixel, bounds.Top, pixel, bounds.Bottom);
}
}
}
}
}
public static void PaintGrid(Graphics graphics, Rectangle bounds, global::JD.Sequencers.Times.Timeline timeline, Color colorBeats, Color colorMeasures)
{
const float quarterBeatDuration = 0.25f;
const float beatDuration = 1f;
const int minimumPixelPerLine = 10;
PaintMeasure(graphics, bounds, timeline, colorMeasures);
float quarterBeatPixelSize = timeline.PixelFromBeatDuration(new BeatUnit(quarterBeatDuration));
float beatPixelSize = timeline.PixelFromBeatDuration(new BeatUnit(beatDuration));
if (beatPixelSize < minimumPixelPerLine)
{
return;
}
using (var p = new Pen(colorBeats))
{
var paintBounds = new Range<int>(bounds.Left, bounds.Right);
var timeRange = timeline.VisibleTimeRange;
var minTime = timeRange.Min - timeRange.Min%quarterBeatDuration;
for (float beat = minTime; beat < timeRange.Max; beat += quarterBeatDuration)
{
int pixel = timeline.TimeToPixel(beat);
bool isBeat = Math.Abs(beat % beatDuration) < float.Epsilon;
if (paintBounds.Contains(pixel))
{
if (isBeat)
{
graphics.DrawLine(p, pixel, bounds.Bottom-2, pixel, bounds.Bottom - 7);
}
else if (quarterBeatPixelSize > minimumPixelPerLine)
{
graphics.DrawLine(p, pixel, bounds.Bottom-2, pixel, bounds.Bottom - 4);
}
}
}
}
}
}
}