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 20 VSTNode::~VSTNode() 21 { 22 Quit(); 23 } 24 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* 43 VSTNode::AddOn(int32* id) const 44 { 45 if(fAddOn) 46 *id = 0; 47 return fAddOn; 48 } 49 50 status_t 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 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 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 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 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 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 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 212 VSTNode::DisposeInputCookie(int32 cookie) 213 { 214 } 215 216 status_t 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 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 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 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 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 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 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 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 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 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 337 VSTNode::DisposeOutputCookie(int32 cookie) 338 { 339 return B_OK; 340 } 341 342 status_t 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 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 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 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 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 460 VSTNode::GetLatency(bigtime_t* latency) 461 { 462 *latency = EventLatency() + SchedulingLatency(); 463 return B_OK; 464 } 465 466 void 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 484 VSTNode::OfflineTime() 485 { 486 return 0LL; 487 } 488 489 //VSTNode 490 void 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 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 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 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 625 VSTNode::InitParameterValues() 626 { 627 fMute = 0; 628 fByPass = 0; 629 fMuteLastChanged = 0LL; 630 fByPassLastChanged = 0LL; 631 } 632 633 void 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 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 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 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