9 #include "../wdlendian.h"
10 #include "../base64encdec.h"
17 typedef int32_t VstInt32
;
21 const double DEFAULT_SAMPLE_RATE
= 44100.0;
23 template <class SRC
, class DEST
>
24 void CastCopy(DEST
* pDest
, SRC
* pSrc
, int n
)
26 for (int i
= 0; i
< n
; ++i
, ++pDest
, ++pSrc
)
28 *pDest
= (DEST
) *pSrc
;
32 void GetVersionParts(int version
, int* pVer
, int* pMaj
, int* pMin
)
34 *pVer
= (version
& 0xFFFF0000) >> 16;
35 *pMaj
= (version
& 0x0000FF00) >> 8;
36 *pMin
= version
& 0x000000FF;
39 int GetDecimalVersion(int version
)
42 GetVersionParts(version
, &ver
, &rmaj
, &rmin
);
43 return 10000 * ver
+ 100 * rmaj
+ rmin
;
46 void GetVersionStr(int version
, char* str
)
49 GetVersionParts(version
, &ver
, &rmaj
, &rmin
);
50 sprintf(str
, "v%d.%d.%d", ver
, rmaj
, rmin
);
57 IPlugBase::IPlugBase(int nParams
,
58 const char* channelIOStr
,
60 const char* effectName
,
61 const char* productName
,
73 , mVersion(vendorVersion
)
74 , mSampleRate(DEFAULT_SAMPLE_RATE
)
79 , mStateChunks(plugDoesChunks
)
81 , mCurrentPresetIdx(0)
83 , mDoesMIDI(plugDoesMidi
)
89 Trace(TRACELOC
, "%s:%s", effectName
, CurrentTime());
91 for (int i
= 0; i
< nParams
; ++i
)
93 mParams
.Add(new IParam
);
96 for (int i
= 0; i
< nPresets
; ++i
)
98 mPresets
.Add(new IPreset(i
));
101 strcpy(mEffectName
, effectName
);
102 strcpy(mProductName
, productName
);
103 strcpy(mMfrName
, mfrName
);
105 int nInputs
= 0, nOutputs
= 0;
109 int nIn
= 0, nOut
= 0;
111 bool channelIOStrValid
= sscanf(channelIOStr
, "%d-%d", &nIn
, &nOut
) == 2;
112 assert(channelIOStrValid
);
114 sscanf(channelIOStr
, "%d-%d", &nIn
, &nOut
);
116 nInputs
= IPMAX(nInputs
, nIn
);
117 nOutputs
= IPMAX(nOutputs
, nOut
);
118 mChannelIO
.Add(new ChannelIO(nIn
, nOut
));
119 channelIOStr
= strstr(channelIOStr
, " ");
127 mInData
.Resize(nInputs
);
128 mOutData
.Resize(nOutputs
);
130 double** ppInData
= mInData
.Get();
132 for (int i
= 0; i
< nInputs
; ++i
, ++ppInData
)
134 InChannel
* pInChannel
= new InChannel
;
135 pInChannel
->mConnected
= false;
136 pInChannel
->mSrc
= ppInData
;
137 mInChannels
.Add(pInChannel
);
140 double** ppOutData
= mOutData
.Get();
142 for (int i
= 0; i
< nOutputs
; ++i
, ++ppOutData
)
144 OutChannel
* pOutChannel
= new OutChannel
;
145 pOutChannel
->mConnected
= false;
146 pOutChannel
->mDest
= ppOutData
;
147 pOutChannel
->mFDest
= 0;
148 mOutChannels
.Add(pOutChannel
);
152 IPlugBase::~IPlugBase()
156 DELETE_NULL(mGraphics
);
159 mPresets
.Empty(true);
160 mInChannels
.Empty(true);
161 mOutChannels
.Empty(true);
162 mChannelIO
.Empty(true);
163 mInputBusLabels
.Empty(true);
164 mOutputBusLabels
.Empty(true);
172 int IPlugBase::GetHostVersion(bool decimal
)
177 return GetDecimalVersion(mHostVersion
);
182 void IPlugBase::GetHostVersionStr(char* str
)
185 GetVersionStr(mHostVersion
, str
);
188 bool IPlugBase::LegalIO(int nIn
, int nOut
)
191 int i
, n
= mChannelIO
.GetSize();
193 for (i
= 0; i
< n
&& !legal
; ++i
)
195 ChannelIO
* pIO
= mChannelIO
.Get(i
);
196 legal
= ((nIn
< 0 || nIn
== pIO
->mIn
) && (nOut
< 0 || nOut
== pIO
->mOut
));
199 Trace(TRACELOC
, "%d:%d:%s", nIn
, nOut
, (legal
? "legal" : "illegal"));
203 void IPlugBase::LimitToStereoIO()
205 int nIn
= NInChannels(), nOut
= NOutChannels();
209 SetInputChannelConnections(2, nIn
- 2, false);
214 SetOutputChannelConnections(2, nOut
- 2, true);
218 void IPlugBase::SetHost(const char* host
, int version
)
220 mHost
= LookUpHost(host
);
221 mHostVersion
= version
;
224 GetVersionStr(version
, vStr
);
225 Trace(TRACELOC
, "host_%sknown:%s:%s", (mHost
== kHostUnknown
? "un" : ""), host
, vStr
);
228 void IPlugBase::AttachGraphics(IGraphics
* pGraphics
)
232 WDL_MutexLock
lock(&mMutex
);
233 int i
, n
= mParams
.GetSize();
235 for (i
= 0; i
< n
; ++i
)
237 pGraphics
->SetParameterFromPlug(i
, GetParam(i
)->GetNormalized(), true);
240 pGraphics
->PrepDraw();
241 mGraphics
= pGraphics
;
246 // Decimal = VVVVRRMM, otherwise 0xVVVVRRMM.
247 int IPlugBase::GetEffectVersion(bool decimal
)
251 return GetDecimalVersion(mVersion
);
259 void IPlugBase::GetEffectVersionStr(char* str
)
261 GetVersionStr(mVersion
, str
);
264 #elif defined TRACER_BUILD
269 const char* IPlugBase::GetAPIString()
273 case kAPIVST2
: return "VST2";
274 case kAPIVST3
: return "VST3";
275 case kAPIAU
: return "AU";
276 case kAPIRTAS
: return "RTAS";
277 case kAPIAAX
: return "AAX";
278 case kAPISA
: return "Standalone";
283 const char* IPlugBase::GetArchString()
292 double IPlugBase::GetSamplesPerBeat()
294 double tempo
= GetTempo();
298 return GetSampleRate() * 60.0 / tempo
;
304 void IPlugBase::SetSampleRate(double sampleRate
)
306 mSampleRate
= sampleRate
;
309 void IPlugBase::SetBlockSize(int blockSize
)
311 if (blockSize
!= mBlockSize
)
313 int i
, nIn
= NInChannels(), nOut
= NOutChannels();
315 for (i
= 0; i
< nIn
; ++i
)
317 InChannel
* pInChannel
= mInChannels
.Get(i
);
318 pInChannel
->mScratchBuf
.Resize(blockSize
);
319 memset(pInChannel
->mScratchBuf
.Get(), 0, blockSize
* sizeof(double));
322 for (i
= 0; i
< nOut
; ++i
)
324 OutChannel
* pOutChannel
= mOutChannels
.Get(i
);
325 pOutChannel
->mScratchBuf
.Resize(blockSize
);
326 memset(pOutChannel
->mScratchBuf
.Get(), 0, blockSize
* sizeof(double));
329 mBlockSize
= blockSize
;
333 void IPlugBase::SetInputChannelConnections(int idx
, int n
, bool connected
)
335 int iEnd
= IPMIN(idx
+ n
, mInChannels
.GetSize());
337 for (int i
= idx
; i
< iEnd
; ++i
)
339 InChannel
* pInChannel
= mInChannels
.Get(i
);
340 pInChannel
->mConnected
= connected
;
344 *(pInChannel
->mSrc
) = pInChannel
->mScratchBuf
.Get();
349 void IPlugBase::SetOutputChannelConnections(int idx
, int n
, bool connected
)
351 int iEnd
= IPMIN(idx
+ n
, mOutChannels
.GetSize());
353 for (int i
= idx
; i
< iEnd
; ++i
)
355 OutChannel
* pOutChannel
= mOutChannels
.Get(i
);
356 pOutChannel
->mConnected
= connected
;
360 *(pOutChannel
->mDest
) = pOutChannel
->mScratchBuf
.Get();
365 bool IPlugBase::IsInChannelConnected(int chIdx
)
367 return (chIdx
< mInChannels
.GetSize() && mInChannels
.Get(chIdx
)->mConnected
);
370 bool IPlugBase::IsOutChannelConnected(int chIdx
)
372 return (chIdx
< mOutChannels
.GetSize() && mOutChannels
.Get(chIdx
)->mConnected
);
375 void IPlugBase::AttachInputBuffers(int idx
, int n
, double** ppData
, int nFrames
)
377 int iEnd
= IPMIN(idx
+ n
, mInChannels
.GetSize());
379 for (int i
= idx
; i
< iEnd
; ++i
)
381 InChannel
* pInChannel
= mInChannels
.Get(i
);
382 if (pInChannel
->mConnected
)
384 *(pInChannel
->mSrc
) = *(ppData
++);
389 void IPlugBase::AttachInputBuffers(int idx
, int n
, float** ppData
, int nFrames
)
391 int iEnd
= IPMIN(idx
+ n
, mInChannels
.GetSize());
392 for (int i
= idx
; i
< iEnd
; ++i
)
394 InChannel
* pInChannel
= mInChannels
.Get(i
);
395 if (pInChannel
->mConnected
)
397 double* pScratch
= pInChannel
->mScratchBuf
.Get();
398 CastCopy(pScratch
, *(ppData
++), nFrames
);
399 *(pInChannel
->mSrc
) = pScratch
;
404 void IPlugBase::AttachOutputBuffers(int idx
, int n
, double** ppData
)
406 int iEnd
= IPMIN(idx
+ n
, mOutChannels
.GetSize());
407 for (int i
= idx
; i
< iEnd
; ++i
)
409 OutChannel
* pOutChannel
= mOutChannels
.Get(i
);
410 if (pOutChannel
->mConnected
)
412 *(pOutChannel
->mDest
) = *(ppData
++);
417 void IPlugBase::AttachOutputBuffers(int idx
, int n
, float** ppData
)
419 int iEnd
= IPMIN(idx
+ n
, mOutChannels
.GetSize());
420 for (int i
= idx
; i
< iEnd
; ++i
)
422 OutChannel
* pOutChannel
= mOutChannels
.Get(i
);
423 if (pOutChannel
->mConnected
)
425 *(pOutChannel
->mDest
) = pOutChannel
->mScratchBuf
.Get();
426 pOutChannel
->mFDest
= *(ppData
++);
431 void IPlugBase::PassThroughBuffers(double sampleType
, int nFrames
)
433 if (mLatency
&& mDelay
)
435 mDelay
->ProcessBlock(mInData
.Get(), mOutData
.Get(), nFrames
);
439 IPlugBase::ProcessDoubleReplacing(mInData
.Get(), mOutData
.Get(), nFrames
);
443 void IPlugBase::PassThroughBuffers(float sampleType
, int nFrames
)
445 // for 32 bit buffers, first run the delay (if mLatency) on the 64bit IPlug buffers
446 PassThroughBuffers(0., nFrames
);
448 int i
, n
= NOutChannels();
449 OutChannel
** ppOutChannel
= mOutChannels
.GetList();
451 for (i
= 0; i
< n
; ++i
, ++ppOutChannel
)
453 OutChannel
* pOutChannel
= *ppOutChannel
;
454 if (pOutChannel
->mConnected
)
456 CastCopy(pOutChannel
->mFDest
, *(pOutChannel
->mDest
), nFrames
);
461 void IPlugBase::ProcessBuffers(double sampleType
, int nFrames
)
463 ProcessDoubleReplacing(mInData
.Get(), mOutData
.Get(), nFrames
);
466 void IPlugBase::ProcessBuffers(float sampleType
, int nFrames
)
468 ProcessDoubleReplacing(mInData
.Get(), mOutData
.Get(), nFrames
);
469 int i
, n
= NOutChannels();
470 OutChannel
** ppOutChannel
= mOutChannels
.GetList();
472 for (i
= 0; i
< n
; ++i
, ++ppOutChannel
)
474 OutChannel
* pOutChannel
= *ppOutChannel
;
476 if (pOutChannel
->mConnected
)
478 CastCopy(pOutChannel
->mFDest
, *(pOutChannel
->mDest
), nFrames
);
483 void IPlugBase::ProcessBuffersAccumulating(float sampleType
, int nFrames
)
485 ProcessDoubleReplacing(mInData
.Get(), mOutData
.Get(), nFrames
);
486 int i
, n
= NOutChannels();
487 OutChannel
** ppOutChannel
= mOutChannels
.GetList();
489 for (i
= 0; i
< n
; ++i
, ++ppOutChannel
)
491 OutChannel
* pOutChannel
= *ppOutChannel
;
492 if (pOutChannel
->mConnected
)
494 float* pDest
= pOutChannel
->mFDest
;
495 double* pSrc
= *(pOutChannel
->mDest
);
497 for (int j
= 0; j
< nFrames
; ++j
, ++pDest
, ++pSrc
)
499 *pDest
+= (float) *pSrc
;
505 void IPlugBase::ZeroScratchBuffers()
507 int i
, nIn
= NInChannels(), nOut
= NOutChannels();
509 for (i
= 0; i
< nIn
; ++i
)
511 InChannel
* pInChannel
= mInChannels
.Get(i
);
512 memset(pInChannel
->mScratchBuf
.Get(), 0, mBlockSize
* sizeof(double));
515 for (i
= 0; i
< nOut
; ++i
)
517 OutChannel
* pOutChannel
= mOutChannels
.Get(i
);
518 memset(pOutChannel
->mScratchBuf
.Get(), 0, mBlockSize
* sizeof(double));
522 // If latency changes after initialization (often not supported by the host).
523 void IPlugBase::SetLatency(int samples
)
529 mDelay
->SetDelayTime(mLatency
);
533 // this is over-ridden for AAX
534 void IPlugBase::SetParameterFromGUI(int idx
, double normalizedValue
)
536 Trace(TRACELOC
, "%d:%f", idx
, normalizedValue
);
537 WDL_MutexLock
lock(&mMutex
);
538 GetParam(idx
)->SetNormalized(normalizedValue
);
539 InformHostOfParamChange(idx
, normalizedValue
);
543 void IPlugBase::OnParamReset()
545 for (int i
= 0; i
< mParams
.GetSize(); ++i
)
552 // Default passthrough.
553 void IPlugBase::ProcessDoubleReplacing(double** inputs
, double** outputs
, int nFrames
)
555 // Mutex is already locked.
556 int i
, nIn
= mInChannels
.GetSize(), nOut
= mOutChannels
.GetSize();
558 for (i
= 0; i
< nOut
; ++i
)
562 memcpy(outputs
[i
], inputs
[i
], nFrames
* sizeof(double));
566 // zero remaining outs
567 for (/* same j */; j
< nOut
; ++j
)
569 memset(outputs
[j
], 0, nFrames
* sizeof(double));
573 // Default passthrough ONLY USED BY IOS.
574 void IPlugBase::ProcessSingleReplacing(float** inputs
, float** outputs
, int nFrames
)
576 // Mutex is already locked.
577 int i
, nIn
= mInChannels
.GetSize(), nOut
= mOutChannels
.GetSize();
578 for (i
= 0; i
< nIn
; ++i
)
580 memcpy(outputs
[i
], inputs
[i
], nFrames
* sizeof(float));
582 for (/* same i */; i
< nOut
; ++i
)
584 memset(outputs
[i
], 0, nFrames
* sizeof(float));
588 // Default passthrough.
589 void IPlugBase::ProcessMidiMsg(IMidiMsg
* pMsg
)
594 IPreset
* GetNextUninitializedPreset(WDL_PtrList
<IPreset
>* pPresets
)
596 int n
= pPresets
->GetSize();
597 for (int i
= 0; i
< n
; ++i
)
599 IPreset
* pPreset
= pPresets
->Get(i
);
600 if (!(pPreset
->mInitialized
))
608 void IPlugBase::MakeDefaultPreset(char* name
, int nPresets
)
610 for (int i
= 0; i
< nPresets
; ++i
)
612 IPreset
* pPreset
= GetNextUninitializedPreset(&mPresets
);
615 pPreset
->mInitialized
= true;
616 strcpy(pPreset
->mName
, (name
? name
: "Empty"));
617 SerializeState(&(pPreset
->mChunk
));
622 #define GET_PARAM_FROM_VARARG(paramType, vp, v) \
625 switch (paramType) { \
626 case IParam::kTypeBool: \
627 case IParam::kTypeInt: \
628 case IParam::kTypeEnum: { \
629 v = (double) va_arg(vp, int); \
632 case IParam::kTypeDouble: \
634 v = (double) va_arg(vp, double); \
640 void IPlugBase::MakePreset(char* name
, ...)
642 IPreset
* pPreset
= GetNextUninitializedPreset(&mPresets
);
645 pPreset
->mInitialized
= true;
646 strcpy(pPreset
->mName
, name
);
648 int i
, n
= mParams
.GetSize();
653 for (i
= 0; i
< n
; ++i
)
655 GET_PARAM_FROM_VARARG(GetParam(i
)->Type(), vp
, v
);
656 pPreset
->mChunk
.Put(&v
);
661 #define PARAM_UNINIT 99.99e-9
663 void IPlugBase::MakePresetFromNamedParams(char* name
, int nParamsNamed
, ...)
666 IPreset
* pPreset
= GetNextUninitializedPreset(&mPresets
);
669 pPreset
->mInitialized
= true;
670 strcpy(pPreset
->mName
, name
);
672 int i
= 0, n
= mParams
.GetSize();
674 WDL_TypedBuf
<double> vals
;
676 double* pV
= vals
.Get();
677 for (i
= 0; i
< n
; ++i
, ++pV
)
683 va_start(vp
, nParamsNamed
);
684 for (int i
= 0; i
< nParamsNamed
; ++i
)
686 int paramIdx
= (int) va_arg(vp
, int);
687 // This assert will fire if any of the passed-in param values do not match
688 // the type that the param was initialized with (int for bool, int, enum; double for double).
689 assert(paramIdx
>= 0 && paramIdx
< n
);
690 GET_PARAM_FROM_VARARG(GetParam(paramIdx
)->Type(), vp
, *(vals
.Get() + paramIdx
));
695 for (int i
= 0; i
< n
; ++i
, ++pV
)
697 if (*pV
== PARAM_UNINIT
) // Any that weren't explicitly set, use the defaults.
699 *pV
= GetParam(i
)->Value();
701 pPreset
->mChunk
.Put(pV
);
706 void IPlugBase::MakePresetFromChunk(char* name
, ByteChunk
* pChunk
)
708 IPreset
* pPreset
= GetNextUninitializedPreset(&mPresets
);
711 pPreset
->mInitialized
= true;
712 strcpy(pPreset
->mName
, name
);
714 pPreset
->mChunk
.PutChunk(pChunk
);
718 void IPlugBase::MakePresetFromBlob(char* name
, const char* blob
, int sizeOfChunk
)
720 ByteChunk presetChunk
;
721 presetChunk
.Resize(sizeOfChunk
);
722 base64decode(blob
, presetChunk
.GetBytes(), sizeOfChunk
);
724 MakePresetFromChunk(name
, &presetChunk
);
727 #define DEFAULT_USER_PRESET_NAME "user preset"
729 void MakeDefaultUserPresetName(WDL_PtrList
<IPreset
>* pPresets
, char* str
)
731 int nDefaultNames
= 0;
732 int n
= pPresets
->GetSize();
733 for (int i
= 0; i
< n
; ++i
)
735 IPreset
* pPreset
= pPresets
->Get(i
);
736 if (strstr(pPreset
->mName
, DEFAULT_USER_PRESET_NAME
))
741 sprintf(str
, "%s %d", DEFAULT_USER_PRESET_NAME
, nDefaultNames
+ 1);
744 void IPlugBase::EnsureDefaultPreset()
747 MakeDefaultPreset("Empty", mPresets
.GetSize());
750 void IPlugBase::PruneUninitializedPresets()
754 while (i
< mPresets
.GetSize())
756 IPreset
* pPreset
= mPresets
.Get(i
);
757 if (pPreset
->mInitialized
)
763 mPresets
.Delete(i
, true);
768 bool IPlugBase::RestorePreset(int idx
)
771 bool restoredOK
= false;
772 if (idx
>= 0 && idx
< mPresets
.GetSize())
774 IPreset
* pPreset
= mPresets
.Get(idx
);
776 if (!(pPreset
->mInitialized
))
778 pPreset
->mInitialized
= true;
779 MakeDefaultUserPresetName(&mPresets
, pPreset
->mName
);
780 restoredOK
= SerializeState(&(pPreset
->mChunk
));
784 restoredOK
= (UnserializeState(&(pPreset
->mChunk
), 0) > 0);
789 mCurrentPresetIdx
= idx
;
790 PresetsChangedByHost();
792 RedrawParamControls();
799 bool IPlugBase::RestorePreset(const char* name
)
801 if (CSTR_NOT_EMPTY(name
))
803 int n
= mPresets
.GetSize();
804 for (int i
= 0; i
< n
; ++i
)
806 IPreset
* pPreset
= mPresets
.Get(i
);
807 if (!strcmp(pPreset
->mName
, name
))
809 return RestorePreset(i
);
816 const char* IPlugBase::GetPresetName(int idx
)
818 if (idx
>= 0 && idx
< mPresets
.GetSize())
820 return mPresets
.Get(idx
)->mName
;
825 void IPlugBase::ModifyCurrentPreset(const char* name
)
827 if (mCurrentPresetIdx
>= 0 && mCurrentPresetIdx
< mPresets
.GetSize())
829 IPreset
* pPreset
= mPresets
.Get(mCurrentPresetIdx
);
830 pPreset
->mChunk
.Clear();
832 Trace(TRACELOC
, "%d %s", mCurrentPresetIdx
, pPreset
->mName
);
834 SerializeState(&(pPreset
->mChunk
));
836 if (CSTR_NOT_EMPTY(name
))
838 strcpy(pPreset
->mName
, name
);
843 bool IPlugBase::SerializePresets(ByteChunk
* pChunk
)
847 int n
= mPresets
.GetSize();
848 for (int i
= 0; i
< n
&& savedOK
; ++i
)
850 IPreset
* pPreset
= mPresets
.Get(i
);
851 pChunk
->PutStr(pPreset
->mName
);
853 Trace(TRACELOC
, "%d %s", i
, pPreset
->mName
);
855 pChunk
->PutBool(pPreset
->mInitialized
);
856 if (pPreset
->mInitialized
)
858 savedOK
&= (pChunk
->PutChunk(&(pPreset
->mChunk
)) > 0);
864 int IPlugBase::UnserializePresets(ByteChunk
* pChunk
, int startPos
)
868 int n
= mPresets
.GetSize(), pos
= startPos
;
869 for (int i
= 0; i
< n
&& pos
>= 0; ++i
)
871 IPreset
* pPreset
= mPresets
.Get(i
);
872 pos
= pChunk
->GetStr(&name
, pos
);
873 strcpy(pPreset
->mName
, name
.Get());
875 Trace(TRACELOC
, "%d %s", i
, pPreset
->mName
);
877 pos
= pChunk
->GetBool(&(pPreset
->mInitialized
), pos
);
878 if (pPreset
->mInitialized
)
880 pos
= UnserializeState(pChunk
, pos
);
883 pPreset
->mChunk
.Clear();
884 SerializeState(&(pPreset
->mChunk
));
888 RestorePreset(mCurrentPresetIdx
);
892 bool IPlugBase::SerializeParams(ByteChunk
* pChunk
)
896 WDL_MutexLock
lock(&mMutex
);
898 int i
, n
= mParams
.GetSize();
899 for (i
= 0; i
< n
&& savedOK
; ++i
)
901 IParam
* pParam
= mParams
.Get(i
);
902 Trace(TRACELOC
, "%d %s %f", i
, pParam
->GetNameForHost(), pParam
->Value());
903 double v
= pParam
->Value();
904 savedOK
&= (pChunk
->Put(&v
) > 0);
909 int IPlugBase::UnserializeParams(ByteChunk
* pChunk
, int startPos
)
913 WDL_MutexLock
lock(&mMutex
);
914 int i
, n
= mParams
.GetSize(), pos
= startPos
;
915 for (i
= 0; i
< n
&& pos
>= 0; ++i
)
917 IParam
* pParam
= mParams
.Get(i
);
919 Trace(TRACELOC
, "%d %s %f", i
, pParam
->GetNameForHost(), pParam
->Value());
920 pos
= pChunk
->Get(&v
, pos
);
927 bool IPlugBase::CompareState(const unsigned char* incomingState
, int startPos
)
931 const double* data
= (const double*) incomingState
+ startPos
;
933 // dirty hack here because protools treats param values as 32 bit int and in IPlug they are 64bit float
934 // if we memcmp() the incoming state with the current they may have tiny differences due to the quantization
935 for (int i
= 0; i
< NParams(); i
++)
937 float v
= (float) GetParam(i
)->Value();
938 float vi
= (float) *(data
++);
940 isEqual
&= (fabsf(v
- vi
) < 0.00001);
947 void IPlugBase::RedrawParamControls()
951 int i
, n
= mParams
.GetSize();
952 for (i
= 0; i
< n
; ++i
)
954 double v
= mParams
.Get(i
)->Value();
955 mGraphics
->SetParameterFromPlug(i
, v
, false);
960 void IPlugBase::DirtyParameters()
962 WDL_MutexLock
lock(&mMutex
);
964 for (int p
= 0; p
< NParams(); p
++)
966 double normalizedValue
= GetParam(p
)->GetNormalized();
967 InformHostOfParamChange(p
, normalizedValue
);
971 void IPlugBase::DumpPresetSrcCode(const char* filename
, const char* paramEnumNames
[])
973 // static bool sDumped = false;
974 bool sDumped
= false;
979 int i
, n
= NParams();
980 FILE* fp
= fopen(filename
, "w");
981 fprintf(fp
, " MakePresetFromNamedParams(\"name\", %d", n
);
982 for (i
= 0; i
< n
; ++i
)
984 IParam
* pParam
= GetParam(i
);
986 switch (pParam
->Type())
988 case IParam::kTypeBool
:
989 sprintf(paramVal
, "%s", (pParam
->Bool() ? "true" : "false"));
991 case IParam::kTypeInt
:
992 sprintf(paramVal
, "%d", pParam
->Int());
994 case IParam::kTypeEnum
:
995 sprintf(paramVal
, "%d", pParam
->Int());
997 case IParam::kTypeDouble
:
999 sprintf(paramVal
, "%.6f", pParam
->Value());
1002 fprintf(fp
, ",\n %s, %s", paramEnumNames
[i
], paramVal
);
1004 fprintf(fp
, ");\n");
1009 #ifndef MAX_BLOB_LENGTH
1010 #define MAX_BLOB_LENGTH 2048
1013 void IPlugBase::DumpPresetBlob(const char* filename
)
1015 FILE* fp
= fopen(filename
, "w");
1016 fprintf(fp
, "MakePresetFromBlob(\"name\", \"");
1018 char buf
[MAX_BLOB_LENGTH
];
1020 ByteChunk
* pPresetChunk
= &mPresets
.Get(mCurrentPresetIdx
)->mChunk
;
1021 BYTE
* byteStart
= pPresetChunk
->GetBytes();
1023 base64encode(byteStart
, buf
, pPresetChunk
->Size());
1025 fprintf(fp
, "%s\", %i);\n", buf
, pPresetChunk
->Size());
1029 void IPlugBase::DumpBankBlob(const char* filename
)
1031 FILE* fp
= fopen(filename
, "w");
1036 char buf
[MAX_BLOB_LENGTH
] = "";
1038 for (int i
= 0; i
< NPresets(); i
++)
1040 IPreset
* pPreset
= mPresets
.Get(i
);
1041 fprintf(fp
, "MakePresetFromBlob(\"%s\", \"", pPreset
->mName
);
1043 ByteChunk
* pPresetChunk
= &pPreset
->mChunk
;
1044 base64encode(pPresetChunk
->GetBytes(), buf
, pPresetChunk
->Size());
1046 fprintf(fp
, "%s\", %i);\n", buf
, pPresetChunk
->Size());
1052 void IPlugBase::SetInputLabel(int idx
, const char* pLabel
)
1054 if (idx
>= 0 && idx
< NInChannels())
1056 mInChannels
.Get(idx
)->mLabel
.Set(pLabel
);
1060 void IPlugBase::SetOutputLabel(int idx
, const char* pLabel
)
1062 if (idx
>= 0 && idx
< NOutChannels())
1064 mOutChannels
.Get(idx
)->mLabel
.Set(pLabel
);
1068 void IPlugBase::SetInputBusLabel(int idx
, const char* pLabel
)
1070 if (idx
>= 0 && idx
< 2) // only possible to have two input buses
1072 if (mInputBusLabels
.Get(idx
))
1074 mInputBusLabels
.Delete(idx
, true);
1077 mInputBusLabels
.Insert(idx
, new WDL_String(pLabel
, strlen(pLabel
)));
1081 void IPlugBase::SetOutputBusLabel(int idx
, const char* pLabel
)
1085 if (mOutputBusLabels
.Get(idx
))
1087 mOutputBusLabels
.Delete(idx
, true);
1090 mOutputBusLabels
.Insert(idx
, new WDL_String(pLabel
, strlen(pLabel
)));
1094 const int kFXPVersionNum
= 1;
1095 const int kFXBVersionNum
= 2;
1097 // confusing... bytechunk will force storage as little endian on big endian platforms,
1098 // so when we use it here, since vst fxp/fxb files are big endian, we need to swap the endianess
1099 // regardless of the endianness of the host, and on big endian hosts it will get swapped back to
1101 bool IPlugBase::SaveProgramAsFXP(WDL_String
* fileName
)
1103 if (fileName
->GetLength())
1105 FILE* fp
= fopen(fileName
->Get(), "wb");
1109 VstInt32 chunkMagic
= WDL_bswap32('CcnK');
1110 VstInt32 byteSize
= 0;
1112 VstInt32 fxpVersion
= WDL_bswap32(kFXPVersionNum
);
1113 VstInt32 pluginID
= WDL_bswap32(GetUniqueID());
1114 VstInt32 pluginVersion
= WDL_bswap32(GetEffectVersion(true));
1115 VstInt32 numParams
= WDL_bswap32(NParams());
1117 memset(prgName
, 0, 28);
1118 strcpy(prgName
, GetPresetName(GetCurrentPresetIdx()));
1120 pgm
.Put(&chunkMagic
);
1122 if (DoesStateChunks())
1127 fxpMagic
= WDL_bswap32('FPCh');
1129 InitChunkWithIPlugVer(&state
);
1130 SerializeState(&state
);
1132 chunkSize
= WDL_bswap32(state
.Size());
1133 byteSize
= WDL_bswap32(state
.Size() + 60);
1137 pgm
.Put(&fxpVersion
);
1139 pgm
.Put(&pluginVersion
);
1140 pgm
.Put(&numParams
);
1141 pgm
.PutBytes(prgName
, 28); // not PutStr (we want all 28 bytes)
1142 pgm
.Put(&chunkSize
);
1143 pgm
.PutBytes(state
.GetBytes(), state
.Size());
1147 fxpMagic
= WDL_bswap32('FxCk');
1148 //byteSize = WDL_bswap32(20 + 28 + (NParams() * 4) );
1151 pgm
.Put(&fxpVersion
);
1153 pgm
.Put(&pluginVersion
);
1154 pgm
.Put(&numParams
);
1155 pgm
.PutBytes(prgName
, 28); // not PutStr (we want all 28 bytes)
1157 for (int i
= 0; i
< NParams(); i
++)
1159 WDL_EndianFloat v32
;
1160 v32
.f
= (float) mParams
.Get(i
)->GetNormalized();
1161 unsigned int swapped
= WDL_bswap32(v32
.int32
);
1166 fwrite(pgm
.GetBytes(), pgm
.Size(), 1, fp
);
1174 bool IPlugBase::SaveBankAsFXB(WDL_String
* fileName
)
1176 if (fileName
->GetLength())
1178 FILE* fp
= fopen(fileName
->Get(), "wb");
1182 VstInt32 chunkMagic
= WDL_bswap32('CcnK');
1183 VstInt32 byteSize
= 0;
1185 VstInt32 fxbVersion
= WDL_bswap32(kFXBVersionNum
);
1186 VstInt32 pluginID
= WDL_bswap32(GetUniqueID());
1187 VstInt32 pluginVersion
= WDL_bswap32(GetEffectVersion(true));
1188 VstInt32 numPgms
= WDL_bswap32(NPresets());
1189 VstInt32 currentPgm
= WDL_bswap32(GetCurrentPresetIdx());
1191 memset(future
, 0, 124);
1193 bnk
.Put(&chunkMagic
);
1195 if (DoesStateChunks())
1200 fxbMagic
= WDL_bswap32('FBCh');
1202 InitChunkWithIPlugVer(&state
);
1203 SerializePresets(&state
);
1205 chunkSize
= WDL_bswap32(state
.Size());
1206 byteSize
= WDL_bswap32(160 + state
.Size() );
1210 bnk
.Put(&fxbVersion
);
1212 bnk
.Put(&pluginVersion
);
1214 bnk
.Put(¤tPgm
);
1215 bnk
.PutBytes(&future
, 124);
1217 bnk
.Put(&chunkSize
);
1218 bnk
.PutBytes(state
.GetBytes(), state
.Size());
1222 fxbMagic
= WDL_bswap32('FxBk');
1226 bnk
.Put(&fxbVersion
);
1228 bnk
.Put(&pluginVersion
);
1230 bnk
.Put(¤tPgm
);
1231 bnk
.PutBytes(&future
, 124);
1233 VstInt32 fxpMagic
= WDL_bswap32('FxCk');
1234 VstInt32 fxpVersion
= WDL_bswap32(kFXPVersionNum
);
1235 VstInt32 numParams
= WDL_bswap32(NParams());
1237 for (int p
= 0; p
< NPresets(); p
++)
1239 IPreset
* pPreset
= mPresets
.Get(p
);
1242 memset(prgName
, 0, 28);
1243 strcpy(prgName
, pPreset
->mName
);
1245 bnk
.Put(&chunkMagic
);
1246 //byteSize = WDL_bswap32(20 + 28 + (NParams() * 4) );
1249 bnk
.Put(&fxpVersion
);
1251 bnk
.Put(&pluginVersion
);
1252 bnk
.Put(&numParams
);
1253 bnk
.PutBytes(prgName
, 28);
1257 for (int i
= 0; i
< NParams(); i
++)
1260 pos
= pPreset
->mChunk
.Get(&v
, pos
);
1262 WDL_EndianFloat v32
;
1263 v32
.f
= (float) mParams
.Get(i
)->GetNormalized(v
);
1264 unsigned int swapped
= WDL_bswap32(v32
.int32
);
1270 fwrite(bnk
.GetBytes(), bnk
.Size(), 1, fp
);
1279 bool IPlugBase::LoadProgramFromFXP(WDL_String
* fileName
)
1281 if (fileName
->GetLength())
1283 FILE* fp
= fopen(fileName
->Get(), "rb");
1290 fseek(fp
, 0 , SEEK_END
);
1291 fileSize
= ftell(fp
);
1294 pgm
.Resize(fileSize
);
1295 fread(pgm
.GetBytes(), fileSize
, 1, fp
);
1301 VstInt32 chunkMagic
;
1302 VstInt32 byteSize
= 0;
1304 VstInt32 fxpVersion
;
1306 VstInt32 pluginVersion
;
1310 pos
= pgm
.Get(&chunkMagic
, pos
);
1311 chunkMagic
= WDL_bswap_if_le(chunkMagic
);
1312 pos
= pgm
.Get(&byteSize
, pos
);
1313 byteSize
= WDL_bswap_if_le(byteSize
);
1314 pos
= pgm
.Get(&fxpMagic
, pos
);
1315 fxpMagic
= WDL_bswap_if_le(fxpMagic
);
1316 pos
= pgm
.Get(&fxpVersion
, pos
);
1317 fxpVersion
= WDL_bswap_if_le(fxpVersion
);
1318 pos
= pgm
.Get(&pluginID
, pos
);
1319 pluginID
= WDL_bswap_if_le(pluginID
);
1320 pos
= pgm
.Get(&pluginVersion
, pos
);
1321 pluginVersion
= WDL_bswap_if_le(pluginVersion
);
1322 pos
= pgm
.Get(&numParams
, pos
);
1323 numParams
= WDL_bswap_if_le(numParams
);
1324 pos
= pgm
.GetBytes(prgName
, 28, pos
);
1326 if (chunkMagic
!= 'CcnK') return false;
1327 if (fxpVersion
!= kFXPVersionNum
) return false; // TODO: what if a host saves as a different version?
1328 if (pluginID
!= GetUniqueID()) return false;
1329 //if (pluginVersion != GetEffectVersion(true)) return false; // TODO: provide mechanism for loading earlier versions
1330 //if (numParams != NParams()) return false; // TODO: provide mechanism for loading earlier versions with less params
1332 if (DoesStateChunks() && fxpMagic
== 'FPCh')
1335 pos
= pgm
.Get(&chunkSize
, pos
);
1336 chunkSize
= WDL_bswap_if_le(chunkSize
);
1338 GetIPlugVerFromChunk(&pgm
, &pos
);
1339 UnserializeState(&pgm
, pos
);
1340 ModifyCurrentPreset(prgName
);
1341 RestorePreset(GetCurrentPresetIdx());
1342 InformHostOfProgramChange();
1346 else if (fxpMagic
== 'FxCk')
1348 for (int i
= 0; i
< NParams(); i
++)
1350 WDL_EndianFloat v32
;
1351 pos
= pgm
.Get(&v32
.int32
, pos
);
1352 v32
.int32
= WDL_bswap_if_le(v32
.int32
);
1353 mParams
.Get(i
)->SetNormalized((double) v32
.f
);
1356 ModifyCurrentPreset(prgName
);
1357 RestorePreset(GetCurrentPresetIdx());
1358 InformHostOfProgramChange();
1368 bool IPlugBase::LoadBankFromFXB(WDL_String
* fileName
)
1370 if (fileName
->GetLength())
1372 FILE* fp
= fopen(fileName
->Get(), "rb");
1379 fseek(fp
, 0 , SEEK_END
);
1380 fileSize
= ftell(fp
);
1383 bnk
.Resize(fileSize
);
1384 fread(bnk
.GetBytes(), fileSize
, 1, fp
);
1390 VstInt32 chunkMagic
;
1391 VstInt32 byteSize
= 0;
1393 VstInt32 fxbVersion
;
1395 VstInt32 pluginVersion
;
1397 VstInt32 currentPgm
;
1399 memset(future
, 0, 124);
1401 pos
= bnk
.Get(&chunkMagic
, pos
);
1402 chunkMagic
= WDL_bswap_if_le(chunkMagic
);
1403 pos
= bnk
.Get(&byteSize
, pos
);
1404 byteSize
= WDL_bswap_if_le(byteSize
);
1405 pos
= bnk
.Get(&fxbMagic
, pos
);
1406 fxbMagic
= WDL_bswap_if_le(fxbMagic
);
1407 pos
= bnk
.Get(&fxbVersion
, pos
);
1408 fxbVersion
= WDL_bswap_if_le(fxbVersion
);
1409 pos
= bnk
.Get(&pluginID
, pos
);
1410 pluginID
= WDL_bswap_if_le(pluginID
);
1411 pos
= bnk
.Get(&pluginVersion
, pos
);
1412 pluginVersion
= WDL_bswap_if_le(pluginVersion
);
1413 pos
= bnk
.Get(&numPgms
, pos
);
1414 numPgms
= WDL_bswap_if_le(numPgms
);
1415 pos
= bnk
.Get(¤tPgm
, pos
);
1416 currentPgm
= WDL_bswap_if_le(currentPgm
);
1417 pos
= bnk
.GetBytes(future
, 124, pos
);
1419 if (chunkMagic
!= 'CcnK') return false;
1420 //if (fxbVersion != kFXBVersionNum) return false; // TODO: what if a host saves as a different version?
1421 if (pluginID
!= GetUniqueID()) return false;
1422 //if (pluginVersion != GetEffectVersion(true)) return false; // TODO: provide mechanism for loading earlier versions
1423 //if (numPgms != NPresets()) return false; // TODO: provide mechanism for loading earlier versions with less params
1425 if (DoesStateChunks() && fxbMagic
== 'FBCh')
1428 pos
= bnk
.Get(&chunkSize
, pos
);
1429 chunkSize
= WDL_bswap_if_le(chunkSize
);
1431 GetIPlugVerFromChunk(&bnk
, &pos
);
1432 UnserializePresets(&bnk
, pos
);
1433 //RestorePreset(currentPgm);
1434 InformHostOfProgramChange();
1437 else if (fxbMagic
== 'FxBk')
1439 VstInt32 chunkMagic
;
1442 VstInt32 fxpVersion
;
1444 VstInt32 pluginVersion
;
1448 for(int i
= 0; i
<numPgms
; i
++)
1450 pos
= bnk
.Get(&chunkMagic
, pos
);
1451 chunkMagic
= WDL_bswap_if_le(chunkMagic
);
1453 pos
= bnk
.Get(&byteSize
, pos
);
1454 byteSize
= WDL_bswap_if_le(byteSize
);
1456 pos
= bnk
.Get(&fxpMagic
, pos
);
1457 fxpMagic
= WDL_bswap_if_le(fxpMagic
);
1459 pos
= bnk
.Get(&fxpVersion
, pos
);
1460 fxpVersion
= WDL_bswap_if_le(fxpVersion
);
1462 pos
= bnk
.Get(&pluginID
, pos
);
1463 pluginID
= WDL_bswap_if_le(pluginID
);
1465 pos
= bnk
.Get(&pluginVersion
, pos
);
1466 pluginVersion
= WDL_bswap_if_le(pluginVersion
);
1468 pos
= bnk
.Get(&numParams
, pos
);
1469 numParams
= WDL_bswap_if_le(numParams
);
1471 if (chunkMagic
!= 'CcnK') return false;
1472 if (fxpMagic
!= 'FxCk') return false;
1473 if (fxpVersion
!= kFXPVersionNum
) return false;
1474 if (numParams
!= NParams()) return false;
1476 pos
= bnk
.GetBytes(prgName
, 28, pos
);
1480 for (int j
= 0; j
< NParams(); j
++)
1482 WDL_EndianFloat v32
;
1483 pos
= bnk
.Get(&v32
.int32
, pos
);
1484 v32
.int32
= WDL_bswap_if_le(v32
.int32
);
1485 mParams
.Get(j
)->SetNormalized((double) v32
.f
);
1488 ModifyCurrentPreset(prgName
);
1491 RestorePreset(currentPgm
);
1492 InformHostOfProgramChange();
1502 void IPlugBase::InitChunkWithIPlugVer(ByteChunk
* pChunk
)
1505 int magic
= IPLUG_VERSION_MAGIC
;
1506 pChunk
->Put(&magic
);
1507 int ver
= IPLUG_VERSION
;
1511 int IPlugBase::GetIPlugVerFromChunk(ByteChunk
* pChunk
, int* pPos
)
1513 int magic
= 0, ver
= 0;
1514 int pos
= pChunk
->Get(&magic
, *pPos
);
1515 if (pos
> *pPos
&& magic
== IPLUG_VERSION_MAGIC
)
1517 *pPos
= pChunk
->Get(&ver
, pos
);
1522 bool IPlugBase::SendMidiMsgs(WDL_TypedBuf
<IMidiMsg
>* pMsgs
)
1525 int n
= pMsgs
->GetSize();
1526 IMidiMsg
* pMsg
= pMsgs
->Get();
1527 for (int i
= 0; i
< n
; ++i
, ++pMsg
) {
1528 rc
&= SendMidiMsg(pMsg
);