【问题标题】:How to run a clock on its own thread如何在自己的线程上运行时钟
【发布时间】:2015-06-05 22:12:39
【问题描述】:

我正在尝试用 C++ 创建一个步进音序器,它最终会发送 MIDI 数据。我通过在它自己的线程上创建一个时钟来计算自上次节拍以来的时间量,如果是下一个节拍的时间,它会将一段数据写入控制台。

但是,我发现无论我将 BPM 设置为什么,我收到消息的速度显然都太慢了。我似乎无法弄清楚为什么这个线程上的时间是错误的,而且我对std::chrono 库的工作方式不是很熟悉也无济于事。想法?

代码如下:

#include <thread>
#include <mutex>
#include <chrono>
#include <vector>
#include <iostream>

class StepSequencer {
 public:
  StepSequencer();
  ~StepSequencer();
  void run();
  void setBeatsPerMinute(float bpm);
  void addNote(int noteValue, int beatIndex);
  void playNote(int beatIndex);
 protected:
  int mNumberOfBeatBins;
  int mSequencerPlayhead;
  float mBeatsPerMinute;
  float mSecondsPerBeat;
  std::vector<int> mBeatBins;
  std::mutex mMutex;
  std::thread mSequencerThread;
  bool mRunSequencerThread;
  std::chrono::time_point<std::chrono::system_clock> mLastBeatTime;
  std::chrono::time_point<std::chrono::system_clock> mCurrentTime;
};

#include "stdafx.h"
#include "StepSequencer.h"

StepSequencer::StepSequencer() {
  mNumberOfBeatBins = 16;
  for(int i = 0; i < 16; i++) {
    mBeatBins.push_back(0);
  }

  mBeatsPerMinute = 0;
  mSecondsPerBeat = 1;

  mLastBeatTime = std::chrono::system_clock::now();
  mCurrentTime = std::chrono::system_clock::now();

  mSequencerPlayhead = 0;

    mRunSequencerThread = false;
    mSequencerThread = std::thread(&StepSequencer::run, this);
}

StepSequencer::~StepSequencer() {
  if(mSequencerThread.joinable()) {
    mSequencerThread.join();
  }
}

void StepSequencer::run() {
  mRunSequencerThread = true;
  while(mRunSequencerThread) {
        mCurrentTime = std::chrono::system_clock::now();
    mMutex.lock();
        if (std::chrono::duration_cast<std::chrono::seconds>(mCurrentTime - mLastBeatTime).count() > mSecondsPerBeat) {
      mSequencerPlayhead++;
      mSequencerPlayhead = mSequencerPlayhead % mNumberOfBeatBins;
      playNote(mSequencerPlayhead);
            mLastBeatTime = std::chrono::system_clock::now();
    }
    mMutex.unlock();
    this_thread::sleep_for(std::chrono::milliseconds(1));
  }
} 

void StepSequencer::setBeatsPerMinute(float bpm) {
  mMutex.lock();
  mBeatsPerMinute = bpm;
  if(mBeatsPerMinute > 0) {
      mSecondsPerBeat = 60.0 / mBeatsPerMinute;
  }
  else {
    mSecondsPerBeat = 1;
  }
 mMutex.unlock();
}

void StepSequencer::addNote(int noteValue, int beatIndex) {
  mBeatBins[beatIndex] = noteValue;
}

void StepSequencer::playNote(int beatIndex) {
  std::cout << mBeatBins[beatIndex] << std::endl;
}

【问题讨论】:

  • 请指定计时器。
  • 如果可以,我会 -- 你能指定我描述计时器的选项吗?
  • 使用更高精度的时钟。
  • 你有什么建议?
  • 睡眠一毫秒不太可能起作用,并且会导致您偶尔睡眠更多,因为操作系统会断定您的进程它不是交互式的。在现代操作系统上,十或二十是绝对最低限度。

标签: c++ multithreading c++11 chrono


【解决方案1】:

std::chrono::seconds 具有“至少 35 位的有符号整数类型”的表示。因此,您将获得 count() 的值,该值每秒仅增加一次,可选择每分钟 60、30、20、15、12 等节拍。

以毫秒为单位工作或使用由浮点值支持的自定义持续时间。

【讨论】:

  • 啊哈!这非常有用,而且似乎是我遗漏的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
  • 2021-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多