@@ -37,6 +37,10 @@ ifeq ($(HAVE_DGL),true) | |||||
STANDALONE_LIBS += $(MODULEDIR)/dgl.a | STANDALONE_LIBS += $(MODULEDIR)/dgl.a | ||||
endif | endif | ||||
ifeq ($(HAVE_HYLIA),true) | |||||
STANDALONE_LIBS += $(MODULEDIR)/hylia.a | |||||
endif | |||||
ifeq ($(MACOS_OR_WIN32),true) | ifeq ($(MACOS_OR_WIN32),true) | ||||
STANDALONE_LIBS += $(MODULEDIR)/juce_audio_devices.a | STANDALONE_LIBS += $(MODULEDIR)/juce_audio_devices.a | ||||
STANDALONE_LIBS += $(MODULEDIR)/juce_audio_processors.a | STANDALONE_LIBS += $(MODULEDIR)/juce_audio_processors.a | ||||
@@ -64,7 +64,23 @@ EngineInternalTime::EngineInternalTime() noexcept | |||||
frame(0), | frame(0), | ||||
bpm(120.0), | bpm(120.0), | ||||
sampleRate(0.0), | sampleRate(0.0), | ||||
#ifdef BUILD_BRIDGE | |||||
tick(0.0) {} | tick(0.0) {} | ||||
#else | |||||
tick(0.0), | |||||
hylia(nullptr), | |||||
hylia_enabled(0) | |||||
{ | |||||
carla_zeroStruct(hylia_time); | |||||
} | |||||
#endif | |||||
EngineInternalTime::~EngineInternalTime() noexcept | |||||
{ | |||||
#ifndef BUILD_BRIDGE | |||||
hylia_cleanup(hylia); | |||||
#endif | |||||
} | |||||
void EngineInternalTime::fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t newFrames) noexcept | void EngineInternalTime::fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t newFrames) noexcept | ||||
{ | { | ||||
@@ -84,6 +100,19 @@ void EngineInternalTime::fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t | |||||
double abs_beat, abs_tick; | double abs_beat, abs_tick; | ||||
#ifndef BUILD_BRIDGE | |||||
if (hylia_enabled > 0 && hylia_time.bpm > 0.0) | |||||
{ | |||||
const double beats = hylia_time.beats; | |||||
if (beats < 0.0) | |||||
return; | |||||
abs_beat = std::floor(beats); | |||||
abs_tick = beats * kTicksPerBeat; | |||||
} | |||||
else | |||||
#endif | |||||
{ | { | ||||
const double min = frame / (sampleRate * 60.0); | const double min = frame / (sampleRate * 60.0); | ||||
abs_tick = min * bpm * kTicksPerBeat; | abs_tick = min * bpm * kTicksPerBeat; | ||||
@@ -316,6 +345,14 @@ void CarlaEngine::ProtectedData::initTime() | |||||
time.sampleRate = sampleRate; | time.sampleRate = sampleRate; | ||||
time.tick = 0.0; | time.tick = 0.0; | ||||
time.fillEngineTimeInfo(timeInfo, 0); | time.fillEngineTimeInfo(timeInfo, 0); | ||||
#ifndef BUILD_BRIDGE | |||||
CARLA_SAFE_ASSERT_RETURN(time.hylia == nullptr,); | |||||
time.hylia = hylia_create(120.0, bufferSize, sampleRate); | |||||
//time.hylia_enabled = 1; | |||||
//hylia_enable(time.hylia, true, 120.0); | |||||
#endif | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -409,8 +446,27 @@ void CarlaEngine::ProtectedData::doNextPluginAction(const bool unlock) noexcept | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// PendingRtEventsRunner | // PendingRtEventsRunner | ||||
PendingRtEventsRunner::PendingRtEventsRunner(CarlaEngine* const engine) noexcept | |||||
: pData(engine->pData) {} | |||||
PendingRtEventsRunner::PendingRtEventsRunner(CarlaEngine* const engine, const uint32_t bufSize) noexcept | |||||
: pData(engine->pData), | |||||
bufferSize(bufSize) | |||||
{ | |||||
#ifndef BUILD_BRIDGE | |||||
if (pData->time.hylia_enabled > 0) | |||||
{ | |||||
hylia_process(pData->time.hylia, bufferSize, &pData->time.hylia_time); | |||||
const double new_bpm = pData->time.hylia_time.bpm; | |||||
if (new_bpm > 0.0 && (pData->time.bpm != new_bpm || ++pData->time.hylia_enabled > 50)) | |||||
{ | |||||
pData->time.bpm = new_bpm; | |||||
pData->time.hylia_enabled = 1; | |||||
if (pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) | |||||
pData->time.fillEngineTimeInfo(pData->timeInfo, 0); | |||||
} | |||||
} | |||||
#endif | |||||
} | |||||
PendingRtEventsRunner::~PendingRtEventsRunner() noexcept | PendingRtEventsRunner::~PendingRtEventsRunner() noexcept | ||||
{ | { | ||||
@@ -418,8 +474,8 @@ PendingRtEventsRunner::~PendingRtEventsRunner() noexcept | |||||
if (pData->time.playing && pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) | if (pData->time.playing && pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) | ||||
{ | { | ||||
pData->time.frame += pData->bufferSize; | |||||
pData->time.fillEngineTimeInfo(pData->timeInfo, pData->bufferSize); | |||||
pData->time.frame += bufferSize; | |||||
pData->time.fillEngineTimeInfo(pData->timeInfo, bufferSize); | |||||
} | } | ||||
} | } | ||||
@@ -22,6 +22,8 @@ | |||||
#include "CarlaEngineThread.hpp" | #include "CarlaEngineThread.hpp" | ||||
#include "CarlaEngineUtils.hpp" | #include "CarlaEngineUtils.hpp" | ||||
#include "hylia/hylia.h" | |||||
// FIXME only use CARLA_PREVENT_HEAP_ALLOCATION for structs | // FIXME only use CARLA_PREVENT_HEAP_ALLOCATION for structs | ||||
// maybe separate macro | // maybe separate macro | ||||
@@ -116,7 +118,14 @@ struct EngineInternalTime { | |||||
double sampleRate; | double sampleRate; | ||||
double tick; | double tick; | ||||
#ifndef BUILD_BRIDGE | |||||
hylia_t* hylia; | |||||
int hylia_enabled; | |||||
hylia_time_info_t hylia_time; | |||||
#endif | |||||
EngineInternalTime() noexcept; | EngineInternalTime() noexcept; | ||||
~EngineInternalTime() noexcept; | |||||
void fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t newFrames) noexcept; | void fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t newFrames) noexcept; | ||||
@@ -245,11 +254,12 @@ struct CarlaEngine::ProtectedData { | |||||
class PendingRtEventsRunner | class PendingRtEventsRunner | ||||
{ | { | ||||
public: | public: | ||||
PendingRtEventsRunner(CarlaEngine* const engine) noexcept; | |||||
PendingRtEventsRunner(CarlaEngine* const engine, const uint32_t bufferSize) noexcept; | |||||
~PendingRtEventsRunner() noexcept; | ~PendingRtEventsRunner() noexcept; | ||||
private: | private: | ||||
CarlaEngine::ProtectedData* const pData; | CarlaEngine::ProtectedData* const pData; | ||||
const uint32_t bufferSize; | |||||
CARLA_PREVENT_HEAP_ALLOCATION | CARLA_PREVENT_HEAP_ALLOCATION | ||||
CARLA_DECLARE_NON_COPY_CLASS(PendingRtEventsRunner) | CARLA_DECLARE_NON_COPY_CLASS(PendingRtEventsRunner) | ||||
@@ -1547,7 +1547,7 @@ protected: | |||||
void handleJackProcessCallback(const uint32_t nframes) | void handleJackProcessCallback(const uint32_t nframes) | ||||
{ | { | ||||
const PendingRtEventsRunner prt(this); | |||||
const PendingRtEventsRunner prt(this, nframes); | |||||
CARLA_SAFE_ASSERT_RETURN(nframes == pData->bufferSize,); | CARLA_SAFE_ASSERT_RETURN(nframes == pData->bufferSize,); | ||||
@@ -1911,7 +1911,7 @@ protected: | |||||
signalThreadShouldExit(); | signalThreadShouldExit(); | ||||
#endif | #endif | ||||
const PendingRtEventsRunner prt(this); | |||||
const PendingRtEventsRunner prt(this, pData->bufferSize); | |||||
for (uint i=0; i < pData->curPluginCount; ++i) | for (uint i=0; i < pData->curPluginCount; ++i) | ||||
{ | { | ||||
@@ -442,9 +442,10 @@ public: | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
protected: | protected: | ||||
void audioDeviceIOCallback(const float** inputChannelData, int numInputChannels, float** outputChannelData, int numOutputChannels, int numSamples) override | |||||
void audioDeviceIOCallback(const float** inputChannelData, int numInputChannels, float** outputChannelData, | |||||
int numOutputChannels, int numSamples) override | |||||
{ | { | ||||
const PendingRtEventsRunner prt(this); | |||||
const PendingRtEventsRunner prt(this, numSamples); | |||||
// assert juce buffers | // assert juce buffers | ||||
CARLA_SAFE_ASSERT_RETURN(numInputChannels >= 0,); | CARLA_SAFE_ASSERT_RETURN(numInputChannels >= 0,); | ||||
@@ -1329,7 +1329,7 @@ protected: | |||||
void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, | void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, | ||||
const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) | const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) | ||||
{ | { | ||||
const PendingRtEventsRunner prt(this); | |||||
const PendingRtEventsRunner prt(this, frames); | |||||
// --------------------------------------------------------------- | // --------------------------------------------------------------- | ||||
// Time Info | // Time Info | ||||
@@ -553,7 +553,7 @@ public: | |||||
protected: | protected: | ||||
void handleAudioProcessCallback(void* outputBuffer, void* inputBuffer, uint nframes, double streamTime, RtAudioStreamStatus status) | void handleAudioProcessCallback(void* outputBuffer, void* inputBuffer, uint nframes, double streamTime, RtAudioStreamStatus status) | ||||
{ | { | ||||
const PendingRtEventsRunner prt(this); | |||||
const PendingRtEventsRunner prt(this, nframes); | |||||
// get buffers from RtAudio | // get buffers from RtAudio | ||||
const float* const insPtr = (const float*)inputBuffer; | const float* const insPtr = (const float*)inputBuffer; | ||||
@@ -694,6 +694,8 @@ protected: | |||||
} | } | ||||
} | } | ||||
fMidiOutMutex.unlock(); | |||||
if (fAudioInterleaved) | if (fAudioInterleaved) | ||||
{ | { | ||||
for (uint i=0; i < nframes; ++i) | for (uint i=0; i < nframes; ++i) | ||||
@@ -701,8 +703,6 @@ protected: | |||||
outsPtr[i*fAudioOutCount+j] = outBuf[j][i]; | outsPtr[i*fAudioOutCount+j] = outBuf[j][i]; | ||||
} | } | ||||
fMidiOutMutex.unlock(); | |||||
return; // unused | return; // unused | ||||
(void)streamTime; (void)status; | (void)streamTime; (void)status; | ||||
} | } | ||||
@@ -41,6 +41,10 @@ ifeq ($(HAVE_DGL),true) | |||||
LIBS += $(MODULEDIR)/dgl.a | LIBS += $(MODULEDIR)/dgl.a | ||||
endif | endif | ||||
ifeq ($(HAVE_HYLIA),true) | |||||
LIBS += $(MODULEDIR)/hylia.a | |||||
endif | |||||
ifeq ($(MACOS_OR_WIN32),true) | ifeq ($(MACOS_OR_WIN32),true) | ||||
LIBS += $(MODULEDIR)/juce_audio_processors.a | LIBS += $(MODULEDIR)/juce_audio_processors.a | ||||
LIBS += $(MODULEDIR)/juce_data_structures.a | LIBS += $(MODULEDIR)/juce_data_structures.a | ||||