@@ -312,10 +312,7 @@ public: | |||||
fURIDs.timeSpeed, &speed, | fURIDs.timeSpeed, &speed, | ||||
nullptr); | nullptr); | ||||
// Not possible with LV2: | |||||
// -> barStartTick | |||||
// -> ticksPerBeat | |||||
fTimePosition.bbt.barStartTick = 0.0; | |||||
// ticksPerBeat is not possible with LV2 | |||||
fTimePosition.bbt.ticksPerBeat = 960.0; | fTimePosition.bbt.ticksPerBeat = 960.0; | ||||
if (bar != nullptr) | if (bar != nullptr) | ||||
@@ -337,27 +334,19 @@ public: | |||||
double barBeatValue = 0.0; | double barBeatValue = 0.0; | ||||
/**/ if (barBeat->type == fURIDs.atomDouble) | /**/ if (barBeat->type == fURIDs.atomDouble) | ||||
barBeatValue = ((LV2_Atom_Double*)barBeat)->body + 1.0; | |||||
barBeatValue = ((LV2_Atom_Double*)barBeat)->body; | |||||
else if (barBeat->type == fURIDs.atomFloat) | else if (barBeat->type == fURIDs.atomFloat) | ||||
barBeatValue = ((LV2_Atom_Float*)barBeat)->body + 1.0f; | |||||
barBeatValue = ((LV2_Atom_Float*)barBeat)->body; | |||||
else if (barBeat->type == fURIDs.atomInt) | else if (barBeat->type == fURIDs.atomInt) | ||||
barBeatValue = ((LV2_Atom_Int*)barBeat)->body + 1; | |||||
barBeatValue = ((LV2_Atom_Int*)barBeat)->body; | |||||
else if (barBeat->type == fURIDs.atomLong) | else if (barBeat->type == fURIDs.atomLong) | ||||
barBeatValue = ((LV2_Atom_Long*)barBeat)->body + 1; | |||||
barBeatValue = ((LV2_Atom_Long*)barBeat)->body; | |||||
else | else | ||||
d_stderr("Unknown lv2 barBeat value type"); | d_stderr("Unknown lv2 barBeat value type"); | ||||
if (barBeatValue != 0.0) | |||||
{ | |||||
const double beat = std::floor(barBeatValue); | |||||
fTimePosition.bbt.beat = beat; | |||||
fTimePosition.bbt.tick = (barBeatValue-beat)*fTimePosition.bbt.ticksPerBeat; | |||||
} | |||||
else | |||||
{ | |||||
fTimePosition.bbt.beat = 0; | |||||
fTimePosition.bbt.tick = 0; | |||||
} | |||||
const double rest = std::fmod(barBeatValue, 1.0); | |||||
fTimePosition.bbt.beat = barBeatValue-rest+1.0; | |||||
fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; | |||||
} | } | ||||
// barBeat includes beat | // barBeat includes beat | ||||
else if (beat != nullptr) | else if (beat != nullptr) | ||||
@@ -416,6 +405,8 @@ public: | |||||
d_stderr("Unknown lv2 beatsPerMinute value type"); | d_stderr("Unknown lv2 beatsPerMinute value type"); | ||||
} | } | ||||
fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*fTimePosition.bbt.beatsPerBar*(fTimePosition.bbt.bar-1); | |||||
if (frame != nullptr && frame->type == fURIDs.atomLong) | if (frame != nullptr && frame->type == fURIDs.atomLong) | ||||
fTimePosition.frame = ((LV2_Atom_Long*)frame)->body; | fTimePosition.frame = ((LV2_Atom_Long*)frame)->body; | ||||
@@ -494,6 +485,7 @@ public: | |||||
fTimePosition.bbt.bar = newBarPos+1.0; | fTimePosition.bbt.bar = newBarPos+1.0; | ||||
fTimePosition.bbt.beat = newBeatPos+1.0; | fTimePosition.bbt.beat = newBeatPos+1.0; | ||||
fTimePosition.bbt.tick = newTickPos; | fTimePosition.bbt.tick = newTickPos; | ||||
fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*fTimePosition.bbt.beatsPerBar*(fTimePosition.bbt.bar-1); | |||||
} | } | ||||
} | } | ||||
# endif | # endif | ||||
@@ -57,10 +57,6 @@ struct ERect { | |||||
# include "vst/aeffectx.h" | # include "vst/aeffectx.h" | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||||
# warning VST TimePos still TODO (only basic BBT working) | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
typedef std::map<const d_string,d_string> StringMap; | typedef std::map<const d_string,d_string> StringMap; | ||||
@@ -624,23 +620,51 @@ public: | |||||
void vst_processReplacing(const float** const inputs, float** const outputs, const int32_t sampleFrames) | void vst_processReplacing(const float** const inputs, float** const outputs, const int32_t sampleFrames) | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | #if DISTRHO_PLUGIN_WANT_TIMEPOS | ||||
static const int kWantVstTimeFlags(kVstTransportPlaying|kVstTempoValid|kVstTimeSigValid); | |||||
static const int kWantVstTimeFlags(kVstTransportPlaying|kVstPpqPosValid|kVstTempoValid|kVstBarsValid|kVstTimeSigValid); | |||||
if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)fAudioMaster(fEffect, audioMasterGetTime, 0, kWantVstTimeFlags, nullptr, 0.0f)) | if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)fAudioMaster(fEffect, audioMasterGetTime, 0, kWantVstTimeFlags, nullptr, 0.0f)) | ||||
{ | { | ||||
fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying); | |||||
fTimePosition.frame = vstTimeInfo->samplePos; | |||||
fTimePosition.frame = vstTimeInfo->samplePos; | |||||
fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying); | |||||
fTimePosition.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0); | fTimePosition.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0); | ||||
if (vstTimeInfo->flags & kVstTempoValid) | |||||
// ticksPerBeat is not possible with VST | |||||
fTimePosition.bbt.ticksPerBeat = 960.0; | |||||
if (vstTimeInfo->flags & kVstPpqPosValid) | |||||
{ | { | ||||
fTimePosition.bbt.beatsPerMinute = vstTimeInfo->tempo; | |||||
const int ppqPerBar = vstTimeInfo->timeSigNumerator * 4 / vstTimeInfo->timeSigDenominator; | |||||
const double barBeats = (std::fmod(vstTimeInfo->ppqPos, ppqPerBar) / ppqPerBar) * vstTimeInfo->timeSigDenominator; | |||||
const double rest = std::fmod(barBeats, 1.0); | |||||
fTimePosition.bbt.bar = int(vstTimeInfo->ppqPos)/ppqPerBar + 1; | |||||
fTimePosition.bbt.beat = barBeats-rest+1; | |||||
fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; | |||||
} | |||||
else | |||||
{ | |||||
fTimePosition.bbt.bar = 1; | |||||
fTimePosition.bbt.beat = 1; | |||||
fTimePosition.bbt.tick = 0; | |||||
} | } | ||||
fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*fTimePosition.bbt.beatsPerBar*(fTimePosition.bbt.bar-1); | |||||
if (vstTimeInfo->flags & kVstTimeSigValid) | if (vstTimeInfo->flags & kVstTimeSigValid) | ||||
{ | { | ||||
fTimePosition.bbt.beatsPerBar = vstTimeInfo->timeSigNumerator; | fTimePosition.bbt.beatsPerBar = vstTimeInfo->timeSigNumerator; | ||||
fTimePosition.bbt.beatType = vstTimeInfo->timeSigDenominator; | fTimePosition.bbt.beatType = vstTimeInfo->timeSigDenominator; | ||||
} | } | ||||
else | |||||
{ | |||||
fTimePosition.bbt.beatsPerBar = 4.0f; | |||||
fTimePosition.bbt.beatType = 4.0f; | |||||
} | |||||
if (vstTimeInfo->flags & kVstTempoValid) | |||||
fTimePosition.bbt.beatsPerMinute = vstTimeInfo->tempo; | |||||
else | |||||
fTimePosition.bbt.beatsPerMinute = 120.0; | |||||
fPlugin.setTimePosition(fTimePosition); | fPlugin.setTimePosition(fTimePosition); | ||||
} | } | ||||
@@ -2,7 +2,7 @@ | |||||
* aeffectx.h - simple header to allow VeSTige compilation and eventually work | * aeffectx.h - simple header to allow VeSTige compilation and eventually work | ||||
* | * | ||||
* Copyright (c) 2006 Javier Serrano Polo <jasp00/at/users.sourceforge.net> | * Copyright (c) 2006 Javier Serrano Polo <jasp00/at/users.sourceforge.net> | ||||
* | |||||
* | |||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net | * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net | ||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
@@ -113,12 +113,11 @@ | |||||
#define kEffectMagic (CCONST( 'V', 's', 't', 'P' )) | #define kEffectMagic (CCONST( 'V', 's', 't', 'P' )) | ||||
#define kVstLangEnglish 1 | #define kVstLangEnglish 1 | ||||
#define kVstMidiType 1 | #define kVstMidiType 1 | ||||
#define kVstTempoValid (1 << 10) | |||||
#define kVstTransportPlaying (1 << 1) | |||||
struct RemoteVstPlugin; | struct RemoteVstPlugin; | ||||
#define kVstTransportPlaying (1 << 1) | |||||
#define kVstNanosValid (1 << 8) | #define kVstNanosValid (1 << 8) | ||||
#define kVstPpqPosValid (1 << 9) | #define kVstPpqPosValid (1 << 9) | ||||
#define kVstTempoValid (1 << 10) | #define kVstTempoValid (1 << 10) | ||||
@@ -250,29 +249,26 @@ struct _AEffect | |||||
typedef struct _AEffect AEffect; | typedef struct _AEffect AEffect; | ||||
struct _VstTimeInfo | |||||
typedef struct _VstTimeInfo | |||||
{ | { | ||||
// 00 | |||||
double samplePos; | |||||
// 08 | |||||
double sampleRate; | |||||
// unconfirmed 10 18 | |||||
char empty1[8 + 8]; | |||||
// 20? | |||||
double tempo; | |||||
// unconfirmed 28 30 38 | |||||
char empty2[8 + 8 + 8]; | |||||
// 40? | |||||
int timeSigNumerator; | |||||
// 44? | |||||
int timeSigDenominator; | |||||
// unconfirmed 48 4c 50 | |||||
char empty3[4 + 4 + 4]; | |||||
// 54 | |||||
int flags; | |||||
}; | |||||
/* info from online documentation of VST provided by Steinberg */ | |||||
double samplePos; | |||||
double sampleRate; | |||||
double nanoSeconds; | |||||
double ppqPos; | |||||
double tempo; | |||||
double barStartPos; | |||||
double cycleStartPos; | |||||
double cycleEndPos; | |||||
int32_t timeSigNumerator; | |||||
int32_t timeSigDenominator; | |||||
int32_t smpteOffset; | |||||
int32_t smpteFrameRate; | |||||
int32_t samplesToNextClock; | |||||
int32_t flags; | |||||
typedef struct _VstTimeInfo VstTimeInfo; | |||||
} VstTimeInfo; | |||||
typedef intptr_t (* audioMasterCallback) (AEffect *, int32_t, int32_t, intptr_t, void *, float); | typedef intptr_t (* audioMasterCallback) (AEffect *, int32_t, int32_t, intptr_t, void *, float); | ||||