1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-11-08 22:23:59 +01:00

Cleanup chunk setting and preset saving/loading

When looking into the +morphfilter issue, I noticed that
I wasn't consistently handling preset chunks.  While I
didn't have any effects complaining about it, some of it
was (near as I can deduce...this stuff isn't well documented)
probably wrong.

So, I cleaned it all up and in the process added more validity
checking when loading presets for all 3 preset formats.

Incidentially, the +morphfilter still crashes Audacity...but
it also crashes Cubase, so we're in good company.  :-)  I've
sent an email to the author to see if I'm setting the chunks
correctly or he has a known issue.
This commit is contained in:
lllucius
2014-12-10 05:44:59 +00:00
parent 4b904f5eb2
commit d01a28be03
3 changed files with 186 additions and 56 deletions

View File

@@ -1898,19 +1898,23 @@ bool VSTEffect::RealtimeAddProcessor(int numChannels, float sampleRate)
{
void *chunk = NULL;
clen = (int) callDispatcher(effGetChunk, 1, 0, &chunk, 0.0);
clen = (int) callDispatcher(effGetChunk, 0, 0, &chunk, 0.0);
if (clen != 0)
{
slave->callDispatcher(effSetChunk, 1, clen, chunk, 0.0);
slave->callSetChunk(false, clen, chunk);
}
}
if (clen == 0)
{
callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
for (int i = 0; i < mAEffect->numParams; i++)
{
slave->callSetParameter(i, callGetParameter(i));
}
callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
}
return slave->RealtimeInitialize();
@@ -2019,6 +2023,7 @@ bool VSTEffect::GetAutomationParameters(EffectAutomationParameters & parms)
bool VSTEffect::SetAutomationParameters(EffectAutomationParameters & parms)
{
callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
for (int i = 0; i < mAEffect->numParams; i++)
{
wxString name = GetString(effGetParamName, i);
@@ -2035,6 +2040,7 @@ bool VSTEffect::SetAutomationParameters(EffectAutomationParameters & parms)
callSetParameter(i, d);
}
callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
return true;
}
@@ -2621,6 +2627,18 @@ void VSTEffect::LoadParameters(const wxString & group)
{
wxString value;
VstPatchChunkInfo info = {1, mAEffect->uniqueID, mAEffect->version, mAEffect->numParams};
mHost->GetPrivateConfig(group, wxT("UniqueID"), info.pluginUniqueID, info.pluginUniqueID);
mHost->GetPrivateConfig(group, wxT("Version"), info.pluginVersion, info.pluginVersion);
mHost->GetPrivateConfig(group, wxT("Elements"), info.numElements, info.numElements);
if ((info.pluginUniqueID != mAEffect->uniqueID) ||
(info.pluginVersion != mAEffect->version) ||
(info.numElements != mAEffect->numParams))
{
return;
}
if (mHost->GetPrivateConfig(group, wxT("Chunk"), value, wxEmptyString))
{
char *buf = new char[value.length() / 4 * 3];
@@ -2628,17 +2646,19 @@ void VSTEffect::LoadParameters(const wxString & group)
int len = VSTEffect::b64decode(value, buf);
if (len)
{
callDispatcher(effSetChunk, 1, len, buf, 0.0);
for (size_t i = 0, cnt = mSlaves.GetCount(); i < cnt; i++)
{
mSlaves[i]->callDispatcher(effSetChunk, 1, len, buf, 0.0);
}
callSetChunk(true, len, buf, &info);
}
delete [] buf;
return;
}
if (callDispatcher(effBeginLoadProgram, 0, 0, &info, 0.0) == -1)
{
return;
}
callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
if (mHost->GetPrivateConfig(group, wxT("Value"), value, wxEmptyString))
{
size_t cnt = mSlaves.GetCount();
@@ -2659,10 +2679,15 @@ void VSTEffect::LoadParameters(const wxString & group)
}
}
}
callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
}
void VSTEffect::SaveParameters(const wxString & group)
{
mHost->SetPrivateConfig(group, wxT("UniqueID"), mAEffect->uniqueID);
mHost->SetPrivateConfig(group, wxT("Version"), mAEffect->version);
mHost->SetPrivateConfig(group, wxT("Elements"), mAEffect->numParams);
if (mAEffect->flags & effFlagsProgramChunks)
{
void *chunk = NULL;
@@ -2877,10 +2902,7 @@ void VSTEffect::callSetParameter(int index, float value)
for (size_t i = 0, cnt = mSlaves.GetCount(); i < cnt; i++)
{
if (mSlaves[i]->callDispatcher(effCanBeAutomated, 0, index, NULL, 0.0))
{
mSlaves[i]->callSetParameter(index, value);
}
mSlaves[i]->callSetParameter(index, value);
}
}
}
@@ -2898,6 +2920,48 @@ void VSTEffect::callSetProgram(int index)
callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
}
void VSTEffect::callSetChunk(bool isPgm, int len, void *buf)
{
VstPatchChunkInfo info;
memset(&info, 0, sizeof(info));
info.version = 1;
info.pluginUniqueID = mAEffect->uniqueID;
info.pluginVersion = mAEffect->version;
info.numElements = isPgm ? mAEffect->numParams : mAEffect->numPrograms;
callSetChunk(isPgm, len, buf, &info);
}
void VSTEffect::callSetChunk(bool isPgm, int len, void *buf, VstPatchChunkInfo *info)
{
if (isPgm)
{
// Ask the effect if this is an acceptable program
if (callDispatcher(effBeginLoadProgram, 0, 0, info, 0.0) == -1)
{
return;
}
}
else
{
// Ask the effect if this is an acceptable bank
if (callDispatcher(effBeginLoadBank, 0, 0, info, 0.0) == -1)
{
return;
}
}
callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
callDispatcher(effSetChunk, isPgm ? 1 : 0, len, buf, 0.0);
callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
for (size_t i = 0, cnt = mSlaves.GetCount(); i < cnt; i++)
{
mSlaves[i]->callSetChunk(isPgm, len, buf, info);
}
}
////////////////////////////////////////////////////////////////////////////////
// Base64 en/decoding
//
@@ -3418,13 +3482,13 @@ bool VSTEffect::LoadFXB(const wxFileName & fn)
// Most references to the data are via an "int" array
int32_t *iptr = (int32_t *) bptr;
// Verify that we have at least enough the header
// Verify that we have at least enough for the header
if (len < 156)
{
break;
}
// Verify that we probably have a FX file
// Verify that we probably have an FX file
if (wxINT32_SWAP_ON_LE(iptr[0]) != CCONST('C', 'c', 'n', 'K'))
{
break;
@@ -3439,22 +3503,28 @@ bool VSTEffect::LoadFXB(const wxFileName & fn)
break;
}
VstPatchChunkInfo info =
{
1,
wxINT32_SWAP_ON_LE(iptr[4]),
wxINT32_SWAP_ON_LE(iptr[5]),
wxINT32_SWAP_ON_LE(iptr[6])
};
// Ensure this program looks to belong to the current plugin
if (wxINT32_SWAP_ON_LE(iptr[4]) != mAEffect->uniqueID)
if ((info.pluginUniqueID != mAEffect->uniqueID) &&
(info.pluginVersion != mAEffect->version) &&
(info.numElements != mAEffect->numPrograms))
{
break;
}
// Get the number of programs
int numProgs = wxINT32_SWAP_ON_LE(iptr[6]);
if (numProgs != mAEffect->numPrograms)
{
break;
}
int numProgs = info.numElements;
// Get the current program index
int curProg = 0;
if (version == 2)
if (version >= 2)
{
curProg = wxINT32_SWAP_ON_LE(iptr[7]);
if (curProg < 0 || curProg >= numProgs)
@@ -3483,7 +3553,7 @@ bool VSTEffect::LoadFXB(const wxFileName & fn)
}
// Ask the effect if this is an acceptable bank
if (callDispatcher(effBeginLoadBank, 0, 0, &iptr, 0.0) == -1)
if (callDispatcher(effBeginLoadBank, 0, 0, &info, 0.0) == -1)
{
return false;
}
@@ -3521,14 +3591,8 @@ bool VSTEffect::LoadFXB(const wxFileName & fn)
break;
}
// Ask the effect if this is an acceptable bank
if (callDispatcher(effBeginLoadBank, 0, 0, &iptr, 0.0) == -1)
{
return false;
}
// Set the entire bank in one shot
callDispatcher(effSetChunk, 0, size, &iptr[40], 0.0);
callSetChunk(false, size, &iptr[40], &info);
// Success
ret = true;
@@ -3540,7 +3604,7 @@ bool VSTEffect::LoadFXB(const wxFileName & fn)
}
// Set the active program
if (ret && version == 2)
if (ret && version >= 2)
{
callSetProgram(curProg);
}
@@ -3633,18 +3697,24 @@ bool VSTEffect::LoadFXProgram(unsigned char **bptr, ssize_t & len, int index, bo
}
#endif
VstPatchChunkInfo info =
{
1,
wxINT32_SWAP_ON_LE(iptr[4]),
wxINT32_SWAP_ON_LE(iptr[5]),
wxINT32_SWAP_ON_LE(iptr[6])
};
// Ensure this program looks to belong to the current plugin
if (wxINT32_SWAP_ON_LE(iptr[4]) != mAEffect->uniqueID)
if ((info.pluginUniqueID != mAEffect->uniqueID) &&
(info.pluginVersion != mAEffect->version) &&
(info.numElements != mAEffect->numParams))
{
return false;
}
// Get the number of parameters
int numParams = wxINT32_SWAP_ON_LE(iptr[6]);
if (numParams != mAEffect->numParams)
{
return false;
}
int numParams = info.numElements;
// At this point, we have to have enough to include the program name as well
if (len < 56)
@@ -3682,7 +3752,7 @@ bool VSTEffect::LoadFXProgram(unsigned char **bptr, ssize_t & len, int index, bo
if (!dryrun)
{
// Ask the effect if this is an acceptable program
if (callDispatcher(effBeginLoadProgram, 0, 0, &iptr, 0.0) == -1)
if (callDispatcher(effBeginLoadProgram, 0, 0, &info, 0.0) == -1)
{
return false;
}
@@ -3731,15 +3801,7 @@ bool VSTEffect::LoadFXProgram(unsigned char **bptr, ssize_t & len, int index, bo
// Set the entire program in one shot
if (!dryrun)
{
// Ask the effect if this is an acceptable program
if (callDispatcher(effBeginLoadProgram, 0, 0, &iptr, 0.0) == -1)
{
return false;
}
callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
callDispatcher(effSetChunk, 1, size, &iptr[15], 0.0);
callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
callSetChunk(true, size, &iptr[15], &info);
}
// Update in case we're loading an "FxBk" format bank file
@@ -3762,16 +3824,21 @@ bool VSTEffect::LoadFXProgram(unsigned char **bptr, ssize_t & len, int index, bo
bool VSTEffect::LoadXML(const wxFileName & fn)
{
// Tell the effect to prepare
callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
mInChunk = false;
mInSet = false;
// default to read as XML file
// Load the program
XMLFileReader reader;
bool ok = reader.Parse(this, fn.GetFullPath());
// Tell the effect we're done
callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
// Something went wrong with the file, clean up
if (mInSet)
{
callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
mInSet = false;
}
if (!ok)
{
@@ -3968,11 +4035,13 @@ void VSTEffect::SaveXML(const wxFileName & fn)
xmlFile.Open(fn.GetFullPath(), wxT("wb"));
xmlFile.StartTag(wxT("vstprogrampersistence"));
xmlFile.WriteAttr(wxT("version"), wxT("1"));
xmlFile.WriteAttr(wxT("version"), wxT("2"));
xmlFile.StartTag(wxT("effect"));
xmlFile.WriteAttr(wxT("name"), GetName());
xmlFile.WriteAttr(wxT("version"), callDispatcher(effGetVendorVersion, 0, 0, NULL, 0.0));
xmlFile.WriteAttr(wxT("uniqueID"), mAEffect->uniqueID);
xmlFile.WriteAttr(wxT("version"), mAEffect->version);
xmlFile.WriteAttr(wxT("numParams"), mAEffect->numParams);
xmlFile.StartTag(wxT("program"));
xmlFile.WriteAttr(wxT("name"), wxEmptyString); //mProgram->GetValue());
@@ -4038,11 +4107,15 @@ bool VSTEffect::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
if (wxStrcmp(attr, wxT("version")) == 0)
{
if (!XMLValueChecker::IsGoodInt(strValue))
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&mXMLVersion))
{
return false;
}
if (mXMLVersion < 1 || mXMLVersion > 2)
{
return false;
}
// Nothing to do with it for now
}
else
{
@@ -4055,6 +4128,8 @@ bool VSTEffect::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
if (wxStrcmp(tag, wxT("effect")) == 0)
{
mXMLInfo = {1, mAEffect->uniqueID, mAEffect->version, mAEffect->numParams};
while (*attrs)
{
const wxChar *attr = *attrs++;
@@ -4087,11 +4162,33 @@ bool VSTEffect::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
}
else if (wxStrcmp(attr, wxT("version")) == 0)
{
if (!XMLValueChecker::IsGoodInt(strValue))
long version;
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&version))
{
return false;
}
// Nothing to do with it for now
mXMLInfo.pluginVersion = (int) version;
}
else if (mXMLVersion > 1 && wxStrcmp(attr, wxT("uniqueID")) == 0)
{
long uniqueID;
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&uniqueID))
{
return false;
}
mXMLInfo.pluginUniqueID = (int) uniqueID;
}
else if (mXMLVersion > 1 && wxStrcmp(attr, wxT("numParams")) == 0)
{
long numParams;
if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&numParams))
{
return false;
}
mXMLInfo.numElements = (int) numParams;
}
else
{
@@ -4144,6 +4241,15 @@ bool VSTEffect::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
mInChunk = false;
if (callDispatcher(effBeginLoadProgram, 0, 0, &mXMLInfo, 0.0) == -1)
{
return false;
}
callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
mInSet = true;
return true;
}
@@ -4230,7 +4336,7 @@ void VSTEffect::HandleXMLEndTag(const wxChar *tag)
int len = VSTEffect::b64decode(mChunk, buf);
if (len)
{
callDispatcher(effSetChunk, 1, len, buf, 0.0);
callSetChunk(true, len, buf, &mXMLInfo);
}
delete [] buf;
@@ -4238,6 +4344,16 @@ void VSTEffect::HandleXMLEndTag(const wxChar *tag)
}
mInChunk = false;
}
if (wxStrcmp(tag, wxT("program")) == 0)
{
if (mInSet)
{
callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
mInSet = false;
}
}
}
void VSTEffect::HandleXMLContent(const wxString & content)

