我正在尝试编写一个Winforms应用程序,该应用程序可以计算每分钟点击的节拍,类似于以下网站:https://www.all8.com/tools/bpm.htm,但对我来说没有用。
我尝试创建一个System.Diagnostics.Stopwatch
对象以计算毫秒数,然后将其除以60,000以获取经过的分钟数,但这并不计算未来的时间
public Stopwatch stopwatch = new Stopwatch();
public Form1()
{
InitializeComponent();
}
float i = 0f;
private void Button1_Click(object sender, EventArgs e)
{
if (!stopwatch.IsRunning) { stopwatch.Start(); }
i++;
speed.Text = String.Format("Speed: {0} bpm\nClicks: {1} Clicks", i / Millis(), i);
}
private float Millis()
{
var returntype = stopwatch.ElapsedMilliseconds / 60000;
return returntype + 1;
}
这只是计算您单击按钮的次数,然后将其除以经过的分钟数,而不是按点击率进行预测。
答案 0 :(得分:-1)
这与我前段时间编写的用于计算编码过程的FPS的某些代码非常相似。
从此代码开始,然后使其适应您的需求。 Calculate方法将使用bool指示是否单击。您将在每次单击时使用True调用它,并让计时器每秒钟使用False调用它。然后,您只需将BMP绑定到此类的属性以进行显示。
这应该足以让您入门。我建议将计算的逻辑放在专门的类中,以免使主类混乱。
/// <summary>
/// Allows calculating the time left during an encoding process.
/// </summary>
public class TimeLeftCalculator {
private KeyValuePair<DateTime, long>[] progressHistory;
private int iterator;
private bool fullCycle;
private long lastPos;
private long frameCount;
private int historyLength;
/// <summary>
/// After calling Calculate, returns the estimated processing time left.
/// </summary>
public TimeSpan ResultTimeLeft { get; private set; }
/// <summary>
/// After calling Calculate, returns the estimated processing rate per second.
/// </summary>
public double ResultFps { get; private set; }
protected readonly IEnvironmentService environment;
/// <summary>
/// Initializes a new instance of the TimeLeftCalculator class.
/// </summary>
/// <param name="frameCount">The total number of frames to encode.</param>
/// <param name="historyLength">The number of status entries to store. The larger the number, the slower the time left will change. Default is 20.</param>
public TimeLeftCalculator(long frameCount, int historyLength = 20) : this(new EnvironmentService(), frameCount, 20) { }
/// <summary>
/// Initializes a new instance of the TimeLeftCalculator class.
/// </summary>
/// <param name="environmentService">A reference to an IEnvironmentService.</param>
/// <param name="frameCount">The total number of frames to encode.</param>
/// <param name="historyLength">The number of status entries to store. The larger the number, the slower the time left will change. Default is 20.</param>
public TimeLeftCalculator(IEnvironmentService environmentService, long frameCount, int historyLength = 20) {
this.environment = environmentService ?? throw new ArgumentNullException(nameof(environmentService));
this.FrameCount = frameCount;
this.HistoryLength = historyLength;
progressHistory = new KeyValuePair<DateTime, long>[historyLength];
}
/// <summary>
/// Gets or sets the total number of frames to encode.
/// </summary>
public long FrameCount {
get => frameCount;
set => frameCount = value >= 0 ? value : throw new ArgumentOutOfRangeException(nameof(FrameCount));
}
/// <summary>
/// Gets or sets the number of status entries to store. The larger the number, the slower the time left will change.
/// </summary>
public int HistoryLength {
get => historyLength;
set => historyLength = value >= 1 ? value : throw new ArgumentOutOfRangeException(nameof(HistoryLength));
}
/// <summary>
/// Calculates the time left and fps. Result will be in ResultTimeLeft and ResultFps.
/// </summary>
/// <param name="pos">The current frame position.</param>
public void Calculate(long pos) {
if (pos < 0)
return;
TimeSpan Result = TimeSpan.Zero;
progressHistory[iterator] = new KeyValuePair<DateTime, long>(environment.Now, pos);
lastPos = pos;
// Calculate SampleWorkTime and SampleWorkFrame for each host
TimeSpan SampleWorkTime = TimeSpan.Zero;
long SampleWorkFrame = 0;
int PosFirst = -1;
if (fullCycle) {
PosFirst = (iterator + 1) % HistoryLength;
} else if (iterator > 0)
PosFirst = 0;
if (PosFirst > -1) {
SampleWorkTime += progressHistory[iterator].Key - progressHistory[PosFirst].Key;
SampleWorkFrame += progressHistory[iterator].Value - progressHistory[PosFirst].Value;
}
if (SampleWorkTime.TotalSeconds > 0 && SampleWorkFrame >= 0) {
ResultFps = SampleWorkFrame / SampleWorkTime.TotalSeconds;
long WorkLeft = FrameCount - pos;
if (WorkLeft <= 0)
ResultTimeLeft = TimeSpan.Zero;
else if (ResultFps > 0)
ResultTimeLeft = TimeSpan.FromSeconds(WorkLeft / ResultFps);
}
iterator = (iterator + 1) % HistoryLength;
if (iterator == 0)
fullCycle = true;
}
}
答案 1 :(得分:-1)
这里有几个实用工具。在BPM和TimeSpan
之间转换的方法:
public static class BpmExtensions
{
static readonly long SecondsPerMinute = TimeSpan.TicksPerMinute / TimeSpan.TicksPerSecond;
public static int ToBpm(this TimeSpan timeSpan)
{
var seconds = 1 / timeSpan.TotalSeconds;
return (int)Math.Round(seconds * SecondsPerMinute);
}
public static TimeSpan ToInterval(this int bpm)
{
var bps = (double)bpm / SecondsPerMinute;
var interval = 1 / bps;
return TimeSpan.FromSeconds(interval);
}
}