如何计算bpm(每分钟的跳数)?

时间:2019-10-25 03:48:45

标签: c#

我正在尝试编写一个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;
}

这只是计算您单击按钮的次数,然后将其除以经过的分钟数,而不是按点击率进行预测。

2 个答案:

答案 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);  
  }          
}