@@ -1341,16 +1341,19 @@ void CarlaEngine::setFileCallback(const FileCallbackFunc func, void* const ptr) | |||
void CarlaEngine::transportPlay() noexcept | |||
{ | |||
pData->time.playing = true; | |||
pData->time.fillEngineTimeInfo(pData->timeInfo, 0); | |||
} | |||
void CarlaEngine::transportPause() noexcept | |||
{ | |||
pData->time.playing = false; | |||
pData->time.fillEngineTimeInfo(pData->timeInfo, 0); | |||
} | |||
void CarlaEngine::transportRelocate(const uint64_t frame) noexcept | |||
{ | |||
pData->time.frame = frame; | |||
pData->time.fillEngineTimeInfo(pData->timeInfo, 0); | |||
} | |||
// ----------------------------------------------------------------------- | |||
@@ -1664,6 +1667,9 @@ void CarlaEngine::sampleRateChanged(const double newSampleRate) | |||
} | |||
#endif | |||
pData->time.sampleRate = newSampleRate; | |||
pData->time.fillEngineTimeInfo(pData->timeInfo, 0); | |||
for (uint i=0; i < pData->curPluginCount; ++i) | |||
{ | |||
CarlaPlugin* const plugin(pData->plugins[i].plugin); | |||
@@ -472,6 +472,8 @@ public: | |||
CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetSampleRate, opcode); | |||
pData->sampleRate = fShmNonRtClientControl.readDouble(); | |||
pData->initTime(); | |||
if (shmRtClientDataSize != sizeof(BridgeRtClientData) || shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) | |||
return false; | |||
@@ -57,9 +57,64 @@ void EngineInternalEvents::clear() noexcept | |||
// ----------------------------------------------------------------------- | |||
// InternalTime | |||
static const float kTicksPerBeat = 1920.0f; | |||
EngineInternalTime::EngineInternalTime() noexcept | |||
: playing(false), | |||
frame(0) {} | |||
frame(0), | |||
bpm(120.0), | |||
sampleRate(0.0), | |||
tick(0.0) {} | |||
void EngineInternalTime::fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t newFrames) noexcept | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate),); | |||
info.playing = playing; | |||
info.frame = frame; | |||
info.usecs = 0; | |||
if (newFrames == 0) | |||
{ | |||
info.valid = EngineTimeInfo::kValidBBT; | |||
info.bbt.beatsPerBar = 4.0f; | |||
info.bbt.beatType = 4.0f; | |||
info.bbt.ticksPerBeat = kTicksPerBeat; | |||
info.bbt.beatsPerMinute = bpm; | |||
double abs_beat, abs_tick; | |||
{ | |||
const double min = frame / (sampleRate * 60.0); | |||
abs_tick = min * bpm * kTicksPerBeat; | |||
abs_beat = abs_tick / kTicksPerBeat; | |||
} | |||
info.bbt.bar = abs_beat / info.bbt.beatsPerBar; | |||
info.bbt.beat = abs_beat - (info.bbt.bar * info.bbt.beatsPerBar) + 1; | |||
tick = abs_tick - (abs_beat * kTicksPerBeat); | |||
info.bbt.barStartTick = info.bbt.bar * info.bbt.beatsPerBar * kTicksPerBeat; | |||
info.bbt.bar++; | |||
} | |||
else | |||
{ | |||
tick += newFrames * kTicksPerBeat * bpm / (sampleRate * 60); | |||
while (tick >= kTicksPerBeat) | |||
{ | |||
tick -= kTicksPerBeat; | |||
if (++info.bbt.beat > info.bbt.beatsPerBar) | |||
{ | |||
info.bbt.beat = 1; | |||
++info.bbt.bar; | |||
info.bbt.barStartTick += info.bbt.beatsPerBar * kTicksPerBeat; | |||
} | |||
} | |||
} | |||
info.bbt.tick = (int)(tick + 0.5); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// NextAction | |||
@@ -253,6 +308,16 @@ void CarlaEngine::ProtectedData::close() | |||
name.clear(); | |||
} | |||
void CarlaEngine::ProtectedData::initTime() | |||
{ | |||
time.playing = false; | |||
time.frame = 0; | |||
time.bpm = 120.0; | |||
time.sampleRate = sampleRate; | |||
time.tick = 0.0; | |||
time.fillEngineTimeInfo(timeInfo, 0); | |||
} | |||
// ----------------------------------------------------------------------- | |||
#ifndef BUILD_BRIDGE | |||
@@ -351,13 +416,10 @@ PendingRtEventsRunner::~PendingRtEventsRunner() noexcept | |||
{ | |||
pData->doNextPluginAction(true); | |||
if (pData->time.playing) | |||
pData->time.frame += pData->bufferSize; | |||
if (pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) | |||
if (pData->time.playing && pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) | |||
{ | |||
pData->timeInfo.playing = pData->time.playing; | |||
pData->timeInfo.frame = pData->time.frame; | |||
pData->time.frame += pData->bufferSize; | |||
pData->time.fillEngineTimeInfo(pData->timeInfo, pData->bufferSize); | |||
} | |||
} | |||
@@ -112,9 +112,14 @@ private: | |||
struct EngineInternalTime { | |||
bool playing; | |||
uint64_t frame; | |||
double bpm; | |||
double sampleRate; | |||
double tick; | |||
EngineInternalTime() noexcept; | |||
void fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t newFrames) noexcept; | |||
CARLA_DECLARE_NON_COPY_STRUCT(EngineInternalTime) | |||
}; | |||
@@ -219,6 +224,8 @@ struct CarlaEngine::ProtectedData { | |||
bool init(const char* const clientName); | |||
void close(); | |||
void initTime(); | |||
// ------------------------------------------------------------------- | |||
void doPluginRemove() noexcept; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* Carla Plugin Host | |||
* Copyright (C) 2011-2015 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2011-2017 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
@@ -953,6 +953,7 @@ public: | |||
pData->bufferSize = jackbridge_get_buffer_size(fClient); | |||
pData->sampleRate = jackbridge_get_sample_rate(fClient); | |||
pData->initTime(); | |||
jackbridge_set_thread_init_callback(fClient, carla_jack_thread_init_callback, nullptr); | |||
jackbridge_set_buffer_size_callback(fClient, carla_jack_bufsize_callback, this); | |||
@@ -1117,6 +1118,7 @@ public: | |||
fClient = client; | |||
pData->bufferSize = jackbridge_get_buffer_size(client); | |||
pData->sampleRate = jackbridge_get_sample_rate(client); | |||
pData->initTime(); | |||
jackbridge_set_buffer_size_callback(client, carla_jack_bufsize_callback, this); | |||
jackbridge_set_sample_rate_callback(client, carla_jack_srate_callback, this); | |||
@@ -1532,7 +1534,9 @@ protected: | |||
pData->timeInfo.bbt.beatsPerMinute = fTransportPos.beats_per_minute; | |||
} | |||
else | |||
{ | |||
pData->timeInfo.valid = 0x0; | |||
} | |||
} | |||
else | |||
{ | |||
@@ -1545,6 +1549,8 @@ protected: | |||
{ | |||
const PendingRtEventsRunner prt(this); | |||
CARLA_SAFE_ASSERT_RETURN(nframes == pData->bufferSize,); | |||
saveTransportInfo(); | |||
#ifdef BUILD_BRIDGE | |||
@@ -200,6 +200,7 @@ public: | |||
pData->bufferSize = static_cast<uint32_t>(fDevice->getCurrentBufferSizeSamples()); | |||
pData->sampleRate = fDevice->getCurrentSampleRate(); | |||
pData->initTime(); | |||
pData->graph.create(static_cast<uint32_t>(inputNames.size()), static_cast<uint32_t>(outputNames.size())); | |||
@@ -495,7 +496,7 @@ protected: | |||
fMidiInEvents.mutex.unlock(); | |||
} | |||
pData->graph.process(pData, inputChannelData, outputChannelData, static_cast<uint32_t>(numSamples)); | |||
pData->graph.process(pData, inputChannelData, outputChannelData, nframes); | |||
fMidiOutMutex.lock(); | |||
@@ -603,6 +603,7 @@ public: | |||
pData->bufferSize = pHost->get_buffer_size(pHost->handle); | |||
pData->sampleRate = pHost->get_sample_rate(pHost->handle); | |||
pData->initTime(); | |||
if (outChan == 0) | |||
outChan = inChan; | |||
@@ -282,6 +282,7 @@ public: | |||
pData->bufferSize = bufferFrames; | |||
pData->sampleRate = fAudio.getStreamSampleRate(); | |||
pData->initTime(); | |||
fAudioInCount = iParams.nChannels; | |||
fAudioOutCount = oParams.nChannels; | |||
@@ -51,6 +51,8 @@ public: | |||
fParameters[kParameterMeasures] = 4.0f; | |||
fParameters[kParameterDefLength] = 4.0f; | |||
fParameters[kParameterQuantize] = 4.0f; | |||
fMaxTicks = 48.0*fTimeSigNum*fParameters[kParameterMeasures] /2; // FIXME: why /2 ? | |||
} | |||
protected: | |||
@@ -348,9 +350,11 @@ protected: | |||
midiEvent.data[3] = event->data[3]; | |||
midiEvent.size = event->size; | |||
#ifdef DEBUG | |||
carla_stdout("Playing at %f :: %03X:%03i:%03i", | |||
float(double(midiEvent.time)*fTicksPerFrame), | |||
midiEvent.data[0], midiEvent.data[1], midiEvent.data[2]); | |||
#endif | |||
NativePluginAndUiClass::writeMidiEvent(&midiEvent); | |||
} | |||