2 * Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com.
4 * Distributed under the terms of the MIT License.
11 #include <Application.h>
15 static int32
VHostCallback(VSTEffect
* effect
, int32 opcode
, int32 index
,
16 int32 value
, void* ptr
, float opt
);
20 TrimString(BString
*string
) {
21 char* str
= string
->LockBuffer(256);
24 for(i
=0; str
[i
]!='\0';) {
25 if (isspace(str
[i
])) {
27 for(uint32 j
= i
; j
< strlen(str
) - 1; j
++)
29 str
[strlen(str
) - 1] = '\0';
34 string
->UnlockBuffer();
38 VSTParameter::VSTParameter(VSTPlugin
* plugin
, int index
)
41 fEffect
= plugin
->Effect();
42 fDropList
.MakeEmpty();
47 fEffect
->dispatcher(fEffect
, VST_GET_PARAM_NAME
, index
, 0, temp
, 0);
50 //get parameter label (unit)
52 fEffect
->dispatcher(fEffect
, VST_GET_PARAM_UNIT
, index
, 0, temp
, 0);
54 ValidateValues(&fUnit
);
56 float val
= fEffect
->getParameter(fEffect
, index
);
57 //test for minimum value
58 fEffect
->setParameter(fEffect
, index
, 0);
60 fEffect
->dispatcher(fEffect
, VST_GET_PARAM_STR
, index
, 0, temp
, 0);
61 fMinValue
.SetTo(temp
);
62 ValidateValues(&fMinValue
);
63 //test for maximum value
65 fEffect
->setParameter(fEffect
, index
, 1.0);
66 fEffect
->dispatcher(fEffect
, VST_GET_PARAM_STR
, index
, 0, temp
, 0);
67 fMaxValue
.SetTo(temp
);
68 ValidateValues(&fMaxValue
);
69 //test for discrete values
70 char test_disp
[VST_PARAM_TEST_COUNT
][256];
71 float test_values
[VST_PARAM_TEST_COUNT
];
72 float delta
= 1.0 / (float)VST_PARAM_TEST_COUNT
;
74 for(int tst_val
= 0; tst_val
< VST_PARAM_TEST_COUNT
; tst_val
++) {
75 float v
= (float)tst_val
/ (float)VST_PARAM_TEST_COUNT
;
77 if (tst_val
>= VST_PARAM_TEST_COUNT
- 1)
80 fEffect
->setParameter(fEffect
, index
, v
);
82 float new_value
= fEffect
->getParameter(fEffect
, index
);
84 for(int i
= 0; i
< test_cnt
; i
++) {
85 if (fabs(test_values
[i
] - new_value
) < delta
) {
90 if (valtest
== false) {
91 test_values
[test_cnt
] = new_value
;
92 fEffect
->dispatcher(fEffect
, VST_GET_PARAM_STR
, index
,
93 0, test_disp
[test_cnt
], 0);
99 fEffect
->setParameter(fEffect
, index
, val
);
103 fType
= VST_PARAM_CHECKBOX
;
105 DropListValue
* min_item
= new DropListValue();
106 min_item
->Value
= 0.0;
108 min_item
->Name
= fMinValue
;
109 fDropList
.AddItem(min_item
);
111 DropListValue
* max_item
= new DropListValue();
112 max_item
->Value
= 1.0;
114 max_item
->Name
= fMaxValue
;
115 fDropList
.AddItem(max_item
);
116 } else if (test_cnt
> 2 && test_cnt
< VST_PARAM_TEST_COUNT
/ 2) {
117 fType
= VST_PARAM_DROPLIST
;
119 for(int i
= 0; i
< test_cnt
; i
++) {
120 DropListValue
* item
= new DropListValue();
121 item
->Value
= test_values
[i
];
123 item
->Name
= test_disp
[i
];
124 fDropList
.AddItem(item
);
127 fType
= VST_PARAM_SLIDER
;
132 VSTParameter::~VSTParameter()
137 VSTParameter::ValidateValues(BString
* string
)
139 if (string
->Length() == 0)
144 const char *ptr
= string
->String();
145 for(; *ptr
!=0; ptr
++) {
147 if (!((ch
>= '0' && ch
<= '9') || ch
== '.' || ch
== '-')) {
154 float val
= atof(string
->String());
156 if (val
<= -pow(2, 31)) {
158 } else if (val
>= pow(2, 31)) {
162 sprintf(temp
, "%g", val
);
167 if (*string
== "oo" || *string
== "inf")
169 if (*string
== "-oo" || *string
== "-inf")
177 VSTParameter::ListCount(void)
179 return fDropList
.CountItems();
183 VSTParameter::ListItemAt(int index
)
185 DropListValue
* item
= NULL
;
186 if (index
>= 0 && index
< fDropList
.CountItems())
187 item
= (DropListValue
*)fDropList
.ItemAt(index
);
193 VSTParameter::Value()
195 float value
= fEffect
->getParameter(fEffect
, fIndex
);
196 if (fType
== VST_PARAM_DROPLIST
) {
197 //scan for near value
199 float min_delta
= 1.0;
200 for(int i
= 0; i
< fDropList
.CountItems(); i
++) {
201 DropListValue
* item
= (DropListValue
*)fDropList
.ItemAt(i
);
202 float delta
= fabs(item
->Value
- value
);
203 if (delta
<= min_delta
) {
215 VSTParameter::SetValue(float value
)
217 if (value
== fLastValue
)
220 if (fType
== VST_PARAM_DROPLIST
) {
221 //take value by index
222 int index
= (int)round(value
);
223 if (index
>= 0 && index
< fDropList
.CountItems()) {
224 DropListValue
*item
= (DropListValue
*)fDropList
.ItemAt(index
);
233 fChanged
= system_time();
234 fEffect
->setParameter(fEffect
, fIndex
, value
);
238 VSTParameter::LastChangeTime(void)
244 VSTParameter::MinimumValue(void)
246 return fMinValue
.String();
250 VSTParameter::MaximumValue(void)
252 return fMaxValue
.String();
256 VSTParameter::Unit(void)
258 return fUnit
.String();
262 VSTParameter::Index(void)
268 VSTParameter::Type(void)
274 VSTParameter::Name(void)
276 return fName
.String();
280 VSTPlugin::VSTPlugin()
287 fSampleRate
= 44100.f
;
291 fParameters
.MakeEmpty();
294 VSTPlugin::~VSTPlugin()
296 fParameters
.MakeEmpty();
301 VSTPlugin::LoadModule(const char *path
)
303 char effectName
[256] = {0};
304 char vendorString
[256] = {0};
305 char productString
[256] = {0};
308 return VST_ERR_ALREADY_LOADED
;
312 fModule
= load_add_on(path
);
314 return VST_ERR_NOT_LOADED
;
316 if (get_image_symbol(fModule
, "main_plugin", B_SYMBOL_TYPE_TEXT
,
317 (void**)&VSTMainProc
) != B_OK
) {
318 unload_add_on(fModule
);
319 return VST_ERR_NO_MAINPROC
;
322 fEffect
= VSTMainProc(VHostCallback
);
324 unload_add_on(fModule
);
325 return VST_ERR_NOT_LOADED
;
328 fEffect
->dispatcher(fEffect
, VST_OPEN
, 0, 0, 0, 0);
330 fEffect
->dispatcher(fEffect
, VST_GET_EFFECT_NAME
, 0, 0, effectName
, 0);
331 fEffectName
.SetTo(effectName
);
332 TrimString(&fEffectName
);
334 fModuleName
.SetTo("VST:");
335 fModuleName
.Append(fPath
.Leaf());
337 fEffect
->dispatcher(fEffect
, VST_GET_VENDOR_STR
, 0, 0, vendorString
, 0);
338 fVendorString
.SetTo(vendorString
);
339 TrimString(&fVendorString
);
341 fEffect
->dispatcher(fEffect
, VST_GET_PRODUCT_STR
, 0, 0, productString
, 0);
342 fProductString
.SetTo(productString
);
343 TrimString(&fProductString
);
345 fInputChannels
= fEffect
->numInputs
;
346 fOutputChannels
= fEffect
->numOutputs
;
348 for(int i
=0; i
< fEffect
->numParams
; i
++) {
349 VSTParameter
*param
= new VSTParameter(this, i
);
350 fParameters
.AddItem(param
);
353 fEffect
->dispatcher(fEffect
, VST_STATE_CHANGED
, 0, 1, 0, 0);
362 VSTPlugin::UnLoadModule(void)
364 if (!fActive
|| fModule
<= 0)
365 return VST_ERR_NOT_LOADED
;
367 fEffect
->dispatcher(fEffect
, VST_STATE_CHANGED
, 0, 0, 0, 0);
368 fEffect
->dispatcher(fEffect
, VST_CLOSE
, 0, 0, 0, 0);
370 unload_add_on(fModule
);
376 VSTPlugin::Channels(int mode
)
379 case VST_INPUT_CHANNELS
:
380 return fInputChannels
;
381 case VST_OUTPUT_CHANNELS
:
382 return fOutputChannels
;
389 VSTPlugin::SetSampleRate(float rate
)
392 fEffect
->dispatcher(fEffect
, VST_SET_SAMPLE_RATE
, 0, 0, 0, rate
);
397 VSTPlugin::SampleRate(void)
403 VSTPlugin::SetBlockSize(size_t size
)
406 fEffect
->dispatcher(fEffect
, VST_SET_BLOCK_SIZE
, 0, size
, 0, 0);
412 VSTPlugin::Path(void)
418 VSTPlugin::ReAllocBuffers(void)
420 if (inputs
!= NULL
) {
421 for(int32 i
= 0; i
< fInputChannels
; i
++)
425 if (outputs
!= NULL
) {
426 for(int32 i
= 0; i
< fOutputChannels
; i
++)
430 if (fInputChannels
> 0) {
431 inputs
= new float*[fInputChannels
];
432 for(int32 i
= 0; i
< fInputChannels
; i
++) {
433 inputs
[i
] = new float[fBlockSize
];
434 memset(inputs
[i
], 0, fBlockSize
* sizeof(float));
438 if (fOutputChannels
> 0) {
439 outputs
= new float*[fOutputChannels
];
440 for(int32_t i
= 0; i
< fOutputChannels
; i
++) {
441 outputs
[i
] = new float[fBlockSize
];
442 memset (outputs
[i
], 0, fBlockSize
* sizeof(float));
449 VSTPlugin::BlockSize(void)
455 VSTPlugin::ParametersCount(void)
457 return fParameters
.CountItems();
461 VSTPlugin::Parameter(int index
)
463 VSTParameter
* param
= NULL
;
465 if (index
>= 0 && index
< fParameters
.CountItems())
466 param
= (VSTParameter
*)fParameters
.ItemAt(index
);
472 VSTPlugin::Effect(void)
478 VSTPlugin::EffectName(void)
480 return fEffectName
.String();
484 VSTPlugin::ModuleName(void)
486 return fModuleName
.String();
490 VSTPlugin::Vendor(void)
492 return fVendorString
.String();
496 VSTPlugin::Product(void)
498 return fProductString
.String();
503 VSTPlugin::Process(float *buffer
, int samples
, int channels
)
505 //todo: full channels remapping needed
508 if (channels
== fInputChannels
) { //channel to channel
509 for(int j
= 0; j
< samples
; j
++) {
510 for(int c
= 0; c
< fInputChannels
; c
++)
511 inputs
[c
][j
] = *src
++;
513 } else if ( channels
== 1) { //from mone to multichannel
514 for(int j
= 0; j
< samples
; j
++, src
++) {
515 for(int c
= 0; c
< fInputChannels
; c
++)
520 fEffect
->processReplacing(fEffect
, inputs
, outputs
, fBlockSize
);
524 if (channels
== fOutputChannels
) { //channel to channel
525 for(int j
= 0; j
< samples
; j
++) {
526 for(int c
= 0; c
< fOutputChannels
; c
++)
527 *dst
++ = outputs
[c
][j
];
529 } else if (channels
== 1) { //from multichannel to mono
530 for(int j
= 0; j
< samples
; j
++, dst
++) {
532 for(int c
= 0; c
< fOutputChannels
; c
++)
533 mix
+= outputs
[c
][j
];
534 *dst
= mix
/ (float)fOutputChannels
;
540 VHostCallback(VSTEffect
* effect
, int32 opcode
, int32 index
, int32 value
,
541 void* ptr
, float opt
)
547 case VST_MASTER_PRODUCT
:
549 strcpy((char*)ptr
, "VSTHost Media AddOn");
553 case VST_MASTER_VERSION
: