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:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user