Merge pull request #712 from jpcima/timed-recheck-files
Timed recheck files
This commit is contained in:
commit
a49636adda
4 changed files with 115 additions and 39 deletions
|
|
@ -14,6 +14,7 @@
|
||||||
#include "pluginterfaces/vst/ivstevents.h"
|
#include "pluginterfaces/vst/ivstevents.h"
|
||||||
#include "pluginterfaces/vst/ivstparameterchanges.h"
|
#include "pluginterfaces/vst/ivstparameterchanges.h"
|
||||||
#include <ghc/fs_std.hpp>
|
#include <ghc/fs_std.hpp>
|
||||||
|
#include <chrono>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
|
|
@ -37,11 +38,12 @@ static const char* kRingIdOsc = "Osc";
|
||||||
static const char* kMsgIdSetNumVoices = "SetNumVoices";
|
static const char* kMsgIdSetNumVoices = "SetNumVoices";
|
||||||
static const char* kMsgIdSetOversampling = "SetOversampling";
|
static const char* kMsgIdSetOversampling = "SetOversampling";
|
||||||
static const char* kMsgIdSetPreloadSize = "SetPreloadSize";
|
static const char* kMsgIdSetPreloadSize = "SetPreloadSize";
|
||||||
static const char* kMsgIdCheckShouldReload = "CheckShouldReload";
|
|
||||||
static const char* kMsgIdNotifyPlayState = "NotifyPlayState";
|
static const char* kMsgIdNotifyPlayState = "NotifyPlayState";
|
||||||
static const char* kMsgIdReceiveMessage = "ReceiveMessage";
|
static const char* kMsgIdReceiveMessage = "ReceiveMessage";
|
||||||
static const char* kMsgIdNoteEvents = "NoteEvents";
|
static const char* kMsgIdNoteEvents = "NoteEvents";
|
||||||
|
|
||||||
|
static constexpr std::chrono::milliseconds kBackgroundIdleInterval { 500 };
|
||||||
|
|
||||||
SfizzVstProcessor::SfizzVstProcessor()
|
SfizzVstProcessor::SfizzVstProcessor()
|
||||||
: _fifoToWorker(64 * 1024), _fifoMessageFromUi(64 * 1024),
|
: _fifoToWorker(64 * 1024), _fifoMessageFromUi(64 * 1024),
|
||||||
_oscTemp(new uint8_t[kOscTempSize])
|
_oscTemp(new uint8_t[kOscTempSize])
|
||||||
|
|
@ -204,7 +206,6 @@ tresult PLUGIN_API SfizzVstProcessor::setActive(TBool state)
|
||||||
synth->setSampleRate(processSetup.sampleRate);
|
synth->setSampleRate(processSetup.sampleRate);
|
||||||
synth->setSamplesPerBlock(processSetup.maxSamplesPerBlock);
|
synth->setSamplesPerBlock(processSetup.maxSamplesPerBlock);
|
||||||
|
|
||||||
_fileChangePeriod = static_cast<uint32>(1.0 * processSetup.sampleRate);
|
|
||||||
_playStateChangePeriod = static_cast<uint32>(50e-3 * processSetup.sampleRate);
|
_playStateChangePeriod = static_cast<uint32>(50e-3 * processSetup.sampleRate);
|
||||||
|
|
||||||
startBackgroundWork();
|
startBackgroundWork();
|
||||||
|
|
@ -271,13 +272,6 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data)
|
||||||
|
|
||||||
synth.renderBlock(outputs, numFrames, numChannels);
|
synth.renderBlock(outputs, numFrames, numChannels);
|
||||||
|
|
||||||
_fileChangeCounter += numFrames;
|
|
||||||
if (_fileChangeCounter > _fileChangePeriod) {
|
|
||||||
_fileChangeCounter %= _fileChangePeriod;
|
|
||||||
if (writeWorkerMessage(kMsgIdCheckShouldReload, nullptr, 0))
|
|
||||||
_semaToWorker.post();
|
|
||||||
}
|
|
||||||
|
|
||||||
_playStateChangeCounter += numFrames;
|
_playStateChangeCounter += numFrames;
|
||||||
if (_playStateChangeCounter > _playStateChangePeriod) {
|
if (_playStateChangeCounter > _playStateChangePeriod) {
|
||||||
_playStateChangeCounter %= _playStateChangePeriod;
|
_playStateChangeCounter %= _playStateChangePeriod;
|
||||||
|
|
@ -640,19 +634,28 @@ void SfizzVstProcessor::loadSfzFileOrDefault(sfz::Sfizz& synth, const std::strin
|
||||||
|
|
||||||
void SfizzVstProcessor::doBackgroundWork()
|
void SfizzVstProcessor::doBackgroundWork()
|
||||||
{
|
{
|
||||||
|
using Clock = std::chrono::steady_clock;
|
||||||
|
|
||||||
|
bool haveDoneIdleWork = false;
|
||||||
|
Clock::time_point lastIdleWorkTime;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_semaToWorker.wait();
|
bool isNotified = _semaToWorker.timed_wait(kBackgroundIdleInterval.count());
|
||||||
|
|
||||||
if (!_workRunning)
|
if (!_workRunning)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
RTMessagePtr msg = readWorkerMessage();
|
const char* id = nullptr;
|
||||||
if (!msg) {
|
RTMessagePtr msg;
|
||||||
fprintf(stderr, "[Sfizz] message synchronization error in worker\n");
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* id = msg->type;
|
if (isNotified) {
|
||||||
|
msg = readWorkerMessage();
|
||||||
|
if (!msg) {
|
||||||
|
fprintf(stderr, "[Sfizz] message synchronization error in worker\n");
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
id = msg->type;
|
||||||
|
}
|
||||||
|
|
||||||
if (id == kMsgIdSetNumVoices) {
|
if (id == kMsgIdSetNumVoices) {
|
||||||
int32 value = *msg->payload<int32>();
|
int32 value = *msg->payload<int32>();
|
||||||
|
|
@ -669,23 +672,6 @@ void SfizzVstProcessor::doBackgroundWork()
|
||||||
std::lock_guard<SpinMutex> lock(_processMutex);
|
std::lock_guard<SpinMutex> lock(_processMutex);
|
||||||
_synth->setPreloadSize(value);
|
_synth->setPreloadSize(value);
|
||||||
}
|
}
|
||||||
else if (id == kMsgIdCheckShouldReload) {
|
|
||||||
if (_synth->shouldReloadFile()) {
|
|
||||||
fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n");
|
|
||||||
std::lock_guard<SpinMutex> lock(_processMutex);
|
|
||||||
loadSfzFileOrDefault(*_synth, _state.sfzFile);
|
|
||||||
|
|
||||||
Steinberg::OPtr<Vst::IMessage> reply { allocateMessage() };
|
|
||||||
reply->setMessageID("LoadedSfz");
|
|
||||||
reply->getAttributes()->setBinary("File", _state.sfzFile.data(), _state.sfzFile.size());
|
|
||||||
sendMessage(reply);
|
|
||||||
}
|
|
||||||
else if (_synth->shouldReloadScala()) {
|
|
||||||
fprintf(stderr, "[Sfizz] scala file has changed, reloading\n");
|
|
||||||
std::lock_guard<SpinMutex> lock(_processMutex);
|
|
||||||
_synth->loadScalaFile(_state.scalaFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (id == kMsgIdNotifyPlayState) {
|
else if (id == kMsgIdNotifyPlayState) {
|
||||||
SfizzPlayState playState = *msg->payload<SfizzPlayState>();
|
SfizzPlayState playState = *msg->payload<SfizzPlayState>();
|
||||||
Steinberg::OPtr<Vst::IMessage> notification { allocateMessage() };
|
Steinberg::OPtr<Vst::IMessage> notification { allocateMessage() };
|
||||||
|
|
@ -705,6 +691,32 @@ void SfizzVstProcessor::doBackgroundWork()
|
||||||
notification->getAttributes()->setBinary("Events", msg->payload<uint8_t>(), msg->size);
|
notification->getAttributes()->setBinary("Events", msg->payload<uint8_t>(), msg->size);
|
||||||
sendMessage(notification);
|
sendMessage(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Clock::time_point currentTime = Clock::now();
|
||||||
|
if (!haveDoneIdleWork || currentTime - lastIdleWorkTime > kBackgroundIdleInterval) {
|
||||||
|
doBackgroundIdle();
|
||||||
|
haveDoneIdleWork = true;
|
||||||
|
lastIdleWorkTime = currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SfizzVstProcessor::doBackgroundIdle()
|
||||||
|
{
|
||||||
|
if (_synth->shouldReloadFile()) {
|
||||||
|
fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n");
|
||||||
|
std::lock_guard<SpinMutex> lock(_processMutex);
|
||||||
|
loadSfzFileOrDefault(*_synth, _state.sfzFile);
|
||||||
|
|
||||||
|
Steinberg::OPtr<Vst::IMessage> reply { allocateMessage() };
|
||||||
|
reply->setMessageID("LoadedSfz");
|
||||||
|
reply->getAttributes()->setBinary("File", _state.sfzFile.data(), _state.sfzFile.size());
|
||||||
|
sendMessage(reply);
|
||||||
|
}
|
||||||
|
if (_synth->shouldReloadScala()) {
|
||||||
|
fprintf(stderr, "[Sfizz] scala file has changed, reloading\n");
|
||||||
|
std::lock_guard<SpinMutex> lock(_processMutex);
|
||||||
|
_synth->loadScalaFile(_state.scalaFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,6 @@ private:
|
||||||
Ring_Buffer _fifoMessageFromUi;
|
Ring_Buffer _fifoMessageFromUi;
|
||||||
SpinMutex _processMutex;
|
SpinMutex _processMutex;
|
||||||
|
|
||||||
// file modification periodic checker
|
|
||||||
uint32 _fileChangeCounter = 0;
|
|
||||||
uint32 _fileChangePeriod = 0;
|
|
||||||
|
|
||||||
// state notification periodic timer
|
// state notification periodic timer
|
||||||
uint32 _playStateChangeCounter = 0;
|
uint32 _playStateChangeCounter = 0;
|
||||||
uint32 _playStateChangePeriod = 0;
|
uint32 _playStateChangePeriod = 0;
|
||||||
|
|
@ -99,6 +95,7 @@ private:
|
||||||
|
|
||||||
// worker
|
// worker
|
||||||
void doBackgroundWork();
|
void doBackgroundWork();
|
||||||
|
void doBackgroundIdle();
|
||||||
void startBackgroundWork();
|
void startBackgroundWork();
|
||||||
void stopBackgroundWork();
|
void stopBackgroundWork();
|
||||||
// writer
|
// writer
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
RTSemaphore::RTSemaphore(unsigned value)
|
RTSemaphore::RTSemaphore(unsigned value)
|
||||||
{
|
{
|
||||||
|
|
@ -57,6 +58,15 @@ bool RTSemaphore::try_wait()
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RTSemaphore::timed_wait(uint32_t milliseconds)
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
bool b = timed_wait(milliseconds, ec);
|
||||||
|
if (ec)
|
||||||
|
throw std::system_error(ec);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
void RTSemaphore::init(std::error_code& ec, unsigned value)
|
void RTSemaphore::init(std::error_code& ec, unsigned value)
|
||||||
{
|
{
|
||||||
|
|
@ -100,10 +110,17 @@ void RTSemaphore::wait(std::error_code& ec) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RTSemaphore::try_wait(std::error_code& ec) noexcept
|
bool RTSemaphore::try_wait(std::error_code& ec) noexcept
|
||||||
|
{
|
||||||
|
return timed_wait(0, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RTSemaphore::timed_wait(uint32_t milliseconds, std::error_code& ec) noexcept
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
do {
|
do {
|
||||||
const mach_timespec_t timeout = { 0, 0 };
|
mach_timespec_t timeout;
|
||||||
|
timeout.tv_sec = milliseconds / 1000;
|
||||||
|
timeout.tv_nsec = (milliseconds % 1000) * (1000L * 1000L);
|
||||||
kern_return_t ret = semaphore_timedwait(sem_, timeout);
|
kern_return_t ret = semaphore_timedwait(sem_, timeout);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case KERN_SUCCESS:
|
case KERN_SUCCESS:
|
||||||
|
|
@ -178,9 +195,14 @@ void RTSemaphore::wait(std::error_code& ec) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RTSemaphore::try_wait(std::error_code& ec) noexcept
|
bool RTSemaphore::try_wait(std::error_code& ec) noexcept
|
||||||
|
{
|
||||||
|
return timed_wait(0, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RTSemaphore::timed_wait(uint32_t milliseconds, std::error_code& ec) noexcept
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
DWORD ret = WaitForSingleObject(sem_, 0);
|
DWORD ret = WaitForSingleObject(sem_, milliseconds);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case WAIT_OBJECT_0:
|
case WAIT_OBJECT_0:
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -251,4 +273,46 @@ bool RTSemaphore::try_wait(std::error_code& ec) noexcept
|
||||||
}
|
}
|
||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool absolute_timeout(uint32_t milliseconds, timespec &result, std::error_code& ec)
|
||||||
|
{
|
||||||
|
timespec now;
|
||||||
|
if (clock_gettime(CLOCK_REALTIME, &now) != 0) {
|
||||||
|
ec = std::error_code(errno, std::generic_category());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
timespec abs;
|
||||||
|
abs.tv_sec = now.tv_sec + milliseconds / 1000;
|
||||||
|
abs.tv_nsec = now.tv_nsec + (milliseconds % 1000) * (1000L * 1000L);
|
||||||
|
|
||||||
|
long abs_nsec_sec = abs.tv_nsec / (1000L * 1000L * 1000L);
|
||||||
|
abs.tv_sec += abs_nsec_sec;
|
||||||
|
abs.tv_nsec -= abs_nsec_sec * (1000L * 1000L * 1000L);
|
||||||
|
|
||||||
|
result = abs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RTSemaphore::timed_wait(uint32_t milliseconds, std::error_code& ec) noexcept
|
||||||
|
{
|
||||||
|
ec.clear();
|
||||||
|
timespec abs;
|
||||||
|
if (!absolute_timeout(milliseconds, abs, ec))
|
||||||
|
return false;
|
||||||
|
do {
|
||||||
|
if (sem_timedwait(&sem_, &abs) == 0)
|
||||||
|
return true;
|
||||||
|
int e = errno;
|
||||||
|
switch (e) {
|
||||||
|
case EINTR:
|
||||||
|
break;
|
||||||
|
case ETIMEDOUT:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
ec = std::error_code(e, std::generic_category());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#else
|
#else
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <cstdint>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
class RTSemaphore {
|
class RTSemaphore {
|
||||||
|
|
@ -28,10 +29,12 @@ public:
|
||||||
void post();
|
void post();
|
||||||
void wait();
|
void wait();
|
||||||
bool try_wait();
|
bool try_wait();
|
||||||
|
bool timed_wait(uint32_t milliseconds);
|
||||||
|
|
||||||
void post(std::error_code& ec) noexcept;
|
void post(std::error_code& ec) noexcept;
|
||||||
void wait(std::error_code& ec) noexcept;
|
void wait(std::error_code& ec) noexcept;
|
||||||
bool try_wait(std::error_code& ec) noexcept;
|
bool try_wait(std::error_code& ec) noexcept;
|
||||||
|
bool timed_wait(uint32_t milliseconds, std::error_code& ec) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init(std::error_code& ec, unsigned value);
|
void init(std::error_code& ec, unsigned value);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue