Browse Source

Rework carla-lv2 time info code similar to DPF, should work better

tags/1.9.7
falkTX 9 years ago
parent
commit
c2de6b2af4
1 changed files with 191 additions and 112 deletions
  1. +191
    -112
      source/plugin/carla-lv2.cpp

+ 191
- 112
source/plugin/carla-lv2.cpp View File

@@ -82,7 +82,6 @@ public:
#endif
fMidiEventCount(0),
fTimeInfo(),
fLastTimeSpeed(0.0),
fIsOffline(false),
fBufferSize(0),
fSampleRate(sampleRate),
@@ -97,11 +96,7 @@ public:
hide = extui_hide;

CarlaString resourceDir(bundlePath);
#ifdef CARLA_OS_WIN
resourceDir += "\\resources\\";
#else
resourceDir += "/resources/";
#endif
resourceDir += CARLA_OS_SEP_STR "resources" CARLA_OS_SEP_STR;

fHost.handle = this;
fHost.resourceDir = resourceDir.dup();
@@ -164,16 +159,6 @@ public:
}

fUridMap = uridMap;

if (fDescriptor->midiIns > 0)
fUI.portOffset += desc->midiIns;
else if (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME)
fUI.portOffset += 1;

fUI.portOffset += desc->midiOuts;
fUI.portOffset += 1; // freewheel
fUI.portOffset += desc->audioIns;
fUI.portOffset += desc->audioOuts;
}

~NativePlugin()
@@ -189,7 +174,7 @@ public:

bool init()
{
if (fUI.portOffset == 0)
if (fUridMap == nullptr)
{
// host is missing features
return false;
@@ -213,6 +198,26 @@ public:
carla_zeroStructs(fMidiEvents, kMaxMidiEvents*2);
carla_zeroStruct(fTimeInfo);

// hosts may not send all values, resulting on some invalid data
fTimeInfo.bbt.bar = 1;
fTimeInfo.bbt.beat = 1;
fTimeInfo.bbt.tick = 0;
fTimeInfo.bbt.barStartTick = 0;
fTimeInfo.bbt.beatsPerBar = 4;
fTimeInfo.bbt.beatType = 4;
fTimeInfo.bbt.ticksPerBeat = 960.0;
fTimeInfo.bbt.beatsPerMinute = 120.0;

if (fDescriptor->midiIns > 0)
fUI.portOffset += fDescriptor->midiIns;
else if (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME)
fUI.portOffset += 1;

fUI.portOffset += fDescriptor->midiOuts;
fUI.portOffset += 1; // freewheel
fUI.portOffset += fDescriptor->audioIns;
fUI.portOffset += fDescriptor->audioOuts;

fPorts.init(fDescriptor, fHandle);
fURIs.map(fUridMap);

@@ -285,13 +290,11 @@ public:

if (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME)
{
LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[0], iter)
LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[0], event)
{
const LV2_Atom_Event* const event((const LV2_Atom_Event*)iter);

if (event == nullptr)
continue;
if (event->body.type != fURIs.atomBlank)
if (event->body.type != fURIs.atomBlank && event->body.type != fURIs.atomObject)
continue;

const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body);
@@ -299,153 +302,186 @@ public:
if (obj->body.otype != fURIs.timePos)
continue;

LV2_Atom* bar = nullptr;
LV2_Atom* barBeat = nullptr;
LV2_Atom* beat = nullptr;
LV2_Atom* bar = nullptr;
LV2_Atom* barBeat = nullptr;
LV2_Atom* beatUnit = nullptr;
LV2_Atom* beatsPerBar = nullptr;
LV2_Atom* beatsPerMinute = nullptr;
LV2_Atom* ticksPerBeat = nullptr;
LV2_Atom* frame = nullptr;
LV2_Atom* speed = nullptr;
LV2_Atom* ticksPerBeat = nullptr;

lv2_atom_object_get(obj,
fURIs.timeBar, &bar,
fURIs.timeBarBeat, &barBeat,
fURIs.timeBeat, &beat,
fURIs.timeBeatUnit, &beatUnit,
fURIs.timeBeatsPerBar, &beatsPerBar,
fURIs.timeBeatsPerMinute, &beatsPerMinute,
fURIs.timeTicksPerBeat, &ticksPerBeat,
fURIs.timeFrame, &frame,
fURIs.timeSpeed, &speed,
fURIs.timeTicksPerBeat, &ticksPerBeat,
nullptr);

// need to handle this first as other values depend on it
if (ticksPerBeat != nullptr)
{
/**/ if (ticksPerBeat->type == fURIs.atomDouble)
fLastPositionData.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body;
else if (ticksPerBeat->type == fURIs.atomFloat)
fLastPositionData.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body;
else if (ticksPerBeat->type == fURIs.atomInt)
fLastPositionData.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body;
else if (ticksPerBeat->type == fURIs.atomLong)
fLastPositionData.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body;
else
carla_stderr("Unknown lv2 ticksPerBeat value type");

if (fLastPositionData.ticksPerBeat > 0)
fTimeInfo.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat;
}

// same
if (speed != nullptr)
{
/**/ if (speed->type == fURIs.atomDouble)
fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body;
else if (speed->type == fURIs.atomFloat)
fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body;
else if (speed->type == fURIs.atomInt)
fLastPositionData.speed = ((LV2_Atom_Int*)speed)->body;
else if (speed->type == fURIs.atomLong)
fLastPositionData.speed = ((LV2_Atom_Long*)speed)->body;
else
carla_stderr("Unknown lv2 speed value type");

fTimeInfo.playing = carla_isNotZero(fLastPositionData.speed);
}

if (bar != nullptr)
{
/**/ if (bar->type == fURIs.atomDouble)
fTimeInfo.bbt.bar = static_cast<int32_t>(((LV2_Atom_Double*)bar)->body + 1.0);
fLastPositionData.bar = ((LV2_Atom_Double*)bar)->body;
else if (bar->type == fURIs.atomFloat)
fTimeInfo.bbt.bar = static_cast<int32_t>(((LV2_Atom_Float*)bar)->body + 1.0f);
fLastPositionData.bar = ((LV2_Atom_Float*)bar)->body;
else if (bar->type == fURIs.atomInt)
fTimeInfo.bbt.bar = static_cast<int32_t>(((LV2_Atom_Int*)bar)->body + 1);
fLastPositionData.bar = ((LV2_Atom_Int*)bar)->body;
else if (bar->type == fURIs.atomLong)
fTimeInfo.bbt.bar = static_cast<int32_t>(((LV2_Atom_Long*)bar)->body + 1);
fLastPositionData.bar = ((LV2_Atom_Long*)bar)->body;
else
carla_stderr("Unknown lv2 bar value type");
}

if (ticksPerBeat != nullptr)
{
/**/ if (ticksPerBeat->type == fURIs.atomDouble)
fTimeInfo.bbt.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body;
else if (ticksPerBeat->type == fURIs.atomFloat)
fTimeInfo.bbt.ticksPerBeat = static_cast<double>(((LV2_Atom_Float*)ticksPerBeat)->body);
else if (ticksPerBeat->type == fURIs.atomInt)
fTimeInfo.bbt.ticksPerBeat = static_cast<double>(((LV2_Atom_Int*)ticksPerBeat)->body);
else if (ticksPerBeat->type == fURIs.atomLong)
fTimeInfo.bbt.ticksPerBeat = static_cast<double>(((LV2_Atom_Long*)ticksPerBeat)->body);
else
carla_stderr("Unknown lv2 ticksPerBeat value type");
if (fLastPositionData.bar >= 0)
fTimeInfo.bbt.bar = fLastPositionData.bar + 1;
}

if (barBeat != nullptr)
{
double barBeatValue = 0.0;

/**/ if (barBeat->type == fURIs.atomDouble)
barBeatValue = ((LV2_Atom_Double*)barBeat)->body;
fLastPositionData.barBeat = ((LV2_Atom_Double*)barBeat)->body;
else if (barBeat->type == fURIs.atomFloat)
barBeatValue = static_cast<double>(((LV2_Atom_Float*)barBeat)->body);
fLastPositionData.barBeat = ((LV2_Atom_Float*)barBeat)->body;
else if (barBeat->type == fURIs.atomInt)
barBeatValue = static_cast<double>(((LV2_Atom_Int*)barBeat)->body);
fLastPositionData.barBeat = ((LV2_Atom_Int*)barBeat)->body;
else if (barBeat->type == fURIs.atomLong)
barBeatValue = static_cast<double>(((LV2_Atom_Long*)barBeat)->body);
fLastPositionData.barBeat = ((LV2_Atom_Long*)barBeat)->body;
else
carla_stderr("Unknown lv2 barBeat value type");

const double rest = std::fmod(barBeatValue, 1.0);
fTimeInfo.bbt.beat = static_cast<int32_t>(barBeatValue-rest+1.0);
fTimeInfo.bbt.tick = static_cast<int32_t>(rest*fTimeInfo.bbt.ticksPerBeat+0.5);
}
// barBeat includes beat
else if (beat != nullptr)
{
/**/ if (beat->type == fURIs.atomDouble)
fTimeInfo.bbt.beat = static_cast<int32_t>(((LV2_Atom_Double*)beat)->body + 1.0);
else if (beat->type == fURIs.atomFloat)
fTimeInfo.bbt.beat = static_cast<int32_t>(((LV2_Atom_Float*)beat)->body + 1.0f);
else if (beat->type == fURIs.atomInt)
fTimeInfo.bbt.beat = static_cast<int32_t>(((LV2_Atom_Int*)beat)->body + 1);
else if (beat->type == fURIs.atomLong)
fTimeInfo.bbt.beat = static_cast<int32_t>(((LV2_Atom_Long*)beat)->body + 1);
else
carla_stderr("Unknown lv2 beat value type");
if (fLastPositionData.barBeat >= 0.0f)
{
const double rest = std::fmod(fLastPositionData.barBeat, 1.0);
fTimeInfo.bbt.beat = fLastPositionData.barBeat-rest+1.0;
fTimeInfo.bbt.tick = rest*fTimeInfo.bbt.ticksPerBeat+0.5;
}
}

if (beatUnit != nullptr)
{
/**/ if (beatUnit->type == fURIs.atomDouble)
fTimeInfo.bbt.beatType = static_cast<float>(((LV2_Atom_Double*)beatUnit)->body);
fLastPositionData.beatUnit = ((LV2_Atom_Double*)beatUnit)->body;
else if (beatUnit->type == fURIs.atomFloat)
fTimeInfo.bbt.beatType = ((LV2_Atom_Float*)beatUnit)->body;
fLastPositionData.beatUnit = ((LV2_Atom_Float*)beatUnit)->body;
else if (beatUnit->type == fURIs.atomInt)
fTimeInfo.bbt.beatType = static_cast<float>(((LV2_Atom_Int*)beatUnit)->body);
fLastPositionData.beatUnit = ((LV2_Atom_Int*)beatUnit)->body;
else if (beatUnit->type == fURIs.atomLong)
fTimeInfo.bbt.beatType = static_cast<float>(((LV2_Atom_Long*)beatUnit)->body);
fLastPositionData.beatUnit = ((LV2_Atom_Long*)beatUnit)->body;
else
carla_stderr("Unknown lv2 beatUnit value type");

if (fLastPositionData.beatUnit > 0)
fTimeInfo.bbt.beatType = fLastPositionData.beatUnit;
}

if (beatsPerBar != nullptr)
{
/**/ if (beatsPerBar->type == fURIs.atomDouble)
fTimeInfo.bbt.beatsPerBar = static_cast<float>(((LV2_Atom_Double*)beatsPerBar)->body);
fLastPositionData.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body;
else if (beatsPerBar->type == fURIs.atomFloat)
fTimeInfo.bbt.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body;
fLastPositionData.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body;
else if (beatsPerBar->type == fURIs.atomInt)
fTimeInfo.bbt.beatsPerBar = static_cast<float>(((LV2_Atom_Int*)beatsPerBar)->body);
fLastPositionData.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body;
else if (beatsPerBar->type == fURIs.atomLong)
fTimeInfo.bbt.beatsPerBar = static_cast<float>(((LV2_Atom_Long*)beatsPerBar)->body);
fLastPositionData.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body;
else
carla_stderr("Unknown lv2 beatsPerBar value type");

if (fLastPositionData.beatsPerBar > 0.0f)
fTimeInfo.bbt.beatsPerBar = fLastPositionData.beatsPerBar;
}

if (beatsPerMinute != nullptr)
{
/**/ if (beatsPerMinute->type == fURIs.atomDouble)
fTimeInfo.bbt.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body;
fLastPositionData.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body;
else if (beatsPerMinute->type == fURIs.atomFloat)
fTimeInfo.bbt.beatsPerMinute = static_cast<double>(((LV2_Atom_Float*)beatsPerMinute)->body);
fLastPositionData.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body;
else if (beatsPerMinute->type == fURIs.atomInt)
fTimeInfo.bbt.beatsPerMinute = static_cast<double>(((LV2_Atom_Int*)beatsPerMinute)->body);
fLastPositionData.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body;
else if (beatsPerMinute->type == fURIs.atomLong)
fTimeInfo.bbt.beatsPerMinute = static_cast<double>(((LV2_Atom_Long*)beatsPerMinute)->body);
fLastPositionData.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body;
else
carla_stderr("Unknown lv2 beatsPerMinute value type");
}

fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat*fTimeInfo.bbt.beatsPerBar*(fTimeInfo.bbt.bar-1);
if (fLastPositionData.beatsPerMinute > 0.0f)
{
fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute;

if (frame != nullptr && frame->type == fURIs.atomLong)
fTimeInfo.frame = static_cast<uint64_t>(((LV2_Atom_Long*)frame)->body);
if (carla_isNotZero(fLastPositionData.speed))
fTimeInfo.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed);
}
}

if (speed != nullptr && speed->type == fURIs.atomFloat)
if (frame != nullptr)
{
fLastTimeSpeed = ((LV2_Atom_Float*)speed)->body;
fTimeInfo.playing = carla_isEqual(fLastTimeSpeed, 1.0);
/**/ if (frame->type == fURIs.atomDouble)
fLastPositionData.frame = ((LV2_Atom_Double*)frame)->body;
else if (frame->type == fURIs.atomFloat)
fLastPositionData.frame = ((LV2_Atom_Float*)frame)->body;
else if (frame->type == fURIs.atomInt)
fLastPositionData.frame = ((LV2_Atom_Int*)frame)->body;
else if (frame->type == fURIs.atomLong)
fLastPositionData.frame = ((LV2_Atom_Long*)frame)->body;
else
carla_stderr("Unknown lv2 frame value type");

if (fLastPositionData.frame >= 0)
fTimeInfo.frame = fLastPositionData.frame;
}

fTimeInfo.bbt.valid = (beatsPerMinute != nullptr && beatsPerBar != nullptr && beatUnit != nullptr);
fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat*
fTimeInfo.bbt.beatsPerBar*
(fTimeInfo.bbt.bar-1);

fTimeInfo.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 &&
fLastPositionData.beatUnit > 0 &&
fLastPositionData.beatsPerBar > 0.0f);
}
}

for (uint32_t i=0; i < fDescriptor->midiIns; ++i)
{
LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[i], iter)
LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[i], event)
{
const LV2_Atom_Event* const event((const LV2_Atom_Event*)iter);

if (event == nullptr)
continue;
if (event->body.type != fURIs.midiEvent)
@@ -476,37 +512,56 @@ public:
fDescriptor->process(fHandle, const_cast<float**>(fPorts.audioIns), fPorts.audioOuts, frames, fMidiEvents, fMidiEventCount);

// update timePos for next callback
if (carla_isNotEqual(fLastTimeSpeed, 0.0))
if (carla_isNotZero(fLastPositionData.speed))
{
const double newFrames = fLastTimeSpeed*frames;
if (fLastPositionData.speed > 0.0)
{
// playing forwards
fLastPositionData.frame += frames;
}
else
{
// playing backwards
fLastPositionData.frame -= frames;

if (fLastPositionData.frame < 0)
fLastPositionData.frame = 0;
}

fTimeInfo.frame += static_cast<uint64_t>(newFrames);
fTimeInfo.frame = fLastPositionData.frame;

if (fTimeInfo.bbt.valid)
{
const double samplesPerBeat = 60.0 / fTimeInfo.bbt.beatsPerMinute * fSampleRate;
const double ticksPerSample = fTimeInfo.bbt.ticksPerBeat / samplesPerBeat;

double newTickPos = double(fTimeInfo.bbt.tick) + ticksPerSample*newFrames;
double newBeatPos = double(fTimeInfo.bbt.beat)-1.0;
double newBarPos = double(fTimeInfo.bbt.bar)-1.0;
const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed;
const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute;
const double addedBarBeats = double(frames) / framesPerBeat;

for (; newTickPos >= fTimeInfo.bbt.ticksPerBeat;)
if (fLastPositionData.barBeat >= 0.0f)
{
++newBeatPos;
newTickPos -= fTimeInfo.bbt.ticksPerBeat;
}
fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+addedBarBeats,
fLastPositionData.beatsPerBar);

for (; newBeatPos >= fTimeInfo.bbt.beatsPerBar;)
{
++newBarPos;
newBeatPos -= fTimeInfo.bbt.beatsPerBar;
const double rest = std::fmod(fLastPositionData.barBeat, 1.0);
fTimeInfo.bbt.beat = fLastPositionData.barBeat-rest+1.0;
fTimeInfo.bbt.tick = rest*fTimeInfo.bbt.ticksPerBeat+0.5;

if (fLastPositionData.bar >= 0)
{
fLastPositionData.bar += std::floor((fLastPositionData.barBeat+addedBarBeats)/
fLastPositionData.beatsPerBar);

if (fLastPositionData.bar < 0)
fLastPositionData.bar = 0;

fTimeInfo.bbt.bar = fLastPositionData.bar + 1;

fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat*
fTimeInfo.bbt.beatsPerBar*
(fTimeInfo.bbt.bar-1);
}
}

fTimeInfo.bbt.bar = static_cast<int32_t>(newBarPos+1.0);
fTimeInfo.bbt.beat = static_cast<int32_t>(newBeatPos+1.0);
fTimeInfo.bbt.tick = static_cast<int32_t>(newTickPos);
fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat*fTimeInfo.bbt.beatsPerBar*(fTimeInfo.bbt.bar-1);
fTimeInfo.bbt.beatsPerMinute = std::abs(beatsPerMinute);
}
}

