24#pragma comment(lib, "shlwapi")
30#include <wx/osx/core/private.h>
42 static_assert(
sizeof(float) ==
sizeof(uint32_t),
"Cannot reinterpret uint32_t to float since sizes are different.");
44 std::memcpy(&f, &x,
sizeof(
float));
50 static_assert(
sizeof(float) ==
sizeof(uint32_t),
"Cannot reinterpret float to uint32_t since sizes are different.");
53 std::memcpy(&x, &f,
sizeof(uint32_t));
73 return (intptr_t) 2400;
79 strcpy((
char *) ptr,
"Audacity Team");
83 strcpy((
char *) ptr,
"Audacity");
87 return (intptr_t) (AUDACITY_VERSION << 24 |
88 AUDACITY_RELEASE << 16 |
89 AUDACITY_REVISION << 8 |
167 char *s = (
char *) ptr;
168 if (strcmp(s,
"acceptIOChanges") == 0 ||
169 strcmp(s,
"sendVstTimeInfo") == 0 ||
170 strcmp(s,
"startStopProcess") == 0 ||
171 strcmp(s,
"shellCategory") == 0 ||
172 strcmp(s,
"sizeWindow") == 0)
177#if defined(VST_DEBUG)
178#if defined(__WXMSW__)
179 wxLogDebug(
wxT(
"VST canDo: %s"), wxString::FromAscii((
char *)ptr));
181 wxPrintf(
wxT(
"VST canDo: %s\n"), wxString::FromAscii((
char *)ptr));
210#if defined(VST_DEBUG)
211#if defined(__WXMSW__)
212 wxLogDebug(
wxT(
"vst: %p opcode: %d index: %d value: %p ptr: %p opt: %f user: %p"),
213 effect, (
int) opcode, (
int) index, (
void *) value, ptr, opt, vst);
215 wxPrintf(
wxT(
"vst: %p opcode: %d index: %d value: %p ptr: %p opt: %f user: %p\n"),
216 effect, (
int) opcode, (
int) index, (
void *) value, ptr, opt, vst);
223#if !defined(__WXMSW__)
224void VSTWrapper::ModuleDeleter::operator() (
void* p)
const
231#if defined(__WXMAC__)
245 auto result = std::make_unique<VSTMessage>(*
this);
247 result->mChunk.reserve(this->
mChunk.capacity());
259 assert(mParamsVec.size() == vstSrc.
mParamsVec.size());
261 for (
size_t i = 0; i < mParamsVec.size(); i++)
274 bool chunkWasAssigned =
false;
276 if ( ! vstSrc.
mChunk.empty() )
279 chunkWasAssigned =
true;
284 assert(mParamsVec.size() == vstSrc.
mParamsVec.size());
286 for (
size_t i = 0; i < mParamsVec.size(); i++)
288 if (chunkWasAssigned)
310 bool success =
false;
313 wxString realPath =
mPath.BeforeFirst(
wxT(
';'));
314 mPath.AfterFirst(
wxT(
';')).ToLong(&effectID);
320#if defined(__WXMAC__)
327 wxCFStringRef path(realPath);
330 BundleHandle bundleRef{ CFBundleCreate(kCFAllocatorDefault,
333 CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
334 path, kCFURLPOSIXPathStyle,
true)
345 Boolean good = CFURLGetFileSystemRepresentation(
347 CF_ptr<CFURLRef>{ CFBundleCopyExecutableURL(bundleRef.get()) }.get(),
348 true, exePath,
sizeof(exePath)
356 mModule.reset((
char*)dlopen((
char *) exePath, RTLD_NOW | RTLD_LOCAL));
364 if (pluginMain == NULL)
370 if (pluginMain == NULL)
385#elif defined(__WXMSW__)
391 auto lib = std::make_unique<wxDynamicLibrary>(realPath);
396 if (!lib->IsLoaded())
401 if (pluginMain == NULL)
404 if (pluginMain == NULL)
431#define RTLD_DEEPBIND 0
434 (
char*) dlopen((
const char *)wxString(realPath).ToUTF8(),
435 RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND)
443 pluginMain = (
vstPluginMain) dlsym(lib.get(),
"VSTPluginMain");
444 if (pluginMain == NULL)
447 if (pluginMain == NULL)
463 wxLogMessage(
wxT(
"VST plugin initialization failed\n"));
511 if (
mName.length() == 0)
516 if (
mName.length() == 0)
518 mName = wxFileName{realPath}.GetName();
587#if defined(__WXMAC__)
655 memset(buf, 0,
sizeof(buf));
660 outstr = wxString::FromUTF8(buf);
677 strcpy(buf,
str.Left(255).ToUTF8());
683 int index, intptr_t value,
void *ptr,
float opt)
692 int index, intptr_t value,
void *ptr,
float opt)
const
725 memset(&info, 0,
sizeof(info));
763 wxFFile f(
fn.GetFullPath(),
wxT(
"rb"));
775 XO(
"Unable to allocate memory when loading presets file."),
777 .
Caption(
XO(
"Error Loading VST Presets")));
780 unsigned char *bptr = data.get();
785 ssize_t len = f.Read((
void *) bptr, f.Length());
790 XO(
"Unable to read presets file."),
792 .
Caption(
XO(
"Error Loading VST Presets")));
797 int32_t *iptr = (int32_t *) bptr;
806 if (wxINT32_SWAP_ON_LE(iptr[0]) !=
CCONST(
'C',
'c',
'n',
'K'))
814 int version = wxINT32_SWAP_ON_LE(iptr[3]);
815 if (version != 1 && version != 2)
823 wxINT32_SWAP_ON_LE(iptr[4]),
824 wxINT32_SWAP_ON_LE(iptr[5]),
825 wxINT32_SWAP_ON_LE(iptr[6]),
844 curProg = wxINT32_SWAP_ON_LE(iptr[7]);
845 if (curProg < 0 || curProg >= numProgs)
852 if (wxINT32_SWAP_ON_LE(iptr[2]) ==
CCONST(
'F',
'x',
'B',
'k'))
858 unsigned char *tempPtr = bptr;
859 ssize_t tempLen = len;
862 for (
int i = 0; i < numProgs; i++)
877 for (
int i = 0; i < numProgs; i++)
883 else if (wxINT32_SWAP_ON_LE(iptr[2]) ==
CCONST(
'F',
'B',
'C',
'h'))
898 int size = wxINT32_SWAP_ON_LE(iptr[39]);
901 int proglen = 160 +
size;
922 if (ret && version >= 2)
936 wxFFile f(
fn.GetFullPath(),
wxT(
"rb"));
948 XO(
"Unable to allocate memory when loading presets file."),
950 .
Caption(
XO(
"Error Loading VST Presets")));
953 unsigned char *bptr = data.get();
958 ssize_t len = f.Read((
void *) bptr, f.Length());
963 XO(
"Unable to read presets file."),
965 .
Caption(
XO(
"Error Loading VST Presets")));
986 int32_t *iptr = (int32_t *) *bptr;
995 if (wxINT32_SWAP_ON_LE(iptr[0]) !=
CCONST(
'C',
'c',
'n',
'K'))
1003#if defined(IS_THIS_AN_FXP_ARTIFICAL_LIMITATION)
1004 int version = wxINT32_SWAP_ON_LE(iptr[3]);
1014 wxINT32_SWAP_ON_LE(iptr[4]),
1015 wxINT32_SWAP_ON_LE(iptr[5]),
1016 wxINT32_SWAP_ON_LE(iptr[6]),
1038 wxString progName(wxString::From8BitData((
char *)&iptr[7]));
1041 if (wxINT32_SWAP_ON_LE(iptr[2]) ==
CCONST(
'F',
'x',
'C',
'k'))
1044 int proglen = 56 + (numParams *
sizeof(float));
1053 for (
int i = 0; i < numParams; i++)
1055 uint32_t ival = wxUINT32_SWAP_ON_LE(iptr[14 + i]);
1057 if (val < 0.0 || val > 1.0)
1074 for (
int i = 0; i < numParams; i++)
1076 wxUint32 val = wxUINT32_SWAP_ON_LE(iptr[14 + i]);
1087 else if (wxINT32_SWAP_ON_LE(iptr[2]) ==
CCONST(
'F',
'P',
'C',
'h'))
1102 int size = wxINT32_SWAP_ON_LE(iptr[14]);
1105 int proglen = 60 +
size;
1145 bool ok = reader.
Parse(
this,
fn.GetFullPath());
1162 .
Caption(
XO(
"Error Loading VST Presets")));
1172 const wxString fullPath{
fn.GetFullPath()};
1173 wxFFile f(fullPath,
wxT(
"wb"));
1178 XO(
"Could not open file: \"%s\"").
Format( fullPath ),
1180 .
Caption(
XO(
"Error Saving VST Presets")));
1186 void *chunkPtr =
nullptr;
1194 subType =
CCONST(
'F',
'B',
'C',
'h');
1198 dataSize += 4 + chunkSize;
1202 subType =
CCONST(
'F',
'x',
'B',
'k');
1209 dataSize += buf.GetDataLen();
1212 tab[0] = wxINT32_SWAP_ON_LE(
CCONST(
'C',
'c',
'n',
'K'));
1213 tab[1] = wxINT32_SWAP_ON_LE(dataSize);
1214 tab[2] = wxINT32_SWAP_ON_LE(subType);
1215 tab[3] = wxINT32_SWAP_ON_LE(curProg >= 0 ? 2 : 1);
1219 tab[7] = wxINT32_SWAP_ON_LE(curProg >= 0 ? curProg : 0);
1221 f.Write(tab,
sizeof(tab));
1225 memset(padding, 0,
sizeof(padding));
1226 f.Write(padding,
sizeof(padding));
1232 wxInt32
size = wxINT32_SWAP_ON_LE(chunkSize);
1234 f.Write(chunkPtr, chunkSize);
1238 f.Write(buf.GetData(), buf.GetDataLen());
1247 XO(
"Error writing to file: \"%s\"").
Format( fullPath ),
1249 .
Caption(
XO(
"Error Saving VST Presets")));
1260 const wxString fullPath{
fn.GetFullPath() };
1261 wxFFile f(fullPath,
wxT(
"wb"));
1266 XO(
"Could not open file: \"%s\"").
Format( fullPath ),
1268 .
Caption(
XO(
"Error Saving VST Presets")));
1278 f.Write(buf.GetData(), buf.GetDataLen());
1283 XO(
"Error writing to file: \"%s\"").
Format( fullPath ),
1285 .
Caption(
XO(
"Error Saving VST Presets")));
1304 progName[27] =
'\0';
1305 chunkSize = strlen(progName);
1306 memset(&progName[chunkSize], 0,
sizeof(progName) - chunkSize);
1310 subType =
CCONST(
'F',
'P',
'C',
'h');
1314 dataSize += 4 + chunkSize;
1318 subType =
CCONST(
'F',
'x',
'C',
'k');
1323 tab[0] = wxINT32_SWAP_ON_LE(
CCONST(
'C',
'c',
'n',
'K'));
1324 tab[1] = wxINT32_SWAP_ON_LE(dataSize);
1325 tab[2] = wxINT32_SWAP_ON_LE(subType);
1326 tab[3] = wxINT32_SWAP_ON_LE(1);
1331 buf.AppendData(tab,
sizeof(tab));
1332 buf.AppendData(progName,
sizeof(progName));
1336 wxInt32
size = wxINT32_SWAP_ON_LE(chunkSize);
1337 buf.AppendData(&
size,
sizeof(
size));
1338 buf.AppendData(chunkPtr, chunkSize);
1346 buf.AppendData(&ival,
sizeof(ival));
1359 xmlFile.StartTag(
wxT(
"vstprogrampersistence"));
1360 xmlFile.WriteAttr(
wxT(
"version"),
wxT(
"2"));
1362 xmlFile.StartTag(
wxT(
"effect"));
1369 xmlFile.StartTag(
wxT(
"program"));
1370 xmlFile.WriteAttr(
wxT(
"name"), wxEmptyString);
1381 xmlFile.StartTag(
wxT(
"chunk"));
1383 xmlFile.EndTag(
wxT(
"chunk"));
1391 xmlFile.StartTag(
wxT(
"param"));
1393 xmlFile.WriteAttr(
wxT(
"index"), i);
1394 xmlFile.WriteAttr(
wxT(
"name"),
1396 xmlFile.WriteAttr(
wxT(
"value"),
1397 wxString::Format(
wxT(
"%f"),
1400 xmlFile.EndTag(
wxT(
"param"));
1404 xmlFile.EndTag(
wxT(
"program"));
1406 xmlFile.EndTag(
wxT(
"effect"));
1408 xmlFile.EndTag(
wxT(
"vstprogrampersistence"));
1415 if (tag ==
"vstprogrampersistence")
1417 for (
auto pair : attrs)
1419 auto attr = pair.first;
1420 auto value = pair.second;
1422 if (attr ==
"version")
1429 if (mXMLVersion < 1 || mXMLVersion > 2)
1443 if (tag ==
"effect")
1451 for (
auto pair : attrs)
1453 auto attr = pair.first;
1454 auto value = pair.second;
1458 wxString strValue = value.ToWString();
1463 auto msg =
XO(
"This parameter file was saved from %s. Continue?")
1464 .Format( strValue );
1469 .ButtonStyle(Button::YesNo));
1470 if (result == MessageBoxResult::No)
1474 else if (attr ==
"version")
1477 if (!value.TryGet(version))
1487 if (!value.TryGet(uniqueID))
1497 if (!value.TryGet(numParams))
1513 if (tag ==
"program")
1515 for (
auto pair : attrs)
1517 auto attr = pair.first;
1518 auto value = pair.second;
1522 const wxString strValue = value.ToWString();
1524 if (strValue.length() > 24)
1530 if (ndx == wxNOT_FOUND)
1562 for (
auto pair : attrs)
1564 auto attr = pair.first;
1565 auto value = pair.second;
1567 if (attr ==
"index")
1569 if (!value.TryGet(ndx))
1587 else if (attr ==
"value")
1589 if (!value.TryGet(val))
1594 if (val < 0.0 || val > 1.0)
1601 if (ndx == -1 || val == -1.0)
1639 if (tag ==
"program")
1654 mChunk += wxString(std::string(content)).Trim(
true).Trim(
false);
1660 if (tag ==
"vstprogrampersistence")
1665 if (tag ==
"effect")
1670 if (tag ==
"program")
1695 name.Printf(
wxT(
"parm_%d"), i);
1740 vstSettings.
mChunk.resize(0);
1744 void* chunk =
nullptr;
1746 if (clen > 0 && chunk) {
1747 vstSettings.
mChunk.resize(clen);
1748 memcpy(vstSettings.
mChunk.data(), chunk, clen);
1756 vstSettings.
mChunk.resize(0);
1776 auto &chunk = vstSettings.
mChunk;
1780 callSetChunk(
true, chunk.size(),
const_cast<char *
>(chunk.data()), &info);
1794 const auto itr = vstSettings.
mParamsMap.find(
pi.mName);
1797 const float& value = *(itr->second);
1799 if (value >= -1.0 && value <= 1.0)
1801 callSetParameter(pi.mID, value);
1818std::unique_ptr<EffectInstance::Message>
1828 auto &slot = paramVector[
pi.mID];
1829 const auto iter =
settings.mParamsMap.find(
pi.mName),
1832 slot = iter->second;
1837 return std::make_unique<VSTMessage>(
1838 settings.mChunk , std::move(paramVector));
@ Internal
Indicates internal failure from Audacity.
Toolkit-neutral facade for basic user interface services.
#define PLATFORM_MAX_PATH
static Settings & settings()
static uint32_t reinterpretAsUint32(float f)
AEffect *(* vstPluginMain)(audioMasterCallback audioMaster)
static float reinterpretAsFloat(uint32_t x)
std::vector< Attribute > AttributesList
const int effGetVendorVersion
const int effGetVstVersion
const int kVstLangEnglish
const int audioMasterGetVendorVersion
const int effCanBeAutomated
const int audioMasterGetCurrentProcessLevel
const int effGetProductString
intptr_t(* audioMasterCallback)(AEffect *, int32_t, int32_t, intptr_t, void *, float)
const int effFlagsProgramChunks
const int effGetParamName
const int effGetProgramNameIndexed
const int audioMasterNeedIdle
const int audioMasterGetProductString
const int effSetBlockSize
const int effSetProgramName
const int effGetVendorString
const int audioMasterWantMidi
const int audioMasterPinConnected
const int effFlagsIsSynth
const int audioMasterWillReplaceOrAccumulate
const int audioMasterUpdateDisplay
const int audioMasterGetTime
const int effGetEffectName
const int audioMasterEndEdit
const int audioMasterIdle
const int audioMasterIOChanged
const int effFlagsCanReplacing
const int effBeginSetProgram
const int effBeginLoadBank
#define CCONST(a, b, c, d)
const int audioMasterProcessEvents
const int effSetSampleRate
const int audioMasterCurrentId
const int audioMasterAutomate
const int effBeginLoadProgram
const int audioMasterVersion
const int audioMasterBeginEdit
const int audioMasterGetVendorString
const int audioMasterGetSampleRate
const int effFlagsHasEditor
const int effEndSetProgram
const int audioMasterGetLanguage
const int audioMasterSizeWindow
const int audioMasterCanDo
VST Effects class, conforming to VST layout.
void(* setParameter)(AEffect *, int, float)
intptr_t(* dispatcher)(AEffect *, int, int, intptr_t, void *, float)
float(* getParameter)(AEffect *, int)
This simplifies arrays of arrays, each array separately allocated with NEW[] But it might be better t...
static wxString NormalizeName(const wxString &name)
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Reads a file and passes the results through an XMLTagHandler.
const TranslatableString & GetErrorStr() const
bool Parse(XMLTagHandler *baseHandler, const FilePath &fname)
Wrapper to output XML data to files.
This class is an interface which should be implemented by classes which wish to be able to load and s...
STRINGS_API wxString Encode(const void *in, int len)
STRINGS_API int Decode(const wxString &in, void *out)
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
TranslatableString Message(unsigned trackCount)
const char * end(const char *str) noexcept
MessageBoxOptions && Caption(TranslatableString caption_) &&
std::vector< std::optional< double > > ParamVector
std::unique_ptr< Message > Clone() const override
void Merge(Message &&src) override
void Assign(Message &&src) override
std::vector< char > mChunk
std::vector< char > mChunk
std::unordered_map< wxString, std::optional< double > > mParamsMap
virtual void SizeWindow(int w, int h)
virtual void Automate(int index, float value)
void SaveFXP(const wxFileName &fn) const
bool LoadFXProgram(unsigned char **bptr, ssize_t &len, int index, bool dryrun)
int GetString(wxString &outstr, int opcode, int index=0) const
bool FetchSettings(VSTSettings &vst3Settings, bool doFetch=true) const
std::unique_ptr< wxDynamicLibrary > ModuleHandle
bool HandleXMLTag(const std::string_view &tag, const AttributesList &attrs) override
bool LoadXML(const wxFileName &fn)
bool StoreSettings(const VSTSettings &vst3settings) const
static intptr_t AudioMaster(AEffect *effect, int32_t opcode, int32_t index, intptr_t value, void *ptr, float opt)
void SetString(int opcode, const wxString &str, int index=0)
CF_ptr< CFBundleRef > BundleHandle
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
void HandleXMLEndTag(const std::string_view &tag) override
intptr_t mCurrentEffectID
std::recursive_mutex mDispatcherLock
intptr_t constCallDispatcher(int opcode, int index, intptr_t value, void *ptr, float opt) const
void ResetModuleAndHandle()
void SaveFXB(const wxFileName &fn) const
bool LoadFXP(const wxFileName &fn)
void ForEachParameter(ParameterVisitor visitor) const
bool IsCompatible(const VstPatchChunkInfo &) const
intptr_t callDispatcher(int opcode, int index, intptr_t value, void *ptr, float opt) override
void callSetParameter(int index, float value) const
virtual void SetBufferDelay(int samples)
float callGetParameter(int index) const
VstPatchChunkInfo mXMLInfo
void SaveFXProgram(wxMemoryBuffer &buf, int index) const
void callSetProgram(int index)
std::unique_ptr< EffectInstance::Message > MakeMessageFS(const VSTSettings &settings) const
void HandleXMLContent(const std::string_view &content) override
std::function< bool(const ParameterInfo &pi) > ParameterVisitor
void SaveXML(const wxFileName &fn) const
bool LoadFXB(const wxFileName &fn)
VstPatchChunkInfo GetChunkInfo() const
void callSetChunk(bool isPgm, int len, void *buf)
ComponentInterfaceSymbol GetSymbol() const
VstTimeInfo * GetTimeInfo()