466 lines
20 KiB
C#
466 lines
20 KiB
C#
|
using LibAudioVisualizer;
|
|||
|
using NAudio.CoreAudioApi;
|
|||
|
using NAudio.Wave;
|
|||
|
using System.Drawing.Drawing2D;
|
|||
|
using System.Numerics;
|
|||
|
|
|||
|
namespace AudioVisualizer
|
|||
|
{
|
|||
|
public partial class MainWindow : Form
|
|||
|
{
|
|||
|
WasapiCapture capture; // <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>
|
|||
|
Visualizer visualizer; // <20><><EFBFBD>ӻ<EFBFBD>
|
|||
|
double[]? spectrumData; // Ƶ<><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
|||
|
Color[] allColors; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ
|
|||
|
|
|||
|
public MainWindow()
|
|||
|
{
|
|||
|
capture = new WasapiLoopbackCapture(); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Է<EFBFBD><D4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
visualizer = new Visualizer(256); // <20>½<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>ӻ<EFBFBD><D3BB><EFBFBD>, <20><>ʹ<EFBFBD><CAB9> 256 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>и<EFBFBD><D0B8><EFBFBD>Ҷ<EFBFBD>任
|
|||
|
|
|||
|
allColors = GetAllHsvColors(); // <20><>ȡ<EFBFBD><C8A1><EFBFBD>еĽ<D0B5><C4BD><EFBFBD><EFBFBD><EFBFBD>ɫ (HSV <20><>ɫ)
|
|||
|
|
|||
|
capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(8192, 1); // ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD>ʽ, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, 32λ<32><CEBB><EFBFBD><EFBFBD>, IeeeFloat <20><><EFBFBD><EFBFBD>, 8192<39><32><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
capture.DataAvailable += Capture_DataAvailable; // <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
|
|||
|
|
|||
|
InitializeComponent();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <20><>ȡ HSV <20><><EFBFBD><EFBFBD><EFBFBD>еĻ<D0B5><C4BB><EFBFBD><EFBFBD><EFBFBD>ɫ (<28><><EFBFBD>ͶȺ<CDB6><C8BA><EFBFBD><EFBFBD>Ⱦ<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>ֵ)
|
|||
|
/// </summary>
|
|||
|
/// <returns><3E><><EFBFBD>е<EFBFBD> HSV <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ(<28><> 256 * 6 <20><>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><>ɫҲ<C9AB>ὥ<EFBFBD><E1BDA5>)</returns>
|
|||
|
private Color[] GetAllHsvColors()
|
|||
|
{
|
|||
|
Color[] result = new Color[256 * 6];
|
|||
|
|
|||
|
for (int i = 0; i < 256; i++)
|
|||
|
{
|
|||
|
result[i] = Color.FromArgb(255, i, 0);
|
|||
|
}
|
|||
|
|
|||
|
for (int i = 0; i < 256; i++)
|
|||
|
{
|
|||
|
result[256 + i] = Color.FromArgb(255 - i, 255, 0);
|
|||
|
}
|
|||
|
|
|||
|
for (int i = 0; i < 256; i++)
|
|||
|
{
|
|||
|
result[512 + i] = Color.FromArgb(0, 255, i);
|
|||
|
}
|
|||
|
|
|||
|
for (int i = 0; i < 256; i++)
|
|||
|
{
|
|||
|
result[768 + i] = Color.FromArgb(0, 255 - i, 255);
|
|||
|
}
|
|||
|
|
|||
|
for (int i = 0; i < 256; i++)
|
|||
|
{
|
|||
|
result[1024 + i] = Color.FromArgb(i, 0, 255);
|
|||
|
}
|
|||
|
|
|||
|
for (int i = 0; i < 256; i++)
|
|||
|
{
|
|||
|
result[1280 + i] = Color.FromArgb(255, 0, 255 - i);
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>ʱ<EFBFBD><CAB1>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
/// </summary>
|
|||
|
/// <param name="sender"></param>
|
|||
|
/// <param name="e"></param>
|
|||
|
private void Capture_DataAvailable(object? sender, WaveInEventArgs e)
|
|||
|
{
|
|||
|
int length = e.BytesRecorded / 4; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (ÿһ<C3BF><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 4 <20>ֽ<EFBFBD>)
|
|||
|
double[] result = new double[length]; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
|||
|
for (int i = 0; i < length; i++)
|
|||
|
result[i] = BitConverter.ToSingle(e.Buffer, i * 4); // ȡ<><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
|||
|
|
|||
|
visualizer.PushSampleData(result); // <20><><EFBFBD>µIJ<C2B5><C4B2><EFBFBD><EFBFBD>洢<EFBFBD><E6B4A2> <20><><EFBFBD>ӻ<EFBFBD><D3BB><EFBFBD> <20><>
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <20><><EFBFBD><EFBFBD>ˢ<EFBFBD><CBA2>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD>ʵ<EFBFBD><CAB5>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD>
|
|||
|
/// </summary>
|
|||
|
/// <param name="sender"></param>
|
|||
|
/// <param name="e"></param>
|
|||
|
private void DataTimer_Tick(object? sender, EventArgs e)
|
|||
|
{
|
|||
|
double[] newSpectrumData = visualizer.GetSpectrumData(); // <20>ӿ<EFBFBD><D3BF>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD>л<EFBFBD>ȡƵ<C8A1><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
newSpectrumData = Visualizer.GetBlurry(newSpectrumData, 2); // ƽ<><C6BD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
|||
|
spectrumData = newSpectrumData;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|||
|
/// </summary>
|
|||
|
/// <param name="g"><3E><>ͼĿ<CDBC><C4BF></param>
|
|||
|
/// <param name="down"><3E>·<EFBFBD><C2B7><EFBFBD>ɫ</param>
|
|||
|
/// <param name="up"><3E>Ϸ<EFBFBD><CFB7><EFBFBD>ɫ</param>
|
|||
|
/// <param name="spectrumData">Ƶ<><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
|||
|
/// <param name="pointCount"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
|||
|
/// <param name="drawingWidth"><3E><><EFBFBD>˵Ŀ<CBB5><C4BF><EFBFBD></param>
|
|||
|
/// <param name="xOffset"><3E><><EFBFBD>˵<EFBFBD><CBB5><EFBFBD>ʼX<CABC><58><EFBFBD><EFBFBD></param>
|
|||
|
/// <param name="yOffset"><3E><><EFBFBD>˵<EFBFBD><CBB5><EFBFBD>ʵY<CAB5><59><EFBFBD><EFBFBD></param>
|
|||
|
/// <param name="scale">Ƶ<><EFBFBD><D7B5><EFBFBD><EFBFBD><EFBFBD>(ʹ<>ø<EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD>Է<EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD>)</param>
|
|||
|
private void DrawGradient(Graphics g, Color down, Color up, double[] spectrumData, int pointCount, int drawingWidth, float xOffset, float yOffset, double scale)
|
|||
|
{
|
|||
|
GraphicsPath path = new GraphicsPath();
|
|||
|
|
|||
|
PointF[] points = new PointF[pointCount + 2];
|
|||
|
for (int i = 0; i < pointCount; i++)
|
|||
|
{
|
|||
|
double x = i * drawingWidth / pointCount + xOffset;
|
|||
|
double y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset;
|
|||
|
points[i + 1] = new PointF((float)x, (float)y);
|
|||
|
}
|
|||
|
|
|||
|
points[0] = new PointF(xOffset, yOffset);
|
|||
|
points[points.Length - 1] = new PointF(xOffset + drawingWidth, yOffset);
|
|||
|
|
|||
|
path.AddCurve(points);
|
|||
|
|
|||
|
float upP = (float)points.Min(v => v.Y);
|
|||
|
|
|||
|
if (Math.Abs(upP - yOffset) < 1)
|
|||
|
return;
|
|||
|
|
|||
|
using Brush brush = new LinearGradientBrush(new PointF(0, yOffset), new PointF(0, upP), down, up);
|
|||
|
g.FillPath(brush, path);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <20><><EFBFBD>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
/// </summary>
|
|||
|
/// <param name="g"><3E><>ͼĿ<CDBC><C4BF></param>
|
|||
|
/// <param name="down"><3E>·<EFBFBD><C2B7><EFBFBD>ɫ</param>
|
|||
|
/// <param name="up"><3E>Ϸ<EFBFBD><CFB7><EFBFBD>ɫ</param>
|
|||
|
/// <param name="spectrumData">Ƶ<><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
|||
|
/// <param name="stripCount"><3E><><EFBFBD>ε<EFBFBD><CEB5><EFBFBD><EFBFBD><EFBFBD></param>
|
|||
|
/// <param name="drawingWidth"><3E><>ͼ<EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD></param>
|
|||
|
/// <param name="xOffset"><3E><>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD>ʼ X <20><><EFBFBD><EFBFBD></param>
|
|||
|
/// <param name="yOffset"><3E><>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD>ʼ Y <20><><EFBFBD><EFBFBD></param>
|
|||
|
/// <param name="spacing"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>(<28><><EFBFBD><EFBFBD>)</param>
|
|||
|
/// <param name="scale"></param>
|
|||
|
private void DrawGradientStrips(Graphics g, Color down, Color up, double[] spectrumData, int stripCount, int drawingWidth, float xOffset, float yOffset, float spacing, double scale)
|
|||
|
{
|
|||
|
float stripWidth = (drawingWidth - spacing * stripCount) / stripCount;
|
|||
|
PointF[] points = new PointF[stripCount];
|
|||
|
|
|||
|
for (int i = 0; i < stripCount; i++)
|
|||
|
{
|
|||
|
double x = stripWidth * i + spacing * i + xOffset;
|
|||
|
double y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height
|
|||
|
points[i] = new PointF((float)x, (float)y);
|
|||
|
}
|
|||
|
|
|||
|
float upP = (float)points.Min(v => v.Y < 0 ? yOffset + v.Y : yOffset);
|
|||
|
float downP = (float)points.Max(v => v.Y < 0 ? yOffset : yOffset + v.Y);
|
|||
|
|
|||
|
if (downP < yOffset)
|
|||
|
downP = yOffset;
|
|||
|
|
|||
|
if (Math.Abs(upP - downP) < 1)
|
|||
|
return;
|
|||
|
|
|||
|
using Brush brush = new LinearGradientBrush(new PointF(0, downP), new PointF(0, upP), down, up);
|
|||
|
|
|||
|
for (int i = 0; i < stripCount; i++)
|
|||
|
{
|
|||
|
PointF p = points[i];
|
|||
|
float y = yOffset;
|
|||
|
float height = p.Y;
|
|||
|
|
|||
|
if (height < 0)
|
|||
|
{
|
|||
|
y += height;
|
|||
|
height = -height;
|
|||
|
}
|
|||
|
|
|||
|
g.FillRectangle(brush, new RectangleF(p.X, y, stripWidth, height));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
/// </summary>
|
|||
|
/// <param name="g"></param>
|
|||
|
/// <param name="pen"></param>
|
|||
|
/// <param name="spectrumData"></param>
|
|||
|
/// <param name="pointCount"></param>
|
|||
|
/// <param name="drawingWidth"></param>
|
|||
|
/// <param name="xOffset"></param>
|
|||
|
/// <param name="yOffset"></param>
|
|||
|
/// <param name="scale"></param>
|
|||
|
private void DrawCurve(Graphics g, Pen pen, double[] spectrumData, int pointCount, int drawingWidth, double xOffset, double yOffset, double scale)
|
|||
|
{
|
|||
|
PointF[] points = new PointF[pointCount];
|
|||
|
for (int i = 0; i < pointCount; i++)
|
|||
|
{
|
|||
|
double x = i * drawingWidth / pointCount + xOffset;
|
|||
|
double y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset;
|
|||
|
points[i] = new PointF((float)x, (float)y);
|
|||
|
}
|
|||
|
|
|||
|
g.DrawCurve(pen, points);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <20><><EFBFBD><EFBFBD>Բ<EFBFBD><D4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
/// </summary>
|
|||
|
/// <param name="g"></param>
|
|||
|
/// <param name="brush"></param>
|
|||
|
/// <param name="spectrumData"></param>
|
|||
|
/// <param name="stripCount"></param>
|
|||
|
/// <param name="xOffset"></param>
|
|||
|
/// <param name="yOffset"></param>
|
|||
|
/// <param name="radius"></param>
|
|||
|
/// <param name="spacing"></param>
|
|||
|
/// <param name="rotation"></param>
|
|||
|
/// <param name="scale"></param>
|
|||
|
private void DrawCircleStrips(Graphics g, Brush brush, double[] spectrumData, int stripCount, double xOffset, double yOffset, double radius, double spacing, double rotation, double scale)
|
|||
|
{
|
|||
|
double rotationAngle = Math.PI / 180 * rotation;
|
|||
|
double blockWidth = MathF.PI * 2 / stripCount; // angle
|
|||
|
double stripWidth = blockWidth - MathF.PI / 180 * spacing; // angle
|
|||
|
PointF[] points = new PointF[stripCount];
|
|||
|
|
|||
|
for (int i = 0; i < stripCount; i++)
|
|||
|
{
|
|||
|
double x = blockWidth * i + rotationAngle; // angle
|
|||
|
double y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height
|
|||
|
points[i] = new PointF((float)x, (float)y);
|
|||
|
}
|
|||
|
|
|||
|
for (int i = 0; i < stripCount; i++)
|
|||
|
{
|
|||
|
PointF p = points[i];
|
|||
|
double sinStart = Math.Sin(p.X);
|
|||
|
double sinEnd = Math.Sin(p.X + stripWidth);
|
|||
|
double cosStart = Math.Cos(p.X);
|
|||
|
double cosEnd = Math.Cos(p.X + stripWidth);
|
|||
|
|
|||
|
PointF[] polygon = new PointF[]
|
|||
|
{
|
|||
|
new PointF((float)(cosStart * radius + xOffset), (float)(sinStart * radius + yOffset)),
|
|||
|
new PointF((float)(cosEnd * radius + xOffset), (float)(sinEnd * radius + yOffset)),
|
|||
|
new PointF((float)(cosEnd * (radius + p.Y) + xOffset), (float)(sinEnd * (radius + p.Y) + yOffset)),
|
|||
|
new PointF((float)(cosStart * (radius + p.Y) + xOffset), (float)(sinStart * (radius + p.Y) + yOffset)),
|
|||
|
};
|
|||
|
|
|||
|
g.FillPolygon(brush, polygon);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <20><>Բ<EFBFBD><D4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
/// </summary>
|
|||
|
/// <param name="g"></param>
|
|||
|
/// <param name="inner"></param>
|
|||
|
/// <param name="outer"></param>
|
|||
|
/// <param name="spectrumData"></param>
|
|||
|
/// <param name="stripCount"></param>
|
|||
|
/// <param name="xOffset"></param>
|
|||
|
/// <param name="yOffset"></param>
|
|||
|
/// <param name="radius"></param>
|
|||
|
/// <param name="spacing"></param>
|
|||
|
/// <param name="scale"></param>
|
|||
|
private void DrawCircleGradientStrips(Graphics g, Color inner, Color outer, double[] spectrumData, int stripCount, double xOffset, double yOffset, double radius, double spacing, double rotation, double scale)
|
|||
|
{
|
|||
|
double rotationAngle = Math.PI / 180 * rotation;
|
|||
|
double blockWidth = Math.PI * 2 / stripCount; // angle
|
|||
|
double stripWidth = blockWidth - MathF.PI / 180 * spacing; // angle
|
|||
|
PointF[] points = new PointF[stripCount];
|
|||
|
|
|||
|
for (int i = 0; i < stripCount; i++)
|
|||
|
{
|
|||
|
double x = blockWidth * i + rotationAngle; // angle
|
|||
|
double y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height
|
|||
|
points[i] = new PointF((float)x, (float)y);
|
|||
|
}
|
|||
|
|
|||
|
double maxHeight = points.Max(v => v.Y);
|
|||
|
double outerRadius = radius + maxHeight;
|
|||
|
|
|||
|
PointF[] polygon = new PointF[4];
|
|||
|
for (int i = 0; i < stripCount; i++)
|
|||
|
{
|
|||
|
PointF p = points[i];
|
|||
|
double sinStart = Math.Sin(p.X);
|
|||
|
double sinEnd = Math.Sin(p.X + stripWidth);
|
|||
|
double cosStart = Math.Cos(p.X);
|
|||
|
double cosEnd = Math.Cos(p.X + stripWidth);
|
|||
|
|
|||
|
PointF
|
|||
|
p1 = new PointF((float)(cosStart * radius + xOffset),(float)(sinStart * radius + yOffset)),
|
|||
|
p2 = new PointF((float)(cosEnd * radius + xOffset),(float)(sinEnd * radius + yOffset)),
|
|||
|
p3 = new PointF((float)(cosEnd * (radius + p.Y) + xOffset), (float)(sinEnd * (radius + p.Y) + yOffset)),
|
|||
|
p4 = new PointF((float)(cosStart * (radius + p.Y) + xOffset), (float)(sinStart * (radius + p.Y) + yOffset));
|
|||
|
|
|||
|
polygon[0] = p1;
|
|||
|
polygon[1] = p2;
|
|||
|
polygon[2] = p3;
|
|||
|
polygon[3] = p4;
|
|||
|
|
|||
|
|
|||
|
PointF innerP = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
|
|||
|
PointF outerP = new PointF((p3.X + p4.X) / 2, (p3.Y + p4.Y) / 2);
|
|||
|
|
|||
|
Vector2 offset = new Vector2(outerP.X - innerP.X, outerP.Y - innerP.Y);
|
|||
|
if (MathF.Sqrt(offset.X * offset.X + offset.Y * offset.Y) < 1) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˢ<EFBFBD><CBA2><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD><EFBFBD><EFBFBD>벻<EFBFBD><EBB2BB>̫С
|
|||
|
continue;
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
using LinearGradientBrush brush = new LinearGradientBrush(innerP, outerP, inner, outer); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѧ bug, <20><><EFBFBD><EFBFBD> <20><><EFBFBD>Ա<EFBFBD>ˢ<EFBFBD><CBA2> OutMemoryException
|
|||
|
g.FillPolygon(brush, polygon); // <20><><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD>ϲ<EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣...
|
|||
|
}
|
|||
|
catch { }
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <20><><EFBFBD><EFBFBD><F2B5A5B5><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
/// </summary>
|
|||
|
/// <param name="g"></param>
|
|||
|
/// <param name="brush"></param>
|
|||
|
/// <param name="spectrumData"></param>
|
|||
|
/// <param name="stripCount"></param>
|
|||
|
/// <param name="drawingWidth"></param>
|
|||
|
/// <param name="xOffset"></param>
|
|||
|
/// <param name="yOffset"></param>
|
|||
|
/// <param name="spacing"></param>
|
|||
|
/// <param name="scale"></param>
|
|||
|
private void DrawStrips(Graphics g, Brush brush, double[] spectrumData, int stripCount, int drawingWidth, float xOffset, float yOffset, float spacing, double scale)
|
|||
|
{
|
|||
|
float stripWidth = (drawingWidth - spacing * stripCount) / stripCount;
|
|||
|
PointF[] points = new PointF[stripCount];
|
|||
|
|
|||
|
for (int i = 0; i < stripCount; i++)
|
|||
|
{
|
|||
|
double x = stripWidth * i + spacing * i + xOffset;
|
|||
|
double y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height
|
|||
|
points[i] = new PointF((float)x, (float)y);
|
|||
|
}
|
|||
|
|
|||
|
for (int i = 0; i < stripCount; i++)
|
|||
|
{
|
|||
|
PointF p = points[i];
|
|||
|
float y = yOffset;
|
|||
|
float height = p.Y;
|
|||
|
|
|||
|
if (height < 0)
|
|||
|
{
|
|||
|
y += height;
|
|||
|
height = -height;
|
|||
|
}
|
|||
|
|
|||
|
g.FillRectangle(brush, new RectangleF(p.X, y, stripWidth, height));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı߿<C4B1>
|
|||
|
/// </summary>
|
|||
|
/// <param name="g"></param>
|
|||
|
/// <param name="inner"></param>
|
|||
|
/// <param name="outer"></param>
|
|||
|
/// <param name="area"></param>
|
|||
|
/// <param name="scale"></param>
|
|||
|
/// <param name="width"></param>
|
|||
|
private void DrawGradientBorder(Graphics g, Color inner, Color outer, Rectangle area, double scale, float width)
|
|||
|
{
|
|||
|
int thickness = (int)(width * scale);
|
|||
|
if (thickness < 1)
|
|||
|
return;
|
|||
|
|
|||
|
Rectangle rect = new Rectangle(area.X, area.Y, area.Width, area.Height);
|
|||
|
|
|||
|
Rectangle up = new Rectangle(rect.Location, new Size(rect.Width, thickness));
|
|||
|
Rectangle down = new Rectangle(new Point(rect.X, (int)(rect.X + rect.Height - scale * width)), new Size(rect.Width, thickness));
|
|||
|
Rectangle left = new Rectangle(rect.Location, new Size(thickness, rect.Height));
|
|||
|
Rectangle right = new Rectangle(new Point((int)(rect.X + rect.Width - scale * width), rect.Y), new Size(thickness, rect.Height));
|
|||
|
|
|||
|
LinearGradientBrush upB = new LinearGradientBrush(up, outer, inner, LinearGradientMode.Vertical);
|
|||
|
LinearGradientBrush downB = new LinearGradientBrush(down, inner, outer, LinearGradientMode.Vertical);
|
|||
|
LinearGradientBrush leftB = new LinearGradientBrush(left, outer, inner, LinearGradientMode.Horizontal);
|
|||
|
LinearGradientBrush rightB = new LinearGradientBrush(right, inner, outer, LinearGradientMode.Horizontal);
|
|||
|
|
|||
|
upB.WrapMode = downB.WrapMode = leftB.WrapMode = rightB.WrapMode = WrapMode.TileFlipXY;
|
|||
|
|
|||
|
g.FillRectangle(upB, up);
|
|||
|
g.FillRectangle(downB, down);
|
|||
|
g.FillRectangle(leftB, left);
|
|||
|
g.FillRectangle(rightB, right);
|
|||
|
}
|
|||
|
|
|||
|
int colorIndex = 0;
|
|||
|
double rotation = 0;
|
|||
|
BufferedGraphics? oldBuffer;
|
|||
|
private void DrawingTimer_Tick(object? sender, EventArgs e)
|
|||
|
{
|
|||
|
if (spectrumData == null)
|
|||
|
return;
|
|||
|
|
|||
|
rotation += 0.1;
|
|||
|
colorIndex++;
|
|||
|
|
|||
|
Color color1 = allColors[colorIndex % allColors.Length];
|
|||
|
Color color2 = allColors[(colorIndex + 200) % allColors.Length];
|
|||
|
|
|||
|
double[] bassArea = Visualizer.TakeSpectrumOfFrequency(spectrumData, capture.WaveFormat.SampleRate, 250); // <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>
|
|||
|
double bassScale = bassArea.Average() * 100; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
|||
|
double extraScale = Math.Min(drawingPanel.Width, drawingPanel.Height) / 6; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD>ϴ<EFBFBD><CFB4>ڴ<EFBFBD>С)
|
|||
|
|
|||
|
Rectangle border = new Rectangle(Point.Empty, drawingPanel.Size);
|
|||
|
|
|||
|
BufferedGraphics buffer = BufferedGraphicsManager.Current.Allocate(drawingPanel.CreateGraphics(), drawingPanel.ClientRectangle);
|
|||
|
Graphics g = buffer.Graphics;
|
|||
|
|
|||
|
if (oldBuffer != null)
|
|||
|
{
|
|||
|
//oldBuffer.Render(buffer.Graphics); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫʵ<D2AA><CAB5> "<22><>Ӱ" Ч<><D0A7>, <20><>ȡ<EFBFBD><C8A1>ע<EFBFBD><D7A2><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD>, <20><><EFBFBD>ҽ<EFBFBD> g.Clear <20><>Ϊ g.FillRectange(xxx, <20><><EFBFBD><CDB8><EFBFBD>ĺ<EFBFBD>ɫ)
|
|||
|
oldBuffer.Dispose();
|
|||
|
}
|
|||
|
|
|||
|
using Pen pen = new Pen(Color.Pink); // <20><><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õı<C3B5>
|
|||
|
|
|||
|
g.SmoothingMode = SmoothingMode.HighQuality; // <20><><EFBFBD>˺<EFBFBD>, <20>DZ<EFBFBD><C7B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǹ<EFBFBD><C7B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ
|
|||
|
g.Clear(drawingPanel.BackColor);
|
|||
|
|
|||
|
//DrawGradientBorder(g, Color.FromArgb(0, color1), color2, border, bassScale, drawingPanel.Width / 10);
|
|||
|
DrawGradientStrips(g, color1, color2, spectrumData, spectrumData.Length, drawingPanel.Width, 0, drawingPanel.Height, 3, -drawingPanel.Height * 50);
|
|||
|
//DrawCircleGradientStrips(g, color1, color2, spectrumData, spectrumData.Length, drawingPanel.Width / 2, drawingPanel.Height / 2, MathF.Min(drawingPanel.Width, drawingPanel.Height) / 4 + extraScale * bassScale, 1, rotation, drawingPanel.Width / 6 * 10);
|
|||
|
|
|||
|
//DrawCurve(g, pen, visualizer.SampleData, visualizer.SampleData.Length, drawingPanel.Width, 0, drawingPanel.Height / 2, MathF.Min(drawingPanel.Height / 10, 100));
|
|||
|
|
|||
|
buffer.Render();
|
|||
|
|
|||
|
oldBuffer = buffer; // <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> buffer (֮<><D6AE><EFBFBD>Բ<EFBFBD>ȫ<EFBFBD><C8AB>ֻʹ<D6BB><CAB9>һ<EFBFBD><D2BB> Buffer <20><><EFBFBD><EFBFBD>Ϊ,,, <20>û<EFBFBD><C3BB><EFBFBD><EFBFBD>ܵ<EFBFBD><DCB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>С, <20><><EFBFBD><EFBFBD>ÿһ֡<D2BB><D6A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ)
|
|||
|
}
|
|||
|
|
|||
|
private void MainWindow_Load(object sender, EventArgs e)
|
|||
|
{
|
|||
|
capture.StartRecording();
|
|||
|
dataTimer.Start();
|
|||
|
drawingTimer.Start();
|
|||
|
}
|
|||
|
|
|||
|
private void MainWindow_FormClosed(object sender, FormClosedEventArgs e)
|
|||
|
{
|
|||
|
Environment.Exit(0);
|
|||
|
}
|
|||
|
|
|||
|
private void DrawingPanel_MouseDoubleClick(object sender, MouseEventArgs e)
|
|||
|
{
|
|||
|
WindowState = WindowState != FormWindowState.Maximized ? FormWindowState.Maximized : FormWindowState.Normal;
|
|||
|
FormBorderStyle = WindowState == FormWindowState.Maximized ? FormBorderStyle.None : FormBorderStyle.Sizable;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|