1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-18 17:10:05 +02:00

Add buffer delay compensation and settings dialog

The buffer delay compensation resolves the issue where an effect
may add a delay to the output.  This would cause the output to shift
and the final samples to get chopped off.

The settings (click Settings on any VST dialog) dialog allows the user
to enable/disable the BDC and to set their desired buffer size (within
reason) to help improve performance.

In addition it fixes a bug in the plugin scan list were you could click
OK twice and have two scans going, eventually asserting.
This commit is contained in:
lllucius 2014-05-20 05:30:41 +00:00
parent fbf9ca213c
commit 001c8a80f7
3 changed files with 397 additions and 56 deletions

View File

@ -14,6 +14,10 @@
**********************************************************************/ **********************************************************************/
// *******************************************************************
// WARNING: This is NOT 64-bit safe
// *******************************************************************
#include "../../Audacity.h" #include "../../Audacity.h"
#if USE_VST #if USE_VST
@ -30,6 +34,7 @@
#include <wx/slider.h> #include <wx/slider.h>
#include <wx/scrolwin.h> #include <wx/scrolwin.h>
#include <wx/stattext.h> #include <wx/stattext.h>
#include <wx/statbox.h>
#include <wx/stopwatch.h> #include <wx/stopwatch.h>
#include <wx/utils.h> #include <wx/utils.h>
#include <wx/dcclient.h> #include <wx/dcclient.h>
@ -59,8 +64,9 @@
#include "../../Prefs.h" #include "../../Prefs.h"
#include "../../xml/XMLFileReader.h" #include "../../xml/XMLFileReader.h"
#include "../../xml/XMLWriter.h" #include "../../xml/XMLWriter.h"
#include "../EffectManager.h"
#include "../../Theme.h" #include "../../Theme.h"
#include "../../widgets/valnum.h"
#include "../EffectManager.h"
#include "../images/Arrow.xpm" #include "../images/Arrow.xpm"
#include "VSTEffect.h" #include "VSTEffect.h"
@ -679,6 +685,7 @@ void PluginRegistrationDialog::ToggleItem(int i)
void PluginRegistrationDialog::OnApply(wxCommandEvent & WXUNUSED(event)) void PluginRegistrationDialog::OnApply(wxCommandEvent & WXUNUSED(event))
{ {
mCancelClicked = false; mCancelClicked = false;
Disable();
size_t cnt = mFiles.GetCount(); size_t cnt = mFiles.GetCount();
for (size_t i = 0; i < cnt && !mCancelClicked; i++) { for (size_t i = 0; i < cnt && !mCancelClicked; i++) {
@ -704,9 +711,126 @@ void PluginRegistrationDialog::OnCancel(wxCommandEvent & WXUNUSED(event))
EndModal(mCancelClicked ? wxID_CANCEL : wxID_OK); EndModal(mCancelClicked ? wxID_CANCEL : wxID_OK);
} }
///////////////////////////////////////////////////////////////////////////////
//
// VSTEffectSettingsDialog
//
///////////////////////////////////////////////////////////////////////////////
class VSTEffectSettingsDialog:public wxDialog
{
public:
VSTEffectSettingsDialog(wxWindow * parent);
virtual ~VSTEffectSettingsDialog();
void PopulateOrExchange(ShuttleGui & S);
bool Validate();
private:
int mBufferSize;
};
VSTEffectSettingsDialog::VSTEffectSettingsDialog(wxWindow * parent)
: wxDialog(parent, wxID_ANY, wxString(_("VST Effect Settings")))
{
gPrefs->Read(wxT("/VST/BufferSize"), &mBufferSize, 8192);
ShuttleGui S(this, eIsCreatingFromPrefs);
PopulateOrExchange(S);
}
VSTEffectSettingsDialog::~VSTEffectSettingsDialog()
{
}
void VSTEffectSettingsDialog::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(5);
S.StartHorizontalLay(wxEXPAND, 1);
{
S.StartVerticalLay(false);
{
S.StartStatic(_("Buffer Specification"));
{
wxIntegerValidator<int> vld(&mBufferSize);
vld.SetRange(8, 1048576);
S.AddVariableText(wxString() +
_("The buffer size controls the number of samples sent to the effect ") +
_("on each iteration. Smaller values will cause slower processing and ") +
_("some effects require 8192 samples or less to work properly. However ") +
_("most effects can accept large buffers and using them will greatly ") +
_("reduce processing time."))->Wrap(650);
S.StartHorizontalLay(wxALIGN_LEFT);
{
wxTextCtrl *t;
t = S.TieNumericTextBox(_("Buffer Size (8 to 1048576 samples)"),
wxT("/VST/BufferSize"),
wxT(""), 12);
t->SetMinSize(wxSize(100, -1));
t->SetValidator(vld);
}
S.EndHorizontalLay();
}
S.EndStatic();
S.StartStatic(_("Buffer Delay Compensation"));
{
S.AddVariableText(wxString() +
_("As part of their processing, some VST effects must delay returning ") +
_("audio to Audacity. When not compensating for this delay, you will ") +
_("notice that bits of silence have been inserted into the audio. ") +
_("Enabling this setting will provide that compensation, but it may ") +
_("not work for all VST effects."))->Wrap(650);
S.StartHorizontalLay(wxALIGN_LEFT);
{
S.TieCheckBox(_("Enable compensation"), wxT("/VST/UseBufferDelay"), true);
}
S.EndHorizontalLay();
}
S.EndStatic();
S.StartStatic(_("Presentation Method"));
{
S.AddVariableText(wxString() +
_("Most VST effects provide a graphical interface for setting the ") +
_("parameter values. However, a basic text only method is also ") +
_("available."))->Wrap(650);
S.TieCheckBox(_("Enable graphical interface"), wxT("/VST/GUI"), true);
}
S.EndStatic();
S.StartStatic(_("Effect Refresh"));
{
S.AddVariableText(wxString() +
_("To improve Audacity startup, a search for VST effects is performed ") +
_("once and relevent information is recorded. When you add VST effects ") +
_("to your system, you need to tell Audacity to rescan so the new ") +
_("information can be recorded."))->Wrap(650);
S.TieCheckBox(_("Rescan effects on next launch"), wxT("/VST/Rescan"), false);
}
S.EndStatic();
}
S.EndVerticalLay();
}
S.EndHorizontalLay();
S.AddStandardButtons();
Layout();
Fit();
Center();
}
bool VSTEffectSettingsDialog::Validate()
{
ShuttleGui S(this, eIsSavingToPrefs);
PopulateOrExchange(S);
return true;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
@ -731,6 +855,7 @@ class VSTEffectDialog:public wxDialog, XMLTagHandler
void OnProgramText(wxCommandEvent & evt); void OnProgramText(wxCommandEvent & evt);
void OnLoad(wxCommandEvent & evt); void OnLoad(wxCommandEvent & evt);
void OnSave(wxCommandEvent & evt); void OnSave(wxCommandEvent & evt);
void OnSettings(wxCommandEvent & evt);
void OnSlider(wxCommandEvent &event); void OnSlider(wxCommandEvent &event);
@ -780,7 +905,8 @@ enum
ID_VST_PROGRAM = 11000, ID_VST_PROGRAM = 11000,
ID_VST_LOAD, ID_VST_LOAD,
ID_VST_SAVE, ID_VST_SAVE,
ID_VST_SLIDERS ID_VST_SLIDERS,
ID_VST_SETTINGS
}; };
BEGIN_EVENT_TABLE(VSTEffectDialog, wxDialog) BEGIN_EVENT_TABLE(VSTEffectDialog, wxDialog)
@ -793,6 +919,7 @@ BEGIN_EVENT_TABLE(VSTEffectDialog, wxDialog)
EVT_TEXT(ID_VST_PROGRAM, VSTEffectDialog::OnProgramText) EVT_TEXT(ID_VST_PROGRAM, VSTEffectDialog::OnProgramText)
EVT_BUTTON(ID_VST_LOAD, VSTEffectDialog::OnLoad) EVT_BUTTON(ID_VST_LOAD, VSTEffectDialog::OnLoad)
EVT_BUTTON(ID_VST_SAVE, VSTEffectDialog::OnSave) EVT_BUTTON(ID_VST_SAVE, VSTEffectDialog::OnSave)
EVT_BUTTON(ID_VST_SETTINGS, VSTEffectDialog::OnSettings)
EVT_SLIDER(wxID_ANY, VSTEffectDialog::OnSlider) EVT_SLIDER(wxID_ANY, VSTEffectDialog::OnSlider)
END_EVENT_TABLE() END_EVENT_TABLE()
@ -926,7 +1053,7 @@ void VSTEffectDialog::BuildFancy()
wxBoxSizer *hs = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *hs = new wxBoxSizer(wxHORIZONTAL);
wxSizerItem *si; wxSizerItem *si;
vs->Add(BuildProgramBar(), 0, wxCENTER); vs->Add(BuildProgramBar(), 0, wxCENTER | wxEXPAND);
si = hs->Add(rect->right - rect->left, rect->bottom - rect->top); si = hs->Add(rect->right - rect->left, rect->bottom - rect->top);
vs->Add(hs, 0, wxCENTER); vs->Add(hs, 0, wxCENTER);
@ -971,7 +1098,7 @@ void VSTEffectDialog::BuildPlain()
mLabels = new wxStaticText *[mAEffect->numParams]; mLabels = new wxStaticText *[mAEffect->numParams];
wxBoxSizer *vSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer *vSizer = new wxBoxSizer(wxVERTICAL);
vSizer->Add(BuildProgramBar(), 0, wxALIGN_CENTER); vSizer->Add(BuildProgramBar(), 0, wxALIGN_CENTER | wxEXPAND);
wxScrolledWindow *sw = new wxScrolledWindow(this, wxScrolledWindow *sw = new wxScrolledWindow(this,
wxID_ANY, wxID_ANY,
@ -1101,6 +1228,11 @@ wxSizer *VSTEffectDialog::BuildProgramBar()
bt = new wxButton(this, ID_VST_SAVE, _("Save")); bt = new wxButton(this, ID_VST_SAVE, _("Save"));
hs->Add(bt, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); hs->Add(bt, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
hs->AddStretchSpacer();
bt = new wxButton(this, ID_VST_SETTINGS, _("Settings"));
hs->Add(bt, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5);
return hs; return hs;
} }
@ -1298,6 +1430,12 @@ void VSTEffectDialog::OnSave(wxCommandEvent & WXUNUSED(event))
xmlFile.Close(); xmlFile.Close();
} }
void VSTEffectDialog::OnSettings(wxCommandEvent & WXUNUSED(event))
{
VSTEffectSettingsDialog dlg(this);
dlg.ShowModal();
}
void VSTEffectDialog::OnClose(wxCloseEvent & WXUNUSED(event)) void VSTEffectDialog::OnClose(wxCloseEvent & WXUNUSED(event))
{ {
EndModal(false); EndModal(false);
@ -1663,10 +1801,10 @@ int VSTEffectDialog::b64decode(wxString in, void *out)
typedef AEffect *(*vstPluginMain)(audioMasterCallback audioMaster); typedef AEffect *(*vstPluginMain)(audioMasterCallback audioMaster);
static long int audioMaster(AEffect * effect, static intptr_t audioMaster(AEffect * effect,
long int opcode, int32_t opcode,
long int index, int32_t index,
long int value, intptr_t value,
void * ptr, void * ptr,
float opt) float opt)
{ {
@ -1712,6 +1850,14 @@ static long int audioMaster(AEffect * effect,
} }
break; break;
// Inputs, outputs, or initial delay has changed...all we care about is initial delay.
case audioMasterIOChanged:
if (vst) {
vst->SetBufferDelay(effect->initialDelay);
return 0;
}
break;
// Ignore these // Ignore these
case audioMasterBeginEdit: case audioMasterBeginEdit:
case audioMasterEndEdit: case audioMasterEndEdit:
@ -1722,6 +1868,7 @@ static long int audioMaster(AEffect * effect,
return 0; return 0;
case audioMasterCanDo: case audioMasterCanDo:
wxLogDebug(wxT("VST canDo: %s\n"), wxString::FromAscii((char *)ptr).c_str());
return 0; return 0;
} }
@ -1872,6 +2019,32 @@ bool VSTEffect::Init()
return true; return true;
} }
//
// Some history...
//
// Before we ran into the Antress plugin problem with buffer size limitations,
// (see below) we just had a plain old effect loop...get the input samples, pass
// them to the effect, save the output samples.
//
// But, the hack I put in to limit the buffer size to only 8k (normally 512k or so)
// severely impacted performance. So, Michael C. added some intermediate buffering
// that sped things up quite a bit and this is how things have worked for quite a
// while. It still didn't get the performance back to the pre-hack stage, but it
// was a definite benefit.
//
// History over...
//
// I've recently (May 2014) tried newer versions of the Antress effects and they
// no longer seem to have a problem with buffer size. So, I've made a bit of a
// compromise...I've made the buffer size user configurable. Should have done this
// from the beginning. I've left the default 8k, just in case, but now the user
// can set the buffering based on their specific setup and needs.
//
// And at the same time I added buffer delay compensation, which allows Audacity
// to account for latency introduced by some effects. This is based on information
// provided by the effect, so it will not work with all effects since they don't
// allow provide the information (kn0ck0ut is one).
//
bool VSTEffect::PromptUser() bool VSTEffect::PromptUser()
{ {
VSTEffectDialog dlog(mParent, mName, this, mAEffect); VSTEffectDialog dlog(mParent, mName, this, mAEffect);
@ -1889,6 +2062,21 @@ bool VSTEffect::Process()
CopyInputTracks(); CopyInputTracks();
bool bGoodResult = true; bool bGoodResult = true;
// Some VST effects (Antress Modern is an example), do not like
// overly large block sizes. Unfortunately, I have not found a
// way to determine if the effect has a maximum it will support,
// so just limit to small value for now. This will increase
// processing time and, it's a shame, because most plugins seem
// to be able to handle much larger sizes.
//
// NOTE: This no longer seems to apply to more recent versions
// of Antress plugins, but leaving comment and 8192 default
// just in case.
gPrefs->Read(wxT("/VST/BufferSize"), &mBufferSize, 8192);
gPrefs->Read(wxT("/VST/UseBufferDelay"), &mUseBufferDelay, true);
mBufferDelay = 0;
mInBuffer = NULL; mInBuffer = NULL;
mOutBuffer = NULL; mOutBuffer = NULL;
@ -1918,14 +2106,10 @@ bool VSTEffect::Process()
if (mBlockSize == 0) { if (mBlockSize == 0) {
mBlockSize = mWTBlockSize = left->GetMaxBlockSize() * 2; mBlockSize = mWTBlockSize = left->GetMaxBlockSize() * 2;
// Some VST effects (Antress Modern is an example), do not like // Limit the buffer size to the user specified value since they may
// overly large block sizes. Unfortunately, I have not found a // have wanted a smaller value for a reason.
// way to determine if the effect has a maximum it will support, if (mBlockSize > mBufferSize) {
// so just limit to small value for now. This will increase mBlockSize = mBufferSize;
// processing time and, it's a shame, because most plugins seem
// to be able to handle much larger sizes.
if (mBlockSize > 8192) { // The Antress limit
mBlockSize = 8192;
} }
mInBuffer = new float *[mInputs]; mInBuffer = new float *[mInputs];
@ -2006,7 +2190,35 @@ bool VSTEffect::ProcessStereo(int count,
// Tell effect we're starting to process // Tell effect we're starting to process
callDispatcher(effStartProcess, 0, 0, NULL, 0.0); callDispatcher(effStartProcess, 0, 0, NULL, 0.0);
// Actually perform the effect here // Get the initial latency
SetBufferDelay(mAEffect->initialDelay);
// LLL:
//
// Some explanation to what this mess is all about.
// (see history above)
//
// For each input block of samples, we pass it to the VST effect along with a
// variable output location. This output location is simply a pointer into a
// much larger buffer. This reduces the number of calls required to add the
// samples to the output track which was Michael's speed up mentioned above.
//
// The buffer delay compensation adds even more complexitity...
//
// Upon return from the effect, the output samples are "moved to the left" by
// the number of samples in the current delay setting, effectively removing the
// delay introduced by the effect.
//
// At the same time the total number of delayed samples are gathered and when the
// there is no further input data to process, the loop continues to call the
// effect with an empty input buffer until the effect has had a chance to
// return all of the remaining delayed samples.
//
// Please note, that this process has next to no documetation on how it should
// work, so a lot of this was from trial and error. It appears to be correct
// though since it has worked with every plugin I've found that adds latency,
// with the exception of kn0ck0ut. I'm sure there are other effects out there
// that add latency but do not provide the delay information, so be wary. :-)
sampleCount originalLen = len; sampleCount originalLen = len;
sampleCount ls = lstart; sampleCount ls = lstart;
sampleCount rs = rstart; sampleCount rs = rstart;
@ -2014,24 +2226,87 @@ bool VSTEffect::ProcessStereo(int count,
sampleCount outrs = rstart; sampleCount outrs = rstart;
sampleCount outBufferCursor = 0; sampleCount outBufferCursor = 0;
float **outBufSegment = new float *[mOutputs]; float **outBufSegment = new float *[mOutputs];
while (len) { sampleCount delay = 0;
int block = mBlockSize; sampleCount delayed = 0;
if (block > len) { bool cleared = false;
block = len;
// Call the effect until we run out of input or delayed samples
while (len || delayed) {
sampleCount block = mBlockSize;
// As long as we have input samples, use those
if (len) {
// At the end if we don't have enough left for a whole block
if (block > len) {
block = len;
}
// Get the samples into our buffer
left->Get((samplePtr)mInBuffer[0], floatSample, ls, block);
if (right) {
right->Get((samplePtr)mInBuffer[1], floatSample, rs, block);
}
}
// We've reached the end of the input samples, so start processing
// delayed ones if there are any
else if (delayed) {
// At the end if we don't have enough left for a whole block
if (block > delayed) {
block = delayed;
}
// Clear the input buffer so that we only pass zeros to the effect.
if (!cleared) {
for (int i = 1; i < mInputs; i++) {
for (int j = 0; j < mBlockSize; j++) {
mInBuffer[i][j] = 0.0;
}
}
cleared = true;
}
} }
left->Get((samplePtr)mInBuffer[0], floatSample, ls, block); // Set current output pointer
if (right) { for (int i = 0; i < mOutputs; i++) {
right->Get((samplePtr)mInBuffer[1], floatSample, rs, block); outBufSegment[i] = mOutBuffer[i] + outBufferCursor;
} }
for (int i = 0; i < mOutputs; i++) // Go let the effect moleste the samples
outBufSegment[i] = mOutBuffer[i ] + outBufferCursor;
callProcessReplacing(mInBuffer, outBufSegment, block); callProcessReplacing(mInBuffer, outBufSegment, block);
outBufferCursor += block;
//Process 2 audacity blockfiles per WaveTrack::Set independently of mBlockSize // Get the current number of delayed samples and accumulate
//because it is extremely slow to do multiple Set()s per blockfile due to Undo History delay += mBufferDelay;
//If we do more optimization we should probably align the Sets to blockfile boundries. delayed += mBufferDelay;
// Reset...the effect will set this again if it has a further
// need to delay samples...some effects only set the value once
// at the start of processing.
mBufferDelay = 0;
// If the effect has delayed the output by more samples than our
// current block size, then we leave the output pointers where they
// are. This will effectively remove those delayed samples from the
// output buffer.
if (delay >= block) {
delay -= block;
}
// We have some delayed samples, at the beginning of the output samples,
// so overlay them by shifting the remaining output samples.
else if (delay > 0) {
sampleCount oblock = block - delay;
memmove(outBufSegment[0], outBufSegment[0] + delay, SAMPLE_SIZE(floatSample) * oblock);
memmove(outBufSegment[1], outBufSegment[1] + delay, SAMPLE_SIZE(floatSample) * oblock);
delay = 0;
outBufferCursor += oblock;
}
// no delay, just bump to the new output location
else {
outBufferCursor += block;
}
// Process 2 audacity blockfiles per WaveTrack::Set independently of mBlockSize
// because it is extremely slow to do multiple Set()s per blockfile due to Undo History
// If we do more optimization we should probably align the Sets to blockfile boundries.
if (outBufferCursor >= mWTBlockSize) { if (outBufferCursor >= mWTBlockSize) {
left->Set((samplePtr)mOutBuffer[0], floatSample, outls, mWTBlockSize); left->Set((samplePtr)mOutBuffer[0], floatSample, outls, mWTBlockSize);
if (right) { if (right) {
@ -2047,7 +2322,19 @@ bool VSTEffect::ProcessStereo(int count,
outrs += mWTBlockSize; outrs += mWTBlockSize;
} }
len -= block; // Still processing input samples
if (len) {
len -= block;
}
// Or maybe we're working on delayed samples
else if (delayed) {
delayed -= block;
}
// "ls" and "rs" serve as the input sample index for the left and
// right channels when processing the input samples. If we flip
// over to processing delayed samples, the simply become counters
// for the progress display.
ls += block; ls += block;
rs += block; rs += block;
mTimeInfo.samplePos += ((double) block / mTimeInfo.sampleRate); mTimeInfo.samplePos += ((double) block / mTimeInfo.sampleRate);
@ -2066,7 +2353,7 @@ bool VSTEffect::ProcessStereo(int count,
} }
} }
//finish taking the remainder. // Finish taking the remainder
if (outBufferCursor) { if (outBufferCursor) {
left->Set((samplePtr)mOutBuffer[0], floatSample, outls, outBufferCursor); left->Set((samplePtr)mOutBuffer[0], floatSample, outls, outBufferCursor);
if (right) { if (right) {
@ -2467,6 +2754,14 @@ VstTimeInfo *VSTEffect::GetTimeInfo()
return &mTimeInfo; return &mTimeInfo;
} }
void VSTEffect::SetBufferDelay(int samples)
{
// We do not support negative delay
if (samples >= 0 && mUseBufferDelay) {
mBufferDelay = samples;
}
}
wxString VSTEffect::GetString(int opcode, int index) wxString VSTEffect::GetString(int opcode, int index)
{ {
char buf[256]; char buf[256];

View File

@ -72,12 +72,11 @@ class VSTEffect:public Effect
static int ShowPluginListDialog( const wxArrayString & files ); static int ShowPluginListDialog( const wxArrayString & files );
static void ShowProgressDialog( const wxString & longest, const wxArrayString & files ); static void ShowProgressDialog( const wxString & longest, const wxArrayString & files );
// Utility methods // Utility methods
int GetChannels(); int GetChannels();
VstTimeInfo *GetTimeInfo(); VstTimeInfo *GetTimeInfo();
void SetBufferDelay(int samples);
wxString GetString(int opcode, int index = 0); wxString GetString(int opcode, int index = 0);
void SetString(int opcode, const wxString & str, int index = 0); void SetString(int opcode, const wxString & str, int index = 0);
@ -113,6 +112,11 @@ class VSTEffect:public Effect
VstTimeInfo mTimeInfo; VstTimeInfo mTimeInfo;
bool mUseBufferDelay;
int mBufferDelay;
int mBufferSize;
sampleCount mBlockSize; sampleCount mBlockSize;
sampleCount mWTBlockSize; sampleCount mWTBlockSize;
float **mInBuffer; float **mInBuffer;

View File

@ -118,7 +118,7 @@ const int effGetVendorString = 47;
const int effGetProductString = 48; const int effGetProductString = 48;
const int effGetVendorVersion = 49; const int effGetVendorVersion = 49;
const int effCanDo = 51; // currently unused const int effCanDo = 51; // currently unused
// The next one was gleaned from http://asseca.com/vst-24-specs/efIdle.html // The next one was gleaned from http://www.asseca.org/vst-24-specs/efIdle.html
const int effIdle = 53; const int effIdle = 53;
const int effGetVstVersion = 58; // currently unused const int effGetVstVersion = 58; // currently unused
// The next two were gleaned from http://www.kvraudio.com/forum/printview.php?t=143587&start=0 // The next two were gleaned from http://www.kvraudio.com/forum/printview.php?t=143587&start=0
@ -128,13 +128,22 @@ const int effStopProcess = 72;
const int kEffectMagic = CCONST( 'V', 's', 't', 'P' ); const int kEffectMagic = CCONST( 'V', 's', 't', 'P' );
const int kVstLangEnglish = 1; const int kVstLangEnglish = 1;
const int kVstMidiType = 1; const int kVstMidiType = 1;
const int kVstParameterUsesFloatStep = 1 << 2;
const int kVstNanosValid = 1 << 8; const int kVstNanosValid = 1 << 8;
const int kVstPpqPosValid = 1 << 9;
const int kVstTempoValid = 1 << 10; const int kVstTempoValid = 1 << 10;
const int kVstBarsValid = 1 << 11;
const int kVstCyclePosValid = 1 << 12;
const int kVstTimeSigValid = 1 << 13;
const int kVstSmpteValid = 1 << 14; // from Ardour
const int kVstClockValid = 1 << 15; // from Ardour
const int kVstTransportPlaying = 1 << 1; const int kVstTransportPlaying = 1 << 1;
const int kVstTransportCycleActive = 1 << 2;
const int kVstTransportChanged = 1;
class remoteVstPlugin; class RemoteVstPlugin;
class VstMidiEvent class VstMidiEvent
@ -183,9 +192,9 @@ public:
// 00 // 00
int numEvents; int numEvents;
// 04 // 04
int reserved; void *reserved;
// 08 // 08
VstEvent * events; VstEvent* events[1];
} ; } ;
@ -196,7 +205,7 @@ public:
class VstParameterProperties class VstParameterProperties
{ {
public: public:
float stepFloat; /* float stepFloat;
char label[64]; char label[64];
int flags; int flags;
int minInteger; int minInteger;
@ -205,7 +214,24 @@ public:
char shortLabel[8]; char shortLabel[8];
int category; int category;
char categoryLabel[24]; char categoryLabel[24];
char empty[128]; char empty[128];*/
float stepFloat;
float smallStepFloat;
float largeStepFloat;
char label[64];
unsigned int flags;
unsigned int minInteger;
unsigned int maxInteger;
unsigned int stepInteger;
unsigned int largeStepInteger;
char shortLabel[8];
unsigned short displayIndex;
unsigned short category;
unsigned short numParametersInCategory;
unsigned short reserved;
char categoryLabel[24];
char future[16];
} ; } ;
@ -219,7 +245,7 @@ public:
// 00-03 // 00-03
int magic; int magic;
// dispatcher 04-07 // dispatcher 04-07
int (* dispatcher)( AEffect * , int , int , int , void * , float ); intptr_t (* dispatcher)( AEffect * , int , int , intptr_t, void * , float );
// process, quite sure 08-0b // process, quite sure 08-0b
void (* process)( AEffect * , float * * , float * * , int ); void (* process)( AEffect * , float * * , float * * , int );
// setParameter 0c-0f // setParameter 0c-0f
@ -237,15 +263,18 @@ public:
// flags 24-27 // flags 24-27
int flags; int flags;
// Fill somewhere 28-2b // Fill somewhere 28-2b
void * user; void * ptr1;
// Zeroes 2c-2f 30-33 34-37 38-3b void * ptr2;
char empty3[4 + 4 + 4 + 4]; int initialDelay;
// Zeroes 34-37 38-3b
int empty3a;
int empty3b;
// 1.0f 3c-3f // 1.0f 3c-3f
float unkown_float; float unkown_float;
// An object? pointer 40-43 // An object? pointer 40-43
char empty4[4]; void *ptr3;
// Zeroes 44-47 // Zeroes 44-47
char empty5[4]; void *user;
// Id 48-4b // Id 48-4b
int32_t uniqueID; int32_t uniqueID;
// Don't know 4c-4f // Don't know 4c-4f
@ -256,6 +285,8 @@ public:
} ; } ;
class VstTimeInfo class VstTimeInfo
{ {
public: public:
@ -265,12 +296,16 @@ public:
double sampleRate; double sampleRate;
// 10 // 10
double nanoSeconds; double nanoSeconds;
// unconfirmed 18 // 18
char empty1[8]; double ppqPos;
// 20? // 20?
double tempo; double tempo;
// unconfirmed 28 30 38 // 28
char empty2[8 + 8 + 8]; double barStartPos;
// 30?
double cycleStartPos;
// 38?
double cycleEndPos;
// 40? // 40?
int timeSigNumerator; int timeSigNumerator;
// 44? // 44?
@ -284,13 +319,20 @@ public:
typedef intptr_t (* audioMasterCallback)( AEffect * , int32_t, int32_t, intptr_t, void * , float );
typedef long int (* audioMasterCallback)( AEffect * , long int , long int ,
long int , void * , float );
// we don't use it, may be noise
#define VSTCALLBACK
// from http://www.asseca.org/vst-24-specs/efGetParameterProperties.html
enum VstParameterFlags
{
kVstParameterIsSwitch = 1 << 0, // parameter is a switch (on/off)
kVstParameterUsesIntegerMinMax = 1 << 1, // minInteger, maxInteger valid
kVstParameterUsesFloatStep = 1 << 2, // stepFloat, smallStepFloat, largeStepFloat valid
kVstParameterUsesIntStep = 1 << 3, // stepInteger, largeStepInteger valid
kVstParameterSupportsDisplayIndex = 1 << 4, // displayIndex valid
kVstParameterSupportsDisplayCategory = 1 << 5, // category, etc. valid
kVstParameterCanRamp = 1 << 6 // set if parameter value can ramp up/down
};
#endif #endif