iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugPluginBase.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
16#include "IPlugPluginBase.h"
17#include "wdlendian.h"
18#include "wdl_base64.h"
19
20using namespace iplug;
21
22IPluginBase::IPluginBase(int nParams, int nPresets)
23: EDITOR_DELEGATE_CLASS(nParams)
24{
25 for (int i = 0; i < nPresets; ++i)
26 mPresets.Add(new IPreset());
27}
28
29IPluginBase::~IPluginBase()
30{
31 mPresets.Empty(true);
32}
33
34int IPluginBase::GetPluginVersion(bool decimal) const
35{
36 if (decimal)
37 return GetDecimalVersion(mVersion);
38 else
39 return mVersion;
40}
41
42void IPluginBase::GetPluginVersionStr(WDL_String& str) const
43{
44 GetVersionStr(mVersion, str);
45#if defined TRACER_BUILD
46 str.Append("T");
47#endif
48#if defined _DEBUG
49 str.Append("D");
50#endif
51}
52
53int IPluginBase::GetHostVersion(bool decimal) const
54{
55 if (decimal)
56 return GetDecimalVersion(mHostVersion);
57
58 return mHostVersion;
59}
60
61void IPluginBase::GetHostVersionStr(WDL_String& str) const
62{
63 GetVersionStr(mHostVersion, str);
64}
65
66const char* IPluginBase::GetAPIStr() const
67{
68 switch (GetAPI())
69 {
70 case kAPIVST2: return "VST2";
71 case kAPIVST3: return "VST3";
72 case kAPIAU: return "AU";
73 case kAPIAUv3: return "AUv3";
74 case kAPIAAX: return "AAX";
75 case kAPIAPP: return "APP";
76 case kAPICLAP: return "CLAP";
77 case kAPIWAM: return "WAM";
78 case kAPIWEB: return "WEB";
79 default: return "";
80 }
81}
82
83const char* IPluginBase::GetArchStr() const
84{
85#if defined OS_WEB
86 return "WASM";
87#elif defined _M_ARM64EC
88 return "arm64ec"; // Windows ARM64 Emulation Compatible
89#elif defined _M_ARM64 || defined __aarch64__
90 return "arm64"; // Native ARM64 (Windows or macOS)
91#elif defined _M_ARM
92 return "arm32"; // 32-bit ARM (Windows)
93#elif defined ARCH_64BIT
94 return "x86-64";
95#else
96 return "x86-32";
97#endif
98}
99
100void IPluginBase::GetBuildInfoStr(WDL_String& str, const char* date, const char* time) const
101{
102 WDL_String version;
103 GetPluginVersionStr(version);
104 str.SetFormatted(MAX_BUILD_INFO_STR_LEN, "%s %s (%s), built on %s at %.5s ", version.Get(), GetAPIStr(), GetArchStr(), date, time);
105}
106
107#pragma mark -
108
110{
111 TRACE
112 bool savedOK = true;
113 int i, n = mParams.GetSize();
114 for (i = 0; i < n && savedOK; ++i)
115 {
116 IParam* pParam = mParams.Get(i);
117 Trace(TRACELOC, "%d %s %f", i, pParam->GetName(), pParam->Value());
118 double v = pParam->Value();
119 savedOK &= (chunk.Put(&v) > 0);
120 }
121 return savedOK;
122}
123
124int IPluginBase::UnserializeParams(const IByteChunk& chunk, int startPos)
125{
126 TRACE
127 int i, n = mParams.GetSize(), pos = startPos;
128 ENTER_PARAMS_MUTEX
129 for (i = 0; i < n && pos >= 0; ++i)
130 {
131 IParam* pParam = mParams.Get(i);
132 double v = 0.0;
133 pos = chunk.Get(&v, pos);
134 if (pos >= 0)
135 {
136 pParam->Set(v);
137 Trace(TRACELOC, "%d %s %f", i, pParam->GetName(), pParam->Value());
138 }
139 }
140
141 OnParamReset(kPresetRecall);
142 LEAVE_PARAMS_MUTEX
143
144 return pos;
145}
146
147void IPluginBase::InitParamRange(int startIdx, int endIdx, int countStart, const char* nameFmtStr, double defaultVal, double minVal, double maxVal, double step, const char *label, int flags, const char *group, const IParam::Shape& shape, IParam::EParamUnit unit, IParam::DisplayFunc displayFunc)
148{
149 WDL_String nameStr;
150 for (auto p = startIdx; p <= endIdx; p++)
151 {
152 nameStr.SetFormatted(MAX_PARAM_NAME_LEN, nameFmtStr, countStart + (p-startIdx));
153 GetParam(p)->InitDouble(nameStr.Get(), defaultVal, minVal, maxVal, step, label, flags, group, shape, unit, displayFunc);
154 }
155}
156
157void IPluginBase::CloneParamRange(int cloneStartIdx, int cloneEndIdx, int startIdx, const char* searchStr, const char* replaceStr, const char* newGroup)
158{
159 for (auto p = cloneStartIdx; p <= cloneEndIdx; p++)
160 {
161 IParam* pParam = GetParam(p);
162 int outIdx = startIdx + (p - cloneStartIdx);
163 GetParam(outIdx)->Init(*pParam, searchStr, replaceStr, newGroup);
164 GetParam(outIdx)->Set(pParam->Value());
165 }
166}
167
168void IPluginBase::CopyParamValues(int startIdx, int destIdx, int nParams)
169{
170 assert((startIdx + nParams) < NParams());
171 assert((destIdx + nParams) < NParams());
172 assert((startIdx + nParams) < destIdx);
173
174 for (auto p = startIdx; p < startIdx + nParams; p++)
175 {
176 GetParam(destIdx++)->Set(GetParam(p)->Value());
177 }
178}
179
180void IPluginBase::CopyParamValues(const char* inGroup, const char *outGroup)
181{
182 WDL_PtrList<IParam> inParams, outParams;
183
184 for (auto p = 0; p < NParams(); p++)
185 {
186 IParam* pParam = GetParam(p);
187 if(strcmp(pParam->GetGroup(), inGroup) == 0)
188 {
189 inParams.Add(pParam);
190 }
191 else if(strcmp(pParam->GetGroup(), outGroup) == 0)
192 {
193 outParams.Add(pParam);
194 }
195 }
196
197 assert(inParams.GetSize() == outParams.GetSize());
198
199 for (auto p = 0; p < inParams.GetSize(); p++)
200 {
201 outParams.Get(p)->Set(inParams.Get(p)->Value());
202 }
203}
204
205void IPluginBase::ForParamInRange(int startIdx, int endIdx, std::function<void(int paramIdx, IParam&)>func)
206{
207 for (auto p = startIdx; p <= endIdx; p++)
208 {
209 func(p, * GetParam(p));
210 }
211}
212
213void IPluginBase::ForParamInGroup(const char* paramGroup, std::function<void (int paramIdx, IParam&)> func)
214{
215 for (auto p = 0; p < NParams(); p++)
216 {
217 IParam* pParam = GetParam(p);
218 if(strcmp(pParam->GetGroup(), paramGroup) == 0)
219 {
220 func(p, *pParam);
221 }
222 }
223}
224
226{
227 DefaultParamValues(0, NParams()-1);
228}
229
230void IPluginBase::DefaultParamValues(int startIdx, int endIdx)
231{
232 ForParamInRange(startIdx, endIdx, [](int paramIdx, IParam& param) {
233 param.SetToDefault();
234 });
235}
236
237void IPluginBase::DefaultParamValues(const char* paramGroup)
238{
239 ForParamInGroup(paramGroup, [](int paramIdx, IParam& param) {
240 param.SetToDefault();
241 });
242}
243
245{
246 RandomiseParamValues(0, NParams()-1);
247}
248
249void IPluginBase::RandomiseParamValues(int startIdx, int endIdx)
250{
251 ForParamInRange(startIdx, endIdx, [&](int paramIdx, IParam& param) { param.SetNormalized( static_cast<float>(std::rand()/(static_cast<float>(RAND_MAX)+1.f)) ); });
252}
253
254void IPluginBase::RandomiseParamValues(const char *paramGroup)
255{
256 ForParamInGroup(paramGroup, [&](int paramIdx, IParam& param) { param.SetNormalized( static_cast<float>(std::rand()/(static_cast<float>(RAND_MAX)+1.f)) ); });
257}
258
260{
261 ForParamInRange(0, NParams()-1, [](int paramIdx, IParam& param) {
262 param.PrintDetails();
263 DBGMSG("\n");
264 });
265}
266
267static IPreset* GetNextUninitializedPreset(WDL_PtrList<IPreset>* pPresets)
268{
269 int n = pPresets->GetSize();
270 for (int i = 0; i < n; ++i)
271 {
272 IPreset* pPreset = pPresets->Get(i);
273 if (!(pPreset->mInitialized))
274 {
275 return pPreset;
276 }
277 }
278 return 0;
279}
280
281void IPluginBase::MakeDefaultPreset(const char* name, int nPresets)
282{
283 for (int i = 0; i < nPresets; ++i)
284 {
285 IPreset* pPreset = GetNextUninitializedPreset(&mPresets);
286 if (pPreset)
287 {
288 pPreset->mInitialized = true;
289 strcpy(pPreset->mName, (name ? name : "Empty"));
290 SerializeState(pPreset->mChunk);
291 }
292 }
293}
294
295void IPluginBase::MakePreset(const char* name, ...)
296{
297 IPreset* pPreset = GetNextUninitializedPreset(&mPresets);
298 if (pPreset)
299 {
300 pPreset->mInitialized = true;
301 strcpy(pPreset->mName, name);
302
303 int i, n = NParams();
304
305 double v = 0.0;
306 va_list vp;
307 va_start(vp, name);
308 for (i = 0; i < n; ++i)
309 {
310 GET_PARAM_FROM_VARARG(GetParam(i)->Type(), vp, v);
311 pPreset->mChunk.Put(&v);
312 }
313 }
314}
315
316void IPluginBase::MakePresetFromNamedParams(const char* name, int nParamsNamed, ...)
317{
318 TRACE
319 IPreset* pPreset = GetNextUninitializedPreset(&mPresets);
320 if (pPreset)
321 {
322 pPreset->mInitialized = true;
323 strcpy(pPreset->mName, name);
324
325 int i = 0, n = NParams();
326
327 WDL_TypedBuf<double> vals;
328 vals.Resize(n);
329 double* pV = vals.Get();
330 for (i = 0; i < n; ++i, ++pV)
331 {
332 *pV = PARAM_UNINIT;
333 }
334
335 va_list vp;
336 va_start(vp, nParamsNamed);
337 for (int i = 0; i < nParamsNamed; ++i)
338 {
339 int paramIdx = (int) va_arg(vp, int);
340 // This assert will fire if any of the passed-in param values do not match
341 // the type that the param was initialized with (int for bool, int, enum; double for double).
342 assert(paramIdx > kNoParameter && paramIdx < n);
343 GET_PARAM_FROM_VARARG(GetParam(paramIdx)->Type(), vp, *(vals.Get() + paramIdx));
344 }
345 va_end(vp);
346
347 pV = vals.Get();
348 for (int i = 0; i < n; ++i, ++pV)
349 {
350 if (*pV == PARAM_UNINIT) // Any that weren't explicitly set, use the defaults.
351 {
352 *pV = GetParam(i)->Value();
353 }
354 pPreset->mChunk.Put(pV);
355 }
356 }
357}
358
359void IPluginBase::MakePresetFromChunk(const char* name, IByteChunk& chunk)
360{
361 IPreset* pPreset = GetNextUninitializedPreset(&mPresets);
362 if (pPreset)
363 {
364 pPreset->mInitialized = true;
365 strcpy(pPreset->mName, name);
366
367 pPreset->mChunk.PutChunk(&chunk);
368 }
369}
370
371void IPluginBase::MakePresetFromBlob(const char* name, const char* blob, int sizeOfChunk)
372{
373 IByteChunk presetChunk;
374 presetChunk.Resize(sizeOfChunk);
375 wdl_base64decode(blob, presetChunk.GetData(), sizeOfChunk);
376
377 MakePresetFromChunk(name, presetChunk);
378}
379
380static void MakeDefaultUserPresetName(WDL_PtrList<IPreset>* pPresets, char* str)
381{
382 int nDefaultNames = 0;
383 int n = pPresets->GetSize();
384 for (int i = 0; i < n; ++i)
385 {
386 IPreset* pPreset = pPresets->Get(i);
387 if (strstr(pPreset->mName, DEFAULT_USER_PRESET_NAME))
388 {
389 ++nDefaultNames;
390 }
391 }
392 snprintf(str, MAX_PRESET_NAME_LEN, "%s %d", DEFAULT_USER_PRESET_NAME, nDefaultNames + 1);
393}
394
396{
397 TRACE
398 MakeDefaultPreset("Empty", mPresets.GetSize());
399}
400
402{
403 TRACE
404 int i = 0;
405 while (i < mPresets.GetSize())
406 {
407 IPreset* pPreset = mPresets.Get(i);
408 if (pPreset->mInitialized)
409 {
410 ++i;
411 }
412 else
413 {
414 mPresets.Delete(i, true);
415 }
416 }
417}
418
420{
421 TRACE
422 bool restoredOK = false;
423 if (idx >= 0 && idx < mPresets.GetSize())
424 {
425 IPreset* pPreset = mPresets.Get(idx);
426
427 if (!(pPreset->mInitialized))
428 {
429 pPreset->mInitialized = true;
430 MakeDefaultUserPresetName(&mPresets, pPreset->mName);
431 restoredOK = SerializeState(pPreset->mChunk);
432 }
433 else
434 {
435 restoredOK = (UnserializeState(pPreset->mChunk, 0) > 0);
436 }
437
438 if (restoredOK)
439 {
440 mCurrentPresetIdx = idx;
442 OnRestoreState();
443 }
444 }
445 return restoredOK;
446}
447
448bool IPluginBase::RestorePreset(const char* name)
449{
450 if (CStringHasContents(name))
451 {
452 int n = mPresets.GetSize();
453 for (int i = 0; i < n; ++i)
454 {
455 IPreset* pPreset = mPresets.Get(i);
456 if (!strcmp(pPreset->mName, name))
457 {
458 return RestorePreset(i);
459 }
460 }
461 }
462 return false;
463}
464
465const char* IPluginBase::GetPresetName(int idx) const
466{
467 if (idx >= 0 && idx < mPresets.GetSize())
468 {
469 return mPresets.Get(idx)->mName;
470 }
471 return "";
472}
473
475{
476 if (mCurrentPresetIdx >= 0 && mCurrentPresetIdx < mPresets.GetSize())
477 {
478 IPreset* pPreset = mPresets.Get(mCurrentPresetIdx);
479 pPreset->mChunk.Clear();
480
481 Trace(TRACELOC, "%d %s", mCurrentPresetIdx, pPreset->mName);
482
483 SerializeState(pPreset->mChunk);
484
485 if (CStringHasContents(name))
486 {
487 strcpy(pPreset->mName, name);
488 }
489 }
490}
491
493{
494 TRACE
495 bool savedOK = true;
496 int n = mPresets.GetSize();
497 for (int i = 0; i < n && savedOK; ++i)
498 {
499 IPreset* pPreset = mPresets.Get(i);
500 chunk.PutStr(pPreset->mName);
501
502 Trace(TRACELOC, "%d %s", i, pPreset->mName);
503
504 chunk.Put(&pPreset->mInitialized);
505 if (pPreset->mInitialized)
506 {
507 savedOK &= (chunk.PutChunk(&(pPreset->mChunk)) > 0);
508 }
509 }
510 return savedOK;
511}
512
513int IPluginBase::UnserializePresets(const IByteChunk& chunk, int startPos)
514{
515 TRACE
516 WDL_String name;
517 int n = mPresets.GetSize(), pos = startPos;
518 for (int i = 0; i < n && pos >= 0; ++i)
519 {
520 IPreset* pPreset = mPresets.Get(i);
521 pos = chunk.GetStr(name, pos);
522 strcpy(pPreset->mName, name.Get());
523
524 Trace(TRACELOC, "%d %s", i, pPreset->mName);
525
526 pos = chunk.Get<bool>(&(pPreset->mInitialized), pos);
527 if (pPreset->mInitialized)
528 {
529 pos = UnserializeState(chunk, pos);
530 if (pos > 0)
531 {
532 pPreset->mChunk.Clear();
533 SerializeState(pPreset->mChunk);
534 }
535 }
536 }
537 RestorePreset(mCurrentPresetIdx);
538 return pos;
539}
540
541void IPluginBase::DumpMakePresetSrc(const char* filename) const
542{
543 bool sDumped = false;
544 if (!sDumped)
545 {
546 sDumped = true;
547 int i, n = NParams();
548 FILE* fp = fopenUTF8(filename, "a");
549
550 if (!fp)
551 return;
552
553 int idx = GetCurrentPresetIdx();
554 fprintf(fp, "MakePreset(\"%s\"", GetPresetName(idx));
555 for (i = 0; i < n; ++i)
556 {
557 const IParam* pParam = GetParam(i);
558 constexpr int maxLen = 32;
559 char paramVal[maxLen];
560
561 switch (pParam->Type())
562 {
563 case IParam::kTypeBool:
564 snprintf(paramVal, maxLen, "%s", (pParam->Bool() ? "true" : "false"));
565 break;
566 case IParam::kTypeInt:
567 snprintf(paramVal, maxLen, "%d", pParam->Int());
568 break;
569 case IParam::kTypeEnum:
570 snprintf(paramVal, maxLen, "%d", pParam->Int());
571 break;
572 case IParam::kTypeDouble:
573 default:
574 snprintf(paramVal, maxLen, "%.6f", pParam->Value());
575 break;
576 }
577 fprintf(fp, ", %s", paramVal);
578 }
579 fprintf(fp, ");\n");
580 fclose(fp);
581 }
582}
583
584void IPluginBase::DumpMakePresetFromNamedParamsSrc(const char* filename, const char* paramEnumNames[]) const
585{
586 bool sDumped = false;
587
588 if (!sDumped)
589 {
590 sDumped = true;
591 int i, n = NParams();
592 FILE* fp = fopenUTF8(filename, "a");
593
594 if (!fp)
595 return;
596
597 int idx = GetCurrentPresetIdx();
598 fprintf(fp, " MakePresetFromNamedParams(\"%s\", %d", GetPresetName(idx), n);
599 for (i = 0; i < n; ++i)
600 {
601 const IParam* pParam = GetParam(i);
602 constexpr int maxLen = 32;
603 char paramVal[maxLen];
604 switch (pParam->Type())
605 {
606 case IParam::kTypeBool:
607 snprintf(paramVal, maxLen, "%s", (pParam->Bool() ? "true" : "false"));
608 break;
609 case IParam::kTypeInt:
610 snprintf(paramVal, maxLen, "%d", pParam->Int());
611 break;
612 case IParam::kTypeEnum:
613 snprintf(paramVal, maxLen, "%d", pParam->Int());
614 break;
615 case IParam::kTypeDouble:
616 default:
617 snprintf(paramVal, maxLen, "%.6f", pParam->Value());
618 break;
619 }
620 fprintf(fp, ",\n %s, %s", paramEnumNames[i], paramVal);
621 }
622 fprintf(fp, ");\n");
623 fclose(fp);
624 }
625}
626
627void IPluginBase::DumpPresetBlob(const char* filename) const
628{
629 FILE* fp = fopenUTF8(filename, "a");
630
631 if (!fp)
632 return;
633
634 int idx = GetCurrentPresetIdx();
635 fprintf(fp, "MakePresetFromBlob(\"%s\", \"", GetPresetName(idx));
636
637 char buf[MAX_BLOB_LENGTH];
638
639 IByteChunk* pPresetChunk = &mPresets.Get(mCurrentPresetIdx)->mChunk;
640 uint8_t* byteStart = pPresetChunk->GetData();
641
642 wdl_base64encode(byteStart, buf, pPresetChunk->Size());
643
644 fprintf(fp, "%s\", %i);\n", buf, pPresetChunk->Size());
645 fclose(fp);
646}
647
648// confusing... IByteChunk will force storage as little endian on big endian platforms,
649// so when we use it here, since vst fxp/fxb files are big endian, we need to swap the endianess
650// regardless of the endianness of the host, and on big endian hosts it will get swapped back to
651// big endian
652bool IPluginBase::SavePresetAsFXP(const char* file) const
653{
654 if (CStringHasContents(file))
655 {
656 FILE* fp = fopenUTF8(file, "wb");
657
658 IByteChunk pgm;
659
660 int32_t chunkMagic = WDL_bswap32('CcnK');
661 int32_t byteSize = 0;
662 int32_t fxpMagic;
663 int32_t fxpVersion = WDL_bswap32(kFXPVersionNum);
664 int32_t pluginID = WDL_bswap32(GetUniqueID());
665 int32_t pluginVersion = WDL_bswap32(GetPluginVersion(true));
666 int32_t numParams = WDL_bswap32(NParams());
667 char prgName[28];
668 memset(prgName, 0, 28);
669 strcpy(prgName, GetPresetName(GetCurrentPresetIdx()));
670
671 pgm.Put(&chunkMagic);
672
673 if (DoesStateChunks())
674 {
675 IByteChunk state;
676 int32_t chunkSize;
677
678 fxpMagic = WDL_bswap32('FPCh');
679
681 SerializeState(state);
682
683 chunkSize = WDL_bswap32(state.Size());
684 byteSize = WDL_bswap32(state.Size() + 60);
685
686 pgm.Put(&byteSize);
687 pgm.Put(&fxpMagic);
688 pgm.Put(&fxpVersion);
689 pgm.Put(&pluginID);
690 pgm.Put(&pluginVersion);
691 pgm.Put(&numParams);
692 pgm.PutBytes(prgName, 28); // not PutStr (we want all 28 bytes)
693 pgm.Put(&chunkSize);
694 pgm.PutBytes(state.GetData(), state.Size());
695 }
696 else
697 {
698 fxpMagic = WDL_bswap32('FxCk');
699 //byteSize = WDL_bswap32(20 + 28 + (NParams() * 4) );
700 pgm.Put(&byteSize);
701 pgm.Put(&fxpMagic);
702 pgm.Put(&fxpVersion);
703 pgm.Put(&pluginID);
704 pgm.Put(&pluginVersion);
705 pgm.Put(&numParams);
706 pgm.PutBytes(prgName, 28); // not PutStr (we want all 28 bytes)
707
708 for (int i = 0; i< NParams(); i++)
709 {
710 WDL_EndianFloat v32;
711 v32.f = (float) GetParam(i)->GetNormalized();
712 unsigned int swapped = WDL_bswap32(v32.int32);
713 pgm.Put(&swapped);
714 }
715 }
716
717 fwrite(pgm.GetData(), pgm.Size(), 1, fp);
718 fclose(fp);
719
720 return true;
721 }
722 return false;
723}
724
725bool IPluginBase::SaveBankAsFXB(const char* file) const
726{
727 if (CStringHasContents(file))
728 {
729 FILE* fp = fopenUTF8(file, "wb");
730
731 IByteChunk bnk;
732
733 int32_t chunkMagic = WDL_bswap32('CcnK');
734 int32_t byteSize = 0;
735 int32_t fxbMagic;
736 int32_t fxbVersion = WDL_bswap32(kFXBVersionNum);
737 int32_t pluginID = WDL_bswap32(GetUniqueID());
738 int32_t pluginVersion = WDL_bswap32(GetPluginVersion(true));
739 int32_t numPgms = WDL_bswap32(NPresets());
740 int32_t currentPgm = WDL_bswap32(GetCurrentPresetIdx());
741 char future[124];
742 memset(future, 0, 124);
743
744 bnk.Put(&chunkMagic);
745
746 if (DoesStateChunks())
747 {
748 IByteChunk state;
749 int32_t chunkSize;
750
751 fxbMagic = WDL_bswap32('FBCh');
752
754 SerializePresets(state);
755
756 chunkSize = WDL_bswap32(state.Size());
757 byteSize = WDL_bswap32(160 + state.Size() );
758
759 bnk.Put(&byteSize);
760 bnk.Put(&fxbMagic);
761 bnk.Put(&fxbVersion);
762 bnk.Put(&pluginID);
763 bnk.Put(&pluginVersion);
764 bnk.Put(&numPgms);
765 bnk.Put(&currentPgm);
766 bnk.PutBytes(&future, 124);
767
768 bnk.Put(&chunkSize);
769 bnk.PutBytes(state.GetData(), state.Size());
770 }
771 else
772 {
773 fxbMagic = WDL_bswap32('FxBk');
774
775 bnk.Put(&byteSize);
776 bnk.Put(&fxbMagic);
777 bnk.Put(&fxbVersion);
778 bnk.Put(&pluginID);
779 bnk.Put(&pluginVersion);
780 bnk.Put(&numPgms);
781 bnk.Put(&currentPgm);
782 bnk.PutBytes(&future, 124);
783
784 int32_t fxpMagic = WDL_bswap32('FxCk');
785 int32_t fxpVersion = WDL_bswap32(kFXPVersionNum);
786 int32_t numParams = WDL_bswap32(NParams());
787
788 for (int p = 0; p < NPresets(); p++)
789 {
790 IPreset* pPreset = mPresets.Get(p);
791
792 char prgName[28];
793 memset(prgName, 0, 28);
794 strcpy(prgName, pPreset->mName);
795
796 bnk.Put(&chunkMagic);
797 //byteSize = WDL_bswap32(20 + 28 + (NParams() * 4) );
798 bnk.Put(&byteSize);
799 bnk.Put(&fxpMagic);
800 bnk.Put(&fxpVersion);
801 bnk.Put(&pluginID);
802 bnk.Put(&pluginVersion);
803 bnk.Put(&numParams);
804 bnk.PutBytes(prgName, 28);
805
806 int pos = 0;
807
808 for (int i = 0; i< NParams(); i++)
809 {
810 double v = 0.0;
811 pos = pPreset->mChunk.Get(&v, pos);
812
813 WDL_EndianFloat v32;
814 v32.f = (float) GetParam(i)->ToNormalized(v);
815 uint32_t swapped = WDL_bswap32(v32.int32);
816 bnk.Put(&swapped);
817 }
818 }
819 }
820
821 fwrite(bnk.GetData(), bnk.Size(), 1, fp);
822 fclose(fp);
823
824 return true;
825 }
826 else
827 return false;
828}
829
830bool IPluginBase::LoadPresetFromFXP(const char* file)
831{
832 if (CStringHasContents(file))
833 {
834 FILE* fp = fopenUTF8(file, "rb");
835
836 if (fp)
837 {
838 IByteChunk pgm;
839 long fileSize;
840
841 fseek(fp , 0 , SEEK_END);
842 fileSize = ftell(fp);
843 rewind(fp);
844
845 pgm.Resize((int) fileSize);
846 fread(pgm.GetData(), fileSize, 1, fp);
847
848 fclose(fp);
849
850 int pos = 0;
851
852 int32_t chunkMagic;
853 int32_t byteSize = 0;
854 int32_t fxpMagic;
855 int32_t fxpVersion;
856 int32_t pluginID;
857 int32_t pluginVersion;
858 int32_t numParams;
859 char prgName[28];
860
861 pos = pgm.Get(&chunkMagic, pos);
862 chunkMagic = WDL_bswap_if_le(chunkMagic);
863 pos = pgm.Get(&byteSize, pos);
864 byteSize = WDL_bswap_if_le(byteSize);
865 pos = pgm.Get(&fxpMagic, pos);
866 fxpMagic = WDL_bswap_if_le(fxpMagic);
867 pos = pgm.Get(&fxpVersion, pos);
868 fxpVersion = WDL_bswap_if_le(fxpVersion);
869 pos = pgm.Get(&pluginID, pos);
870 pluginID = WDL_bswap_if_le(pluginID);
871 pos = pgm.Get(&pluginVersion, pos);
872 pluginVersion = WDL_bswap_if_le(pluginVersion);
873 pos = pgm.Get(&numParams, pos);
874 numParams = WDL_bswap_if_le(numParams);
875 pos = pgm.GetBytes(prgName, 28, pos);
876
877 if (chunkMagic != 'CcnK') return false;
878 if (fxpVersion != kFXPVersionNum) return false; // TODO: what if a host saves as a different version?
879 if (pluginID != GetUniqueID()) return false;
880 //if (pluginVersion != GetPluginVersion(true)) return false; // TODO: provide mechanism for loading earlier versions
881 //if (numParams != NParams()) return false; // TODO: provide mechanism for loading earlier versions with less params
882
883 if (DoesStateChunks() && fxpMagic == 'FPCh')
884 {
885 int32_t chunkSize;
886 pos = pgm.Get(&chunkSize, pos);
887 chunkSize = WDL_bswap_if_le(chunkSize);
888
890 UnserializeState(pgm, pos);
891 ModifyCurrentPreset(prgName);
894
895 return true;
896 }
897 else if (fxpMagic == 'FxCk') // Due to the big Endian-ness of FXP/FXB format we cannot call SerializeParams()
898 {
899 ENTER_PARAMS_MUTEX
900 for (int i = 0; i< NParams(); i++)
901 {
902 WDL_EndianFloat v32;
903 pos = pgm.Get(&v32.int32, pos);
904 v32.int32 = WDL_bswap_if_le(v32.int32);
905 GetParam(i)->SetNormalized((double) v32.f);
906 }
907 LEAVE_PARAMS_MUTEX
908
909 ModifyCurrentPreset(prgName);
912
913 return true;
914 }
915 }
916 }
917
918 return false;
919}
920
921bool IPluginBase::LoadBankFromFXB(const char* file)
922{
923 if (CStringHasContents(file))
924 {
925 FILE* fp = fopenUTF8(file, "rb");
926
927 if (fp)
928 {
929 IByteChunk bnk;
930 long fileSize;
931
932 fseek(fp , 0 , SEEK_END);
933 fileSize = ftell(fp);
934 rewind(fp);
935
936 bnk.Resize((int) fileSize);
937 fread(bnk.GetData(), fileSize, 1, fp);
938
939 fclose(fp);
940
941 int pos = 0;
942
943 int32_t chunkMagic;
944 int32_t byteSize = 0;
945 int32_t fxbMagic;
946 int32_t fxbVersion;
947 int32_t pluginID;
948 int32_t pluginVersion;
949 int32_t numPgms;
950 int32_t currentPgm;
951 char future[124];
952 memset(future, 0, 124);
953
954 pos = bnk.Get(&chunkMagic, pos);
955 chunkMagic = WDL_bswap_if_le(chunkMagic);
956 pos = bnk.Get(&byteSize, pos);
957 byteSize = WDL_bswap_if_le(byteSize);
958 pos = bnk.Get(&fxbMagic, pos);
959 fxbMagic = WDL_bswap_if_le(fxbMagic);
960 pos = bnk.Get(&fxbVersion, pos);
961 fxbVersion = WDL_bswap_if_le(fxbVersion);
962 pos = bnk.Get(&pluginID, pos);
963 pluginID = WDL_bswap_if_le(pluginID);
964 pos = bnk.Get(&pluginVersion, pos);
965 pluginVersion = WDL_bswap_if_le(pluginVersion);
966 pos = bnk.Get(&numPgms, pos);
967 numPgms = WDL_bswap_if_le(numPgms);
968 pos = bnk.Get(&currentPgm, pos);
969 currentPgm = WDL_bswap_if_le(currentPgm);
970 pos = bnk.GetBytes(future, 124, pos);
971
972 if (chunkMagic != 'CcnK') return false;
973 //if (fxbVersion != kFXBVersionNum) return false; // TODO: what if a host saves as a different version?
974 if (pluginID != GetUniqueID()) return false;
975 //if (pluginVersion != GetPluginVersion(true)) return false; // TODO: provide mechanism for loading earlier versions
976 //if (numPgms != NPresets()) return false; // TODO: provide mechanism for loading earlier versions with less params
977
978 if (DoesStateChunks() && fxbMagic == 'FBCh')
979 {
980 int32_t chunkSize;
981 pos = bnk.Get(&chunkSize, pos);
982 chunkSize = WDL_bswap_if_le(chunkSize);
983
985 UnserializePresets(bnk, pos);
986 //RestorePreset(currentPgm);
988 return true;
989 }
990 else if (fxbMagic == 'FxBk') // Due to the big Endian-ness of FXP/FXB format we cannot call SerializeParams()
991 {
992 int32_t chunkMagic;
993 int32_t byteSize;
994 int32_t fxpMagic;
995 int32_t fxpVersion;
996 int32_t pluginID;
997 int32_t pluginVersion;
998 int32_t numParams;
999 char prgName[28];
1000
1001 for(int i = 0; i<numPgms; i++)
1002 {
1003 pos = bnk.Get(&chunkMagic, pos);
1004 chunkMagic = WDL_bswap_if_le(chunkMagic);
1005
1006 pos = bnk.Get(&byteSize, pos);
1007 byteSize = WDL_bswap_if_le(byteSize);
1008
1009 pos = bnk.Get(&fxpMagic, pos);
1010 fxpMagic = WDL_bswap_if_le(fxpMagic);
1011
1012 pos = bnk.Get(&fxpVersion, pos);
1013 fxpVersion = WDL_bswap_if_le(fxpVersion);
1014
1015 pos = bnk.Get(&pluginID, pos);
1016 pluginID = WDL_bswap_if_le(pluginID);
1017
1018 pos = bnk.Get(&pluginVersion, pos);
1019 pluginVersion = WDL_bswap_if_le(pluginVersion);
1020
1021 pos = bnk.Get(&numParams, pos);
1022 numParams = WDL_bswap_if_le(numParams);
1023
1024 if (chunkMagic != 'CcnK') return false;
1025 if (fxpMagic != 'FxCk') return false;
1026 if (fxpVersion != kFXPVersionNum) return false;
1027 if (numParams != NParams()) return false;
1028
1029 pos = bnk.GetBytes(prgName, 28, pos);
1030
1031 RestorePreset(i);
1032
1033 ENTER_PARAMS_MUTEX
1034 for (int j = 0; j< NParams(); j++)
1035 {
1036 WDL_EndianFloat v32;
1037 pos = bnk.Get(&v32.int32, pos);
1038 v32.int32 = WDL_bswap_if_le(v32.int32);
1039 GetParam(j)->SetNormalized((double) v32.f);
1040 }
1041 LEAVE_PARAMS_MUTEX
1042
1043 ModifyCurrentPreset(prgName);
1044 }
1045
1046 RestorePreset(currentPgm);
1048
1049 return true;
1050 }
1051 }
1052 }
1053
1054 return false;
1055}
Manages a block of memory, for plug-in settings store/recall.
Definition: IPlugStructs.h:112
static int GetIPlugVerFromChunk(const IByteChunk &chunk, int &position)
Helper method to retrieve the IPlug version number from the beginning of the byte chunk.
Definition: IPlugStructs.h:132
int Put(const T *pVal)
Copies arbitary typed data into the IByteChunk.
Definition: IPlugStructs.h:170
int GetBytes(void *pDst, int nBytesToCopy, int startPos) const
Copy raw bytes from the IByteChunk, returning the new position for subsequent calls.
Definition: IPlugStructs.h:160
int PutStr(const char *str)
Put a string into the IByteChunk.
Definition: IPlugStructs.h:189
int Get(T *pDst, int startPos) const
Get arbitary typed data from the IByteChunk.
Definition: IPlugStructs.h:181
int PutBytes(const void *pSrc, int nBytesToCopy)
Copies data into the chunk, placing it at the end, resizing if necessary.
Definition: IPlugStructs.h:147
void Clear()
Clears the chunk (resizes to 0)
Definition: IPlugStructs.h:214
uint8_t * GetData()
Gets a ptr to the chunk data.
Definition: IPlugStructs.h:242
static void InitChunkWithIPlugVer(IByteChunk &chunk)
This method is used in order to place the IPlug version number in the chunk when serialising data.
Definition: IPlugStructs.h:119
int Size() const
Returns the current size of the chunk.
Definition: IPlugStructs.h:221
int Resize(int newSize)
Resizes the chunk.
Definition: IPlugStructs.h:229
int GetStr(WDL_String &str, int startPos) const
Get a string from the IByteChunk.
Definition: IPlugStructs.h:200
int PutChunk(const IByteChunk *pRHS)
Put another IByteChunk into this one.
Definition: IPlugStructs.h:208
IPlug's parameter class.
void SetToDefault()
Replaces the parameter's current value with the default one
EParamType Type() const
Get the parameter's type.
void Set(double value)
Sets the parameter value.
std::function< void(double, WDL_String &)> DisplayFunc
DisplayFunc allows custom parameter display functions, defined by a lambda matching this signature.
void SetNormalized(double normalizedValue)
Sets the parameter value from a normalized range (usually coming from the linked IControl)
EParamUnit
Used by AudioUnit plugins to determine the appearance of parameters, based on the kind of data they r...
const char * GetName() const
Returns the parameter's name.
bool Bool() const
Returns the parameter's value as a boolean.
void PrintDetails() const
Helper to print the parameter details to debug console in debug builds.
int Int() const
Returns the parameter's value as an integer.
const char * GetGroup() const
Returns the parameter's group.
double Value() const
Gets a readable value of the parameter.
void ForParamInRange(int startIdx, int endIdx, std::function< void(int paramIdx, IParam &param)> func)
Modify a range of parameters with a lamda function.
void InitParamRange(int startIdx, int endIdx, int countStart, const char *nameFmtStr, double defaultVal, double minVal, double maxVal, double step, const char *label="", int flags=0, const char *group="", const IParam::Shape &shape=IParam::ShapeLinear(), IParam::EParamUnit unit=IParam::kUnitCustom, IParam::DisplayFunc displayFunc=nullptr)
Initialise a range of parameters simultaneously.
virtual int UnserializeState(const IByteChunk &chunk, int startPos)
Override this method to unserialize custom state data, if your plugin does state chunks.
void DefaultParamValues()
Set all parameters to their default values.
void DumpMakePresetFromNamedParamsSrc(const char *file, const char *paramEnumNames[]) const
Writes a call to MakePresetFromNamedParams() for the current preset to a new text file.
bool SerializeParams(IByteChunk &chunk) const
Serializes the current double precision floating point, non-normalised values (IParam::mValue) of all...
int GetPluginVersion(bool decimal) const
Get the plug-in version number.
const char * GetArchStr() const
void RandomiseParamValues()
Randomise all parameters.
void MakePresetFromBlob(const char *name, const char *blob, int sizeOfChunk)
Creates a preset from a base64 encoded CString.
int GetUniqueID() const
int UnserializePresets(const IByteChunk &chunk, int startPos)
[VST2 only] Called when the VST2 host calls effSetChunk for a bank *
bool LoadPresetFromFXP(const char *file)
Load VST2 format preset.
virtual bool SerializeState(IByteChunk &chunk) const
Override this method to serialize custom state data, if your plugin does state chunks.
bool DoesStateChunks() const
void ModifyCurrentPreset(const char *name=0)
This method should update the current preset with current values NOTE: This is only relevant for VST2...
int GetCurrentPresetIdx() const
Get the index of the current, active preset.
int UnserializeParams(const IByteChunk &chunk, int startPos)
Unserializes double precision floating point, non-normalised values from a byte chunk into mParams.
void EnsureDefaultPreset()
[VST2 only] Called to fill uninitialzed presets
int GetHostVersion(bool decimal) const
Get the host version number as an integer.
void CopyParamValues(int startIdx, int destIdx, int nParams)
Copy a range of parameter values.
virtual void InformHostOfPresetChange()
Implemented by the API class, called by the UI (etc) when the plug-in initiates a program/preset chan...
void GetPluginVersionStr(WDL_String &str) const
Gets the plug-in version as a string.
void MakePresetFromNamedParams(const char *name, int nParamsNamed,...)
Create a baked-in factory preset, specifiying parameter values with a list of parameter index and val...
void DumpPresetBlob(const char *file) const
Writes a call to MakePresetFromBlob() for the current preset to a new text file.
bool RestorePreset(int idx)
Restore a preset by index.
void GetBuildInfoStr(WDL_String &str, const char *date, const char *time) const
Get the build date of the plug-in and architecture/api details in one string.
void GetHostVersionStr(WDL_String &str) const
Get the host version number as a string.
void MakeDefaultPreset(const char *name=0, int nPresets=1)
This method can be used to initialize baked-in factory presets with the default parameter values.
const char * GetAPIStr() const
bool SerializePresets(IByteChunk &chunk) const
[VST2 only] Called when the VST2 host calls effGetChunk for a bank *
void ForParamInGroup(const char *paramGroup, std::function< void(int paramIdx, IParam &param)> func)
Modify a parameter group simulataneously.
const char * GetPresetName(int idx) const
Get the name a preset.
bool LoadBankFromFXB(const char *file)
Load VST2 format bank [VST2 only].
void CloneParamRange(int cloneStartIdx, int cloneEndIdx, int startIdx, const char *searchStr="", const char *replaceStr="", const char *newGroup="")
Clone a range of parameters, optionally doing a string substitution on the parameter name.
void DumpMakePresetSrc(const char *file) const
Writes a call to MakePreset() for the current preset to a new text file.
bool SavePresetAsFXP(const char *file) const
Save current state as a VST2 format preset.
void PruneUninitializedPresets()
[AUV2 only] Removes any presets that weren't initialized
EAPI GetAPI() const
void PrintParamValues()
Default parameter values for a parameter group
virtual void OnPresetsModified()
[VST2 only] Called when the preset name is changed by the host
void MakePresetFromChunk(const char *name, IByteChunk &chunk)
Creates a preset from an IByteChunk containing serialized data.
int NPresets() const
Gets the number of factory presets.
bool SaveBankAsFXB(const char *file) const
Save current bank as a VST2 format bank [VST2 only].
void MakePreset(const char *name,...)
Create a baked-in factory preset, specifiying parameter values sequentially usage: MakePreset(name,...
static int GetDecimalVersion(int versionInteger)
Helper function to get the version number as a decimal integer.
static void GetVersionStr(int versionInteger, WDL_String &str)
Helper function to get the semantic version number as a string from an integer.
Base struct for parameter shaping.
A struct used for specifying baked-in factory presets.
Definition: IPlugStructs.h:602