View File

@@ -245,6 +245,8 @@ private:
void callSetParameter(int index, float value);
float callGetParameter(int index);
void callSetProgram(int index);
void callSetChunk(bool isPgm, int len, void *buf);
void callSetChunk(bool isPgm, int len, void *buf, VstPatchChunkInfo *info);
private:
EffectHostInterface *mHost;
@@ -312,8 +314,11 @@ private:
wxStaticText **mDisplays;
wxStaticText **mLabels;
bool mInSet;
bool mInChunk;
wxString mChunk;
long mXMLVersion;
VstPatchChunkInfo mXMLInfo;
#if defined(__WXMAC__)
static pascal OSStatus OverlayEventHandler(EventHandlerCallRef handler, EventRef event, void *data);

View File

@@ -345,5 +345,14 @@ enum VstParameterFlags
kVstParameterCanRamp = 1 << 6 // set if parameter value can ramp up/down
};
// from http://www.asseca.org/vst-24-specs/efBeginLoadProgram.html
struct VstPatchChunkInfo
{
int32_t version; // Format Version (should be 1)
int32_t pluginUniqueID; // UniqueID of the plug-in
int32_t pluginVersion; // Plug-in Version
int32_t numElements; // Number of Programs (Bank) or Parameters (Program)
char future[48]; // Reserved for future use
};
#endif