1 /*
2 * Copyright 2012, Gerasim Troeglazov (3dEyes**), 3dEyes@gmail.com.
3 * All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
6
7 #include <ByteOrder.h>
8 #include <Buffer.h>
9 #include <BufferGroup.h>
10 #include <TimeSource.h>
11 #include <ParameterWeb.h>
12 #include <String.h>
13
14 #include <stdio.h>
15 #include <string.h>
16
17 #include "VSTNode.h"
18
19 //VSTNode
~VSTNode()20 VSTNode::~VSTNode()
21 {
22 Quit();
23 }
24
VSTNode(BMediaAddOn * addon,const char * name,const char * path)25 VSTNode::VSTNode(BMediaAddOn* addon, const char* name, const char* path)
26 :
27 BMediaNode(name),
28 BBufferConsumer(B_MEDIA_RAW_AUDIO),
29 BBufferProducer(B_MEDIA_RAW_AUDIO),
30 BControllable(),
31 BMediaEventLooper(),
32 fAddOn(addon),
33 fOutputMediaEnabled(true),
34 fDownstreamLatency(0),
35 fProcessLatency(0)
36 {
37 fPlugin = new VSTPlugin();
38 fPlugin->LoadModule(path);
39 }
40
41 //BMediaNode
42 BMediaAddOn*
AddOn(int32 * id) const43 VSTNode::AddOn(int32* id) const
44 {
45 if(fAddOn)
46 *id = 0;
47 return fAddOn;
48 }
49
50 status_t
HandleMessage(int32 message,const void * data,size_t size)51 VSTNode::HandleMessage(int32 message, const void* data, size_t size)
52 {
53 if((BControllable::HandleMessage(message, data, size) != B_OK) &&
54 (BBufferConsumer::HandleMessage(message, data, size) != B_OK) &&
55 (BBufferProducer::HandleMessage(message, data, size) != B_OK) &&
56 (BControllable::HandleMessage(message, data, size) != B_OK) ) {
57 BMediaNode::HandleMessage(message, data, size);
58 return B_OK;
59 }
60 BMediaNode::HandleBadMessage(message, data, size);
61 return B_ERROR;
62 }
63
64 void
NodeRegistered()65 VSTNode::NodeRegistered()
66 {
67 fPreferredFormat.type = B_MEDIA_RAW_AUDIO;
68 fPreferredFormat.u.raw_audio.buffer_size = BUFF_SIZE;
69 fPreferredFormat.u.raw_audio = media_raw_audio_format::wildcard;
70 fPreferredFormat.u.raw_audio.channel_count =
71 media_raw_audio_format::wildcard.channel_count;
72 fPreferredFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
73
74 fFormat.type = B_MEDIA_RAW_AUDIO;
75 fFormat.u.raw_audio = media_raw_audio_format::wildcard;
76
77 fInputMedia.destination.port = ControlPort();
78 fInputMedia.destination.id = ID_AUDIO_INPUT;
79 fInputMedia.node = Node();
80 fInputMedia.source = media_source::null;
81 fInputMedia.format = fFormat;
82 strncpy(fInputMedia.name, "Audio Input", B_MEDIA_NAME_LENGTH);
83
84 fOutputMedia.source.port = ControlPort();
85 fOutputMedia.source.id = ID_AUDIO_OUTPUT;
86 fOutputMedia.node = Node();
87 fOutputMedia.destination = media_destination::null;
88 fOutputMedia.format = fFormat;
89 strncpy(fOutputMedia.name, "Audio Output", B_MEDIA_NAME_LENGTH);
90
91 InitParameterValues();
92 InitParameterWeb();
93
94 SetPriority(B_REAL_TIME_PRIORITY);
95 Run();
96 }
97
98 //BControllable
99 status_t
GetParameterValue(int32 id,bigtime_t * lastChangeTime,void * value,size_t * size)100 VSTNode::GetParameterValue(int32 id, bigtime_t* lastChangeTime, void* value,
101 size_t *size)
102 {
103 if (*size < sizeof(float) || *size < sizeof(int32))
104 return B_NO_MEMORY;
105
106 type_code v_type = B_FLOAT_TYPE;
107
108 BParameter *param;
109 for(int i = 0; i < fWeb->CountParameters(); i++) {
110 param = fWeb->ParameterAt(i);
111 if(param->ID() == id) {
112 v_type = param->ValueType();
113 break;
114 }
115 }
116
117 *size = sizeof(float);
118
119 if (id == P_MUTE) {
120 *(int32*)value = fMute;
121 *lastChangeTime = fMuteLastChanged;
122 return B_OK;
123 } else if (id == P_BYPASS) {
124 *(int32*)value = fByPass;
125 *lastChangeTime = fByPassLastChanged;
126 return B_OK;
127 } else {
128 int32 idx = id - P_PARAM;
129 if (idx >= 0 && idx < fPlugin->ParametersCount()) {
130 VSTParameter *param = fPlugin->Parameter(idx);
131
132 if (v_type == B_FLOAT_TYPE)
133 *(float*)value = param->Value();
134
135 if (v_type == B_INT32_TYPE)
136 *(int32*)value = (int32)ceil(param->Value());
137
138 *lastChangeTime = param->LastChangeTime();
139 return B_OK;
140 }
141 }
142 return B_ERROR;
143 }
144
145 void
SetParameterValue(int32 id,bigtime_t time,const void * value,size_t size)146 VSTNode::SetParameterValue(int32 id, bigtime_t time, const void* value,
147 size_t size)
148 {
149 int32 idx = id - P_PARAM;
150 if ((idx >= 0 && idx < fPlugin->ParametersCount()) || id == P_MUTE ||
151 id == P_BYPASS) {
152 media_timed_event ev(time, BTimedEventQueue::B_PARAMETER, (void*)value,
153 BTimedEventQueue::B_NO_CLEANUP, size, id, "VSTParam");
154 //dirty hack for parameter processing (mediakit bug????)
155 ParameterEventProcessing(&ev);
156 EventQueue()->AddEvent(ev);
157 }
158 }
159
160 //BBufferConsumer
161 void
BufferReceived(BBuffer * buffer)162 VSTNode::BufferReceived(BBuffer* buffer)
163 {
164 if (buffer->Header()->destination != fInputMedia.destination.id) {
165 buffer->Recycle();
166 return;
167 }
168
169 if (fOutputMedia.destination == media_destination::null ||
170 !fOutputMediaEnabled) {
171 buffer->Recycle();
172 return;
173 }
174
175 FilterBuffer(buffer);
176
177 status_t err = SendBuffer(buffer, fOutputMedia.source,
178 fOutputMedia.destination);
179
180 if (err < B_OK)
181 buffer->Recycle();
182 }
183
184 status_t
AcceptFormat(const media_destination & dst,media_format * format)185 VSTNode::AcceptFormat(const media_destination &dst, media_format* format)
186 {
187 if (dst != fInputMedia.destination)
188 return B_MEDIA_BAD_DESTINATION;
189
190 if (format->type != B_MEDIA_RAW_AUDIO)
191 return B_MEDIA_BAD_FORMAT;
192
193 ValidateFormat(
194 (fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
195 fFormat : fPreferredFormat, *format);
196
197 return B_OK;
198 }
199
200 status_t
GetNextInput(int32 * cookie,media_input * input)201 VSTNode::GetNextInput(int32* cookie, media_input* input)
202 {
203 if (*cookie)
204 return B_BAD_INDEX;
205
206 ++*cookie;
207 *input = fInputMedia;
208 return B_OK;
209 }
210
211 void
DisposeInputCookie(int32 cookie)212 VSTNode::DisposeInputCookie(int32 cookie)
213 {
214 }
215
216 status_t
FormatChanged(const media_source & src,const media_destination & dst,int32 changeTag,const media_format & format)217 VSTNode::FormatChanged(const media_source &src, const media_destination &dst,
218 int32 changeTag, const media_format &format)
219 {
220 return B_MEDIA_BAD_FORMAT;
221 }
222
223 void
ProducerDataStatus(const media_destination & dst,int32 status,bigtime_t when)224 VSTNode::ProducerDataStatus(const media_destination &dst, int32 status,
225 bigtime_t when)
226 {
227 if (fOutputMedia.destination != media_destination::null)
228 SendDataStatus(status, fOutputMedia.destination, when);
229 }
230
231 status_t
GetLatencyFor(const media_destination & dst,bigtime_t * latency,media_node_id * outTimeSource)232 VSTNode::GetLatencyFor( const media_destination &dst, bigtime_t* latency,
233 media_node_id* outTimeSource)
234 {
235 if (dst != fInputMedia.destination)
236 return B_MEDIA_BAD_DESTINATION;
237
238 *latency = fDownstreamLatency + fProcessLatency;
239 *outTimeSource = TimeSource()->ID();
240 return B_OK;
241 }
242
243 status_t
Connected(const media_source & source,const media_destination & destination,const media_format & format,media_input * input)244 VSTNode::Connected(const media_source& source,
245 const media_destination& destination, const media_format& format,
246 media_input* input)
247 {
248 if (destination != fInputMedia.destination)
249 return B_MEDIA_BAD_DESTINATION;
250
251 if (fInputMedia.source != media_source::null)
252 return B_MEDIA_ALREADY_CONNECTED;
253
254 fInputMedia.source = source;
255 fInputMedia.format = format;
256 *input = fInputMedia;
257 fFormat = format;
258
259 return B_OK;
260 }
261
262 void
Disconnected(const media_source & src,const media_destination & dst)263 VSTNode::Disconnected(const media_source &src, const media_destination &dst)
264 {
265 if(fInputMedia.source!=src || dst!=fInputMedia.destination)
266 return;
267
268 fInputMedia.source = media_source::null;
269
270 if(fOutputMedia.destination == media_destination::null)
271 fFormat.u.raw_audio = media_raw_audio_format::wildcard;
272
273 fInputMedia.format = fFormat;
274 }
275
276 //BBufferProducer
277 status_t
FormatSuggestionRequested(media_type type,int32 quality,media_format * format)278 VSTNode::FormatSuggestionRequested(media_type type, int32 quality,
279 media_format* format)
280 {
281 if (type != B_MEDIA_RAW_AUDIO)
282 return B_MEDIA_BAD_FORMAT;
283
284 if (fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format)
285 *format = fFormat;
286 else
287 *format = fPreferredFormat;
288
289 return B_OK;
290 }
291
292 status_t
FormatProposal(const media_source & src,media_format * format)293 VSTNode::FormatProposal(const media_source &src, media_format* format)
294 {
295 if (src != fOutputMedia.source)
296 return B_MEDIA_BAD_SOURCE;
297
298 if (format->type != B_MEDIA_RAW_AUDIO)
299 return B_MEDIA_BAD_FORMAT;
300
301 ValidateFormat(
302 (fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
303 fFormat : fPreferredFormat, *format);
304
305 return B_OK;
306 }
307
308 status_t
FormatChangeRequested(const media_source & src,const media_destination & dst,media_format * format,int32 * _deprecated_)309 VSTNode::FormatChangeRequested(const media_source &src,
310 const media_destination &dst, media_format* format, int32* _deprecated_)
311 {
312 return B_MEDIA_BAD_FORMAT;
313 }
314
315 void
LateNoticeReceived(const media_source & src,bigtime_t late,bigtime_t when)316 VSTNode::LateNoticeReceived(const media_source &src,
317 bigtime_t late, bigtime_t when)
318 {
319 if (src != fOutputMedia.source || fInputMedia.source == media_source::null)
320 return;
321
322 NotifyLateProducer(fInputMedia.source, late, when);
323 }
324
325 status_t
GetNextOutput(int32 * cookie,media_output * output)326 VSTNode::GetNextOutput(int32 *cookie, media_output* output)
327 {
328 if (*cookie)
329 return B_BAD_INDEX;
330
331 ++*cookie;
332 *output = fOutputMedia;
333 return B_OK;
334 }
335
336 status_t
DisposeOutputCookie(int32 cookie)337 VSTNode::DisposeOutputCookie(int32 cookie)
338 {
339 return B_OK;
340 }
341
342 status_t
SetBufferGroup(const media_source & src,BBufferGroup * group)343 VSTNode::SetBufferGroup(const media_source &src, BBufferGroup* group)
344 {
345 status_t ret;
346 int32 changeTag;
347
348 if (src != fOutputMedia.source)
349 return B_MEDIA_BAD_SOURCE;
350
351 if (fInputMedia.source == media_source::null)
352 return B_ERROR;
353
354 ret = SetOutputBuffersFor(fInputMedia.source, fInputMedia.destination,
355 group, 0, &changeTag);
356
357 return ret;
358 }
359
360 status_t
PrepareToConnect(const media_source & src,const media_destination & dst,media_format * format,media_source * out_source,char * name)361 VSTNode::PrepareToConnect( const media_source &src, const media_destination &dst,
362 media_format* format, media_source* out_source, char* name)
363 {
364 status_t ret = B_OK;
365
366 if (src != fOutputMedia.source)
367 return B_MEDIA_BAD_SOURCE;
368
369 if (format->type != B_MEDIA_RAW_AUDIO)
370 return B_MEDIA_BAD_FORMAT;
371
372 if (fOutputMedia.destination != media_destination::null)
373 return B_MEDIA_ALREADY_CONNECTED;
374
375 ret = ValidateFormat(
376 (fFormat.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
377 fFormat : fPreferredFormat, *format);
378
379 if (ret < B_OK)
380 return ret;
381
382 SetOutputFormat(*format);
383
384 fOutputMedia.destination = dst;
385 fOutputMedia.format = *format;
386
387 *out_source = fOutputMedia.source;
388 strncpy(name, fOutputMedia.name, B_MEDIA_NAME_LENGTH);
389
390 return B_OK;
391 }
392
393 void
Connect(status_t status,const media_source & src,const media_destination & dst,const media_format & format,char * name)394 VSTNode::Connect(status_t status, const media_source &src,
395 const media_destination &dst, const media_format &format, char* name)
396 {
397 if (status < B_OK) {
398 fOutputMedia.destination = media_destination::null;
399 return;
400 }
401
402 strncpy(name, fOutputMedia.name, B_MEDIA_NAME_LENGTH);
403 fOutputMedia.destination = dst;
404 fFormat = format;
405
406 media_node_id timeSource;
407 FindLatencyFor(fOutputMedia.destination, &fDownstreamLatency, &timeSource);
408
409 InitFilter();
410
411 fProcessLatency = GetFilterLatency();
412 SetEventLatency(fDownstreamLatency + fProcessLatency);
413
414 if (fInputMedia.source != media_source::null) {
415 SendLatencyChange(fInputMedia.source, fInputMedia.destination,
416 EventLatency()+SchedulingLatency());
417 }
418
419 bigtime_t duration = 0;
420
421 int sample_size = (fFormat.u.raw_audio.format & 0xf)*
422 fFormat.u.raw_audio.channel_count;
423 if (fFormat.u.raw_audio.buffer_size > 0 &&
424 fFormat.u.raw_audio.frame_rate > 0 &&
425 sample_size > 0) {
426 duration = (bigtime_t)(((fFormat.u.raw_audio.buffer_size / sample_size) /
427 fFormat.u.raw_audio.frame_rate) * 1000000.0);
428 }
429
430 SetBufferDuration(duration);
431 }
432
433 void
Disconnect(const media_source & src,const media_destination & dst)434 VSTNode::Disconnect(const media_source &src, const media_destination &dst)
435 {
436 if (src != fOutputMedia.source)
437 return;
438
439 if (dst != fOutputMedia.destination)
440 return;
441
442 fOutputMedia.destination = media_destination::null;
443
444 if (fInputMedia.source == media_source::null)
445 fFormat.u.raw_audio = media_raw_audio_format::wildcard;
446
447 fOutputMedia.format = fFormat;
448 }
449
450 void
EnableOutput(const media_source & src,bool enabled,int32 * _deprecated_)451 VSTNode::EnableOutput(const media_source &src, bool enabled, int32* _deprecated_)
452 {
453 if (src != fOutputMedia.source)
454 return;
455
456 fOutputMediaEnabled = enabled;
457 }
458
459 status_t
GetLatency(bigtime_t * latency)460 VSTNode::GetLatency(bigtime_t* latency)
461 {
462 *latency = EventLatency() + SchedulingLatency();
463 return B_OK;
464 }
465
466 void
LatencyChanged(const media_source & src,const media_destination & dst,bigtime_t latency,uint32 flags)467 VSTNode::LatencyChanged(const media_source &src, const media_destination &dst,
468 bigtime_t latency, uint32 flags)
469 {
470 if (src != fOutputMedia.source || dst != fOutputMedia.destination)
471 return;
472
473 fDownstreamLatency = latency;
474 SetEventLatency(fDownstreamLatency + fProcessLatency);
475
476 if (fInputMedia.source != media_source::null) {
477 SendLatencyChange(fInputMedia.source,
478 fInputMedia.destination,EventLatency() + SchedulingLatency());
479 }
480 }
481
482 //BMediaEventLooper
483 bigtime_t
OfflineTime()484 VSTNode::OfflineTime()
485 {
486 return 0LL;
487 }
488
489 //VSTNode
490 void
HandleEvent(const media_timed_event * event,bigtime_t late,bool realTime)491 VSTNode::HandleEvent(const media_timed_event *event, bigtime_t late,
492 bool realTime)
493 {
494 if(event->type == BTimedEventQueue::B_PARAMETER)
495 ParameterEventProcessing(event);
496 }
497
498 void
ParameterEventProcessing(const media_timed_event * event)499 VSTNode::ParameterEventProcessing(const media_timed_event* event)
500 {
501 float value = 0.0;
502 int32 value32 = 0;
503
504 int32 id = event->bigdata;
505 size_t size = event->data;
506 bigtime_t now = TimeSource()->Now();
507
508 type_code v_type = B_FLOAT_TYPE;
509
510 BParameter* web_param;
511 for(int i = 0; i < fWeb->CountParameters(); i++) {
512 web_param = fWeb->ParameterAt(i);
513 if(web_param->ID() == id) {
514 v_type = web_param->ValueType();
515 break;
516 }
517 }
518
519 if (v_type == B_FLOAT_TYPE)
520 value = *((float*)event->pointer);
521 if (v_type == B_INT32_TYPE) {
522 value32 = *((int32*)event->pointer);
523 value = (float)value32;
524 }
525
526 if (id == P_MUTE) {
527 fMute = value32;
528 fMuteLastChanged = now;
529 BroadcastNewParameterValue(now, id, event->pointer, size);
530 } else if (id == P_BYPASS) {
531 fByPass = value32;
532 fByPassLastChanged = now;
533 BroadcastNewParameterValue(now, id, event->pointer, size);
534 } else {
535 int32 idx = id - P_PARAM;
536 if (idx >= 0 && idx < fPlugin->ParametersCount()) {
537 VSTParameter *param = fPlugin->Parameter(idx);
538 param->SetValue(value);
539 BroadcastNewParameterValue(now, id, &value, size);
540 }
541 }
542 }
543
544 status_t
ValidateFormat(const media_format & preferredFormat,media_format & proposedFormat)545 VSTNode::ValidateFormat(const media_format &preferredFormat,
546 media_format &proposedFormat)
547 {
548 status_t ret = B_OK;
549
550 if (proposedFormat.type != B_MEDIA_RAW_AUDIO) {
551 proposedFormat = preferredFormat;
552 return B_MEDIA_BAD_FORMAT;
553 }
554
555 const media_raw_audio_format &wild = media_raw_audio_format::wildcard;
556 media_raw_audio_format &f = proposedFormat.u.raw_audio;
557 const media_raw_audio_format &pref = preferredFormat.u.raw_audio;
558
559 if(pref.frame_rate != wild.frame_rate && f.frame_rate != pref.frame_rate) {
560 if(f.frame_rate != wild.frame_rate)
561 ret = B_MEDIA_BAD_FORMAT;
562 f.frame_rate = pref.frame_rate;
563 }
564
565 if(pref.channel_count != wild.channel_count &&
566 f.channel_count != pref.channel_count) {
567 if(f.channel_count != wild.channel_count)
568 ret = B_MEDIA_BAD_FORMAT;
569 f.channel_count = pref.channel_count;
570 }
571
572 if(pref.format != wild.format && f.format != pref.format) {
573 if(f.format != wild.format)
574 ret = B_MEDIA_BAD_FORMAT;
575 f.format = pref.format;
576 }
577
578 if(pref.byte_order != wild.byte_order &&
579 f.byte_order != pref.byte_order) {
580 if(f.byte_order != wild.byte_order)
581 ret = B_MEDIA_BAD_FORMAT;
582 f.byte_order = pref.byte_order;
583 }
584
585 if(pref.buffer_size != wild.buffer_size &&
586 f.buffer_size != pref.buffer_size) {
587 if(f.buffer_size != wild.buffer_size)
588 ret = B_MEDIA_BAD_FORMAT;
589 f.buffer_size = pref.buffer_size;
590 }
591
592 return ret;
593 }
594
595
596 void
SetOutputFormat(media_format & format)597 VSTNode::SetOutputFormat(media_format &format)
598 {
599 media_raw_audio_format &f = format.u.raw_audio;
600 const media_raw_audio_format &w = media_raw_audio_format::wildcard;
601
602 if (f.frame_rate == w.frame_rate)
603 f.frame_rate = 44100.0;
604
605 if (f.channel_count == w.channel_count) {
606 if(fInputMedia.source != media_source::null)
607 f.channel_count = fInputMedia.format.u.raw_audio.channel_count;
608 else
609 f.channel_count = fPlugin->Channels(VST_OUTPUT_CHANNELS);
610 }
611
612 if (f.format == w.format)
613 f.format = media_raw_audio_format::B_AUDIO_FLOAT;
614
615 if (f.byte_order == w.format) {
616 f.byte_order = (B_HOST_IS_BENDIAN) ?
617 B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
618 }
619
620 if (f.buffer_size == w.buffer_size)
621 f.buffer_size = BUFF_SIZE;
622 }
623
624 void
InitParameterValues()625 VSTNode::InitParameterValues()
626 {
627 fMute = 0;
628 fByPass = 0;
629 fMuteLastChanged = 0LL;
630 fByPassLastChanged = 0LL;
631 }
632
633 void
InitParameterWeb()634 VSTNode::InitParameterWeb()
635 {
636 fWeb = new BParameterWeb();
637
638 bool switch_group_needed = false;
639 for(int i = 0; i < fPlugin->ParametersCount(); i++) {
640 VSTParameter* param = fPlugin->Parameter(i);
641 if (param->Type() == VST_PARAM_CHECKBOX ||
642 param->Type() == VST_PARAM_DROPLIST) {
643 switch_group_needed = true;
644 break;
645 }
646 }
647
648 BParameterGroup* fParamGroup = fWeb->MakeGroup("Parameters");
649 BParameterGroup* fSwitchesGroup = switch_group_needed ?
650 fWeb->MakeGroup("Switches") : NULL;
651 BParameterGroup* fAboutGroup = fWeb->MakeGroup("About");
652
653 BParameter* value;
654 BNullParameter* label;
655 BParameterGroup* group;
656
657 BParameterGroup* fFControlGroup = fParamGroup->MakeGroup("FilterControl");
658 BParameterGroup* fCheckBoxGroup = switch_group_needed ?
659 fSwitchesGroup->MakeGroup("CheckBoxes") : NULL;
660 BParameterGroup* fSelectorsGroup = switch_group_needed ?
661 fSwitchesGroup->MakeGroup("Selectors") : NULL;
662
663 fFControlGroup->MakeDiscreteParameter(P_MUTE,
664 B_MEDIA_NO_TYPE,"Mute", B_ENABLE);
665 fFControlGroup->MakeDiscreteParameter(P_BYPASS,
666 B_MEDIA_NO_TYPE,"ByPass", B_ENABLE);
667
668 for(int i = 0; i < fPlugin->ParametersCount(); i++) {
669 VSTParameter *param = fPlugin->Parameter(i);
670 switch(param->Type()) {
671 case VST_PARAM_CHECKBOX:
672 {
673 BString str;
674 str << param->Name() << " (" << param->MinimumValue()
675 << "/" << param->MaximumValue() << ")";
676 value = fCheckBoxGroup->MakeDiscreteParameter(
677 P_PARAM + param->Index(), B_MEDIA_NO_TYPE,
678 str.String(), B_ENABLE);
679 break;
680 }
681 case VST_PARAM_DROPLIST:
682 {
683 BDiscreteParameter *dvalue =
684 fSelectorsGroup->MakeDiscreteParameter(P_PARAM + param->Index(),
685 B_MEDIA_NO_TYPE, param->Name(), B_OUTPUT_MUX);
686 for(int j = 0; j < param->ListCount(); j++) {
687 dvalue->AddItem( param->ListItemAt(j)->Index,
688 param->ListItemAt(j)->Name.String());
689 }
690 break;
691 }
692 //sliders
693 default:
694 {
695 BString str;
696 group = fParamGroup->MakeGroup(param->Name());
697 label = group->MakeNullParameter(P_LABEL + param->Index(),
698 B_MEDIA_NO_TYPE, param->Name(), B_GENERIC);
699
700 str.SetTo(param->MaximumValue());
701 str << " " << param->Unit();
702
703 group->MakeNullParameter(P_LABEL2 + param->Index(),
704 B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
705 value = group->MakeContinuousParameter(P_PARAM + param->Index(),
706 B_MEDIA_NO_TYPE, "", B_GAIN, "", 0.0, 1.0, 0.01);
707 label->AddOutput(value);
708 value->AddInput(label);
709
710 str.SetTo(param->MinimumValue());
711 str << " " << param->Unit();
712
713 group->MakeNullParameter(P_LABEL3 + param->Index(),
714 B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
715 break;
716 }
717 }
718 }
719
720 BString str("About plugin");
721 label = fAboutGroup->MakeNullParameter(P_ABOUT + 0,
722 B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
723
724 str.SetTo("Effect name: ");
725 if (strlen(fPlugin->EffectName()) != 0)
726 str.Append(fPlugin->EffectName());
727 else
728 str.Append("not specified");
729
730 label = fAboutGroup->MakeNullParameter(P_ABOUT + 1,
731 B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
732
733 str.SetTo("Vendor: ");
734 if (strlen(fPlugin->Vendor()) != 0)
735 str.Append(fPlugin->Vendor());
736 else
737 str.Append("not specified");
738
739 label = fAboutGroup->MakeNullParameter(P_ABOUT + 2,
740 B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
741
742 str.SetTo("Product: ");
743 if (strlen(fPlugin->Product()) != 0)
744 str.Append(fPlugin->Product());
745 else
746 str.Append("not specified");
747
748 label = fAboutGroup->MakeNullParameter(P_ABOUT + 3,
749 B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
750
751 str.SetTo("Input Channels: ");
752 str<<fPlugin->Channels(VST_INPUT_CHANNELS);
753 label = fAboutGroup->MakeNullParameter(P_ABOUT + 4,
754 B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
755
756 str.SetTo("Output Channels: ");
757 str<<fPlugin->Channels(VST_OUTPUT_CHANNELS);
758 label = fAboutGroup->MakeNullParameter(P_ABOUT + 5,
759 B_MEDIA_NO_TYPE, str.String(), B_GENERIC);
760
761 SetParameterWeb(fWeb);
762 }
763
764 void
InitFilter()765 VSTNode::InitFilter()
766 {
767 fBlockSize = fFormat.u.raw_audio.buffer_size /
768 (fFormat.u.raw_audio.channel_count * sizeof(float));
769
770 fPlugin->SetBlockSize(fBlockSize);
771 fPlugin->SetSampleRate(fFormat.u.raw_audio.frame_rate);
772 }
773
774 bigtime_t
GetFilterLatency()775 VSTNode::GetFilterLatency()
776 {
777 if (fOutputMedia.destination == media_destination::null)
778 return 0LL;
779
780 BBufferGroup* temp_group =
781 new BBufferGroup(fOutputMedia.format.u.raw_audio.buffer_size, 1);
782
783 BBuffer *buffer =
784 temp_group->RequestBuffer(fOutputMedia.format.u.raw_audio.buffer_size);
785 buffer->Header()->type = B_MEDIA_RAW_AUDIO;
786 buffer->Header()->size_used = fOutputMedia.format.u.raw_audio.buffer_size;
787
788 bigtime_t begin = system_time();
789 FilterBuffer(buffer);
790 bigtime_t latency = system_time()-begin;
791
792 InitFilter();
793
794 buffer->Recycle();
795 delete temp_group;
796
797 return latency;
798 }
799
800 void
FilterBuffer(BBuffer * buffer)801 VSTNode::FilterBuffer(BBuffer* buffer)
802 {
803 uint32 m_frameSize = (fFormat.u.raw_audio.format & 0x0f)*
804 fFormat.u.raw_audio.channel_count;
805 uint32 samples = buffer->Header()->size_used / m_frameSize;
806 uint32 channels = fFormat.u.raw_audio.channel_count;
807
808 if (fMute != 0) {
809 memset(buffer->Data(), 0, buffer->Header()->size_used);
810 } else {
811 if (fByPass == 0) {
812 fPlugin->Process((float*)buffer->Data(), samples, channels);
813 }
814 }
815 }
816