@@ -988,7 +1043,6 @@ private:
uint32_t fMidiEventCount;
NativeMidiEvent fMidiEvents[kMaxMidiEvents*2];
NativeTimeInfo fTimeInfo;
double fLastTimeSpeed;

// Lv2 host data
bool fIsOffline;
@@ -997,8 +1051,31 @@ private:

const LV2_URID_Map* fUridMap;

struct Lv2PositionData {
int64_t bar;
float barBeat;
uint32_t beatUnit;
float beatsPerBar;
float beatsPerMinute;
int64_t frame;
double speed;
int64_t ticksPerBeat;

Lv2PositionData()
: bar(-1),
barBeat(-1.0f),
beatUnit(0),
beatsPerBar(0.0f),
beatsPerMinute(0.0f),
frame(-1),
speed(0.0),
ticksPerBeat(-1) {}

} fLastPositionData;

struct URIDs {
LV2_URID atomBlank;
LV2_URID atomObject;
LV2_URID atomDouble;
LV2_URID atomFloat;
LV2_URID atomInt;
@@ -1019,6 +1096,7 @@ private:

URIDs()
: atomBlank(0),
atomObject(0),
atomDouble(0),
atomFloat(0),
atomInt(0),
@@ -1040,6 +1118,7 @@ private:
void map(const LV2_URID_Map* const uridMap)
{
atomBlank = uridMap->map(uridMap->handle, LV2_ATOM__Blank);
atomObject = uridMap->map(uridMap->handle, LV2_ATOM__Object);
atomDouble = uridMap->map(uridMap->handle, LV2_ATOM__Double);
atomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float);
atomInt = uridMap->map(uridMap->handle, LV2_ATOM__Int);


Loading…
Cancel
Save