BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / add-ons / media / media-add-ons / vst_host / VSTHost.cpp
blob26262261313023e2189cc0b8ac6d95a84b851956
1 /*
2 * Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com.
3 * All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <image.h>
11 #include <Application.h>
13 #include "VSTHost.h"
15 static int32 VHostCallback(VSTEffect* effect, int32 opcode, int32 index,
16 int32 value, void* ptr, float opt);
18 //Trim string
19 static void
20 TrimString(BString *string) {
21 char* str = string->LockBuffer(256);
22 uint32 k = 0;
23 uint32 i = 0;
24 for(i=0; str[i]!='\0';) {
25 if (isspace(str[i])) {
26 k = i;
27 for(uint32 j = i; j < strlen(str) - 1; j++)
28 str[j] = str[j + 1];
29 str[strlen(str) - 1] = '\0';
30 i = k;
31 } else
32 i++;
34 string->UnlockBuffer();
37 //VST Parameter class
38 VSTParameter::VSTParameter(VSTPlugin* plugin, int index)
40 fIndex = index;
41 fEffect = plugin->Effect();
42 fDropList.MakeEmpty();
44 char temp[256];
45 //get parameter name
46 temp[0] = 0;
47 fEffect->dispatcher(fEffect, VST_GET_PARAM_NAME, index, 0, temp, 0);
48 fName.SetTo(temp);
49 TrimString(&fName);
50 //get parameter label (unit)
51 temp[0] = 0;
52 fEffect->dispatcher(fEffect, VST_GET_PARAM_UNIT, index, 0, temp, 0);
53 fUnit.SetTo(temp);
54 ValidateValues(&fUnit);
55 //store current value
56 float val = fEffect->getParameter(fEffect, index);
57 //test for minimum value
58 fEffect->setParameter(fEffect, index, 0);
59 temp[0] = 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
64 temp[0] = 0;
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;
73 int test_cnt = 0;
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)
78 v = 1.0;
80 fEffect->setParameter(fEffect, index, v);
82 float new_value = fEffect->getParameter(fEffect, index);
83 bool valtest = false;
84 for(int i = 0; i < test_cnt; i++) {
85 if (fabs(test_values[i] - new_value) < delta) {
86 valtest = true;
87 break;
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);
94 test_cnt++;
98 //restore value
99 fEffect->setParameter(fEffect, index, val);
101 //detect param type
102 if (test_cnt == 2) {
103 fType = VST_PARAM_CHECKBOX;
105 DropListValue* min_item = new DropListValue();
106 min_item->Value = 0.0;
107 min_item->Index = 0;
108 min_item->Name = fMinValue;
109 fDropList.AddItem(min_item);
111 DropListValue* max_item = new DropListValue();
112 max_item->Value = 1.0;
113 max_item->Index = 1;
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];
122 item->Index = i;
123 item->Name = test_disp[i];
124 fDropList.AddItem(item);
126 } else {
127 fType = VST_PARAM_SLIDER;
129 fChanged = 0LL;
132 VSTParameter::~VSTParameter()
136 BString*
137 VSTParameter::ValidateValues(BString* string)
139 if (string->Length() == 0)
140 return string;
142 bool isNum = true;
144 const char *ptr = string->String();
145 for(; *ptr!=0; ptr++) {
146 char ch = *ptr;
147 if (!((ch >= '0' && ch <= '9') || ch == '.' || ch == '-')) {
148 isNum = false;
149 break;
153 if (isNum) {
154 float val = atof(string->String());
156 if (val <= -pow(2, 31)) {
157 string->SetTo("-∞");
158 } else if (val >= pow(2, 31)) {
159 string->SetTo("∞");
160 } else {
161 char temp[256];
162 sprintf(temp, "%g", val);
163 string->SetTo(temp);
165 } else {
166 TrimString(string);
167 if (*string == "oo" || *string == "inf")
168 string->SetTo("∞");
169 if (*string == "-oo" || *string == "-inf")
170 string->SetTo("-∞");
173 return string;
177 VSTParameter::ListCount(void)
179 return fDropList.CountItems();
182 DropListValue*
183 VSTParameter::ListItemAt(int index)
185 DropListValue* item = NULL;
186 if (index >= 0 && index < fDropList.CountItems())
187 item = (DropListValue*)fDropList.ItemAt(index);
188 return item;
192 float
193 VSTParameter::Value()
195 float value = fEffect->getParameter(fEffect, fIndex);
196 if (fType == VST_PARAM_DROPLIST) {
197 //scan for near value
198 int min_index = 0;
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) {
204 min_delta = delta;
205 min_index = i;
208 value = min_index;
210 fLastValue = value;
211 return value;
214 void
215 VSTParameter::SetValue(float value)
217 if (value == fLastValue)
218 return;
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);
225 value = item->Value;
226 fLastValue = index;
227 } else {
228 return;
230 } else {
231 fLastValue = value;
233 fChanged = system_time();
234 fEffect->setParameter(fEffect, fIndex, value);
237 bigtime_t
238 VSTParameter::LastChangeTime(void)
240 return fChanged;
243 const char*
244 VSTParameter::MinimumValue(void)
246 return fMinValue.String();
249 const char*
250 VSTParameter::MaximumValue(void)
252 return fMaxValue.String();
255 const char*
256 VSTParameter::Unit(void)
258 return fUnit.String();
262 VSTParameter::Index(void)
264 return fIndex;
268 VSTParameter::Type(void)
270 return fType;
273 const char*
274 VSTParameter::Name(void)
276 return fName.String();
279 //VST Plugin class
280 VSTPlugin::VSTPlugin()
282 fActive = false;
283 fEffect = NULL;
284 VSTMainProc = NULL;
285 fInputChannels = 0;
286 fOutputChannels = 0;
287 fSampleRate = 44100.f;
288 fBlockSize = 0;
289 inputs = NULL;
290 outputs = NULL;
291 fParameters.MakeEmpty();
294 VSTPlugin::~VSTPlugin()
296 fParameters.MakeEmpty();
297 UnLoadModule();
301 VSTPlugin::LoadModule(const char *path)
303 char effectName[256] = {0};
304 char vendorString[256] = {0};
305 char productString[256] = {0};
307 if (fActive)
308 return VST_ERR_ALREADY_LOADED;
310 fPath = BPath(path);
312 fModule = load_add_on(path);
313 if (fModule <= 0)
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);
323 if (fEffect==NULL) {
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);
355 ReAllocBuffers();
357 fActive = true;
358 return B_OK;
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);
372 return B_OK;
376 VSTPlugin::Channels(int mode)
378 switch(mode) {
379 case VST_INPUT_CHANNELS:
380 return fInputChannels;
381 case VST_OUTPUT_CHANNELS:
382 return fOutputChannels;
383 default:
384 return 0;
389 VSTPlugin::SetSampleRate(float rate)
391 fSampleRate = rate;
392 fEffect->dispatcher(fEffect, VST_SET_SAMPLE_RATE, 0, 0, 0, rate);
393 return B_OK;
396 float
397 VSTPlugin::SampleRate(void)
399 return fSampleRate;
403 VSTPlugin::SetBlockSize(size_t size)
405 fBlockSize = size;
406 fEffect->dispatcher(fEffect, VST_SET_BLOCK_SIZE, 0, size, 0, 0);
407 ReAllocBuffers();
408 return B_OK;
411 const char*
412 VSTPlugin::Path(void)
414 return fPath.Path();
418 VSTPlugin::ReAllocBuffers(void)
420 if (inputs != NULL) {
421 for(int32 i = 0; i < fInputChannels; i++)
422 delete inputs[i];
425 if (outputs != NULL) {
426 for(int32 i = 0; i < fOutputChannels; i++)
427 delete outputs[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));
445 return B_OK;
448 size_t
449 VSTPlugin::BlockSize(void)
451 return fBlockSize;
455 VSTPlugin::ParametersCount(void)
457 return fParameters.CountItems();
460 VSTParameter*
461 VSTPlugin::Parameter(int index)
463 VSTParameter* param = NULL;
465 if (index >= 0 && index < fParameters.CountItems())
466 param = (VSTParameter*)fParameters.ItemAt(index);
468 return param;
471 VSTEffect*
472 VSTPlugin::Effect(void)
474 return fEffect;
477 const char*
478 VSTPlugin::EffectName(void)
480 return fEffectName.String();
483 const char*
484 VSTPlugin::ModuleName(void)
486 return fModuleName.String();
489 const char*
490 VSTPlugin::Vendor(void)
492 return fVendorString.String();
495 const char*
496 VSTPlugin::Product(void)
498 return fProductString.String();
502 void
503 VSTPlugin::Process(float *buffer, int samples, int channels)
505 //todo: full channels remapping needed
506 float* src = buffer;
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++)
516 inputs[c][j] = *src;
520 fEffect->processReplacing(fEffect, inputs, outputs, fBlockSize);
522 float* dst = buffer;
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++) {
531 float mix = 0;
532 for(int c = 0; c < fOutputChannels; c++)
533 mix += outputs[c][j];
534 *dst = mix / (float)fOutputChannels;
539 static int32
540 VHostCallback(VSTEffect* effect, int32 opcode, int32 index, int32 value,
541 void* ptr, float opt)
543 intptr_t result = 0;
545 switch(opcode)
547 case VST_MASTER_PRODUCT:
548 if (ptr) {
549 strcpy((char*)ptr, "VSTHost Media AddOn");
550 result = 1;
552 break;
553 case VST_MASTER_VERSION :
554 result = 2300;
555 break;
558 return result;