如何在自己的线程上 运行 一个时钟
How to run a clock on its own thread
我正在尝试用 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;
}
std::chrono::seconds
表示 'A signed integral type of at least 35 bits'。因此,您将获得 count()
的值,该值每秒仅递增一次,提供每分钟 60、30、20、15、12 等节拍的选项。
以毫秒为单位工作或使用由浮点值支持的自定义持续时间。
我正在尝试用 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;
}
std::chrono::seconds
表示 'A signed integral type of at least 35 bits'。因此,您将获得 count()
的值,该值每秒仅递增一次,提供每分钟 60、30、20、15、12 等节拍的选项。
以毫秒为单位工作或使用由浮点值支持的自定义持续时间。