1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 08 янв. 2016 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #ifndef CONTAINER_VST_WRAPPER_H_ 23 #define CONTAINER_VST_WRAPPER_H_ 24 25 #include <container/vst/defs.h> 26 #include <container/vst/chunk.h> 27 #include <core/ipc/NativeExecutor.h> 28 29 #ifndef LSP_NO_VST_UI 30 #define IF_VST_UI_ON(...) __VA_ARGS__ 31 #else 32 #define IF_VST_UI_ON(...) 33 #endif 34 35 namespace lsp 36 { 37 class VSTAudioPort; 38 class VSTParameterPort; 39 class VSTPort; 40 class VSTUIPort; 41 42 class VSTWrapper: public IWrapper IF_VST_UI_ON(, public IUIWrapper) 43 { 44 private: 45 AEffect *pEffect; 46 audioMasterCallback pMaster; 47 ipc::IExecutor *pExecutor; 48 vst_chunk_t sChunk; 49 bool bUpdateSettings; 50 float fLatency; 51 volatile atomic_t nDumpReq; 52 atomic_t nDumpResp; 53 VSTPort *pBypass; 54 55 cvector<VSTAudioPort> vInputs; // List of input audio ports 56 cvector<VSTAudioPort> vOutputs; // List of output audio ports 57 cvector<VSTParameterPort> vParams; // List of controllable parameters 58 cvector<VSTPort> vPorts; // List of all created VST ports 59 cvector<VSTPort> vProxyPorts; // List of all created VST proxy ports 60 cvector<port_t> vGenMetadata; // Generated metadata 61 62 position_t sPosition; 63 64 KVTStorage sKVT; 65 ipc::Mutex sKVTMutex; 66 67 IF_VST_UI_ON( 68 plugin_ui *pUI; 69 ERect sRect; 70 cvector<VSTUIPort> vUIPorts; // List of all created UI ports 71 ) 72 73 private: 74 IF_VST_UI_ON( 75 void transfer_dsp_to_ui(); 76 ) 77 78 VSTPort *create_port(const port_t *port, const char *postfix); 79 VSTPort *find_by_id(const char *id); 80 void create_ports(const port_t *meta); 81 82 protected: 83 IF_VST_UI_ON( 84 static status_t slot_ui_resize(LSPWidget *sender, void *ptr, void *data); 85 ) 86 87 status_t check_vst_bank_header(const fxBank *bank, size_t size); 88 status_t check_vst_program_header(const fxProgram *prog, size_t size); 89 void deserialize_v1(const fxBank *bank); 90 void deserialize_v2_v3(const uint8_t *data, size_t bytes); 91 void deserialize_new_chunk_format(const uint8_t *data, size_t bytes); 92 void sync_position(); 93 status_t serialize_port_data(); 94 95 public: VSTWrapper(AEffect * effect,plugin_t * plugin,const char * name,audioMasterCallback callback)96 VSTWrapper( 97 AEffect *effect, 98 plugin_t *plugin, 99 const char *name, 100 audioMasterCallback callback 101 ): IWrapper(plugin) 102 { 103 pPlugin = plugin; 104 pEffect = effect; 105 106 pMaster = callback; 107 pExecutor = NULL; 108 109 fLatency = 0.0f; 110 nDumpReq = 0; 111 nDumpResp = 0; 112 pBypass = NULL; 113 bUpdateSettings = true; 114 115 IF_VST_UI_ON( 116 pUI = NULL; 117 sRect.top = 0; 118 sRect.left = 0; 119 sRect.bottom = 0; 120 sRect.right = 0; 121 ) 122 123 position_t::init(&sPosition); 124 } 125 ~VSTWrapper()126 virtual ~VSTWrapper() 127 { 128 pPlugin = NULL; 129 pEffect = NULL; 130 IF_VST_UI_ON( 131 pUI = NULL; 132 ) 133 134 pMaster = NULL; 135 } 136 137 public: get_metadata()138 inline const plugin_metadata_t *get_metadata() const { return pPlugin->get_metadata(); }; get_parameter(size_t index)139 inline VSTParameterPort *get_parameter(size_t index) { return vParams[index]; }; 140 141 void init(); 142 void destroy(); open()143 inline void open() { }; 144 void run(float** inputs, float** outputs, size_t samples); 145 void run_legacy(float** inputs, float** outputs, size_t samples); 146 void process_events(const VstEvents *e); 147 set_sample_rate(float sr)148 inline void set_sample_rate(float sr) 149 { 150 if (sr > MAX_SAMPLE_RATE) 151 { 152 lsp_warn("Unsupported sample rate: %f, maximum supported sample rate is %ld", sr, long(MAX_SAMPLE_RATE)); 153 sr = MAX_SAMPLE_RATE; 154 } 155 pPlugin->set_sample_rate(sr); 156 bUpdateSettings = true; 157 } 158 159 inline void set_block_size(size_t size); 160 mains_changed(VstIntPtr value)161 inline void mains_changed(VstIntPtr value) 162 { 163 if (value) 164 pPlugin->activate(); 165 else 166 pPlugin->deactivate(); 167 } 168 169 #ifndef LSP_NO_VST_UI 170 bool show_ui(void *root_widget); 171 void hide_ui(); 172 void iterate_ui(); 173 void destroy_ui(); 174 void resize_ui(const realize_t *r); 175 ERect *get_ui_rect(); 176 #endif 177 has_bypass()178 inline bool has_bypass() const 179 { 180 return pBypass != NULL; 181 } 182 183 inline void set_bypass(bool bypass); 184 get_executor()185 virtual ipc::IExecutor *get_executor() 186 { 187 lsp_trace("executor = %p", reinterpret_cast<void *>(pExecutor)); 188 if (pExecutor != NULL) 189 return pExecutor; 190 191 lsp_trace("Creating native executor service"); 192 ipc::NativeExecutor *exec = new ipc::NativeExecutor(); 193 if (exec == NULL) 194 return NULL; 195 if (exec->start() != STATUS_OK) 196 { 197 delete exec; 198 return NULL; 199 } 200 return pExecutor = exec; 201 } 202 position()203 virtual const position_t *position() 204 { 205 return &sPosition; 206 } 207 208 virtual ICanvas *create_canvas(ICanvas *&cv, size_t width, size_t height); 209 210 size_t serialize_state(const void **dst, bool program); 211 void deserialize_state(const void *data, size_t size); 212 213 /** 214 * Lock KVT storage 215 * @return pointer to locked storage or NULL 216 */ 217 virtual KVTStorage *kvt_lock(); 218 219 /** 220 * Try to lock KVT storage and return pointer to the storage on success 221 * @return pointer to KVT storage or NULL 222 */ 223 virtual KVTStorage *kvt_trylock(); 224 225 /** 226 * Release the KVT storage 227 * @return true on success 228 */ 229 virtual bool kvt_release(); 230 231 /** 232 * Request for state dump 233 */ 234 virtual void dump_state_request(); 235 }; 236 } 237 238 // Here Port description should be included 239 #include <container/vst/ports.h> 240 #ifndef LSP_NO_VST_UI 241 #include <container/vst/ui_ports.h> 242 #endif 243 244 namespace lsp 245 { create_port(const port_t * port,const char * postfix)246 VSTPort *VSTWrapper::create_port(const port_t *port, const char *postfix) 247 { 248 VSTPort *vp = NULL; 249 IF_VST_UI_ON(VSTUIPort *vup = NULL;) 250 251 switch (port->role) 252 { 253 case R_MESH: 254 vp = new VSTMeshPort(port, pEffect, pMaster); 255 IF_VST_UI_ON(vup = new VSTUIMeshPort(port, vp);) 256 break; 257 258 case R_STREAM: 259 vp = new VSTStreamPort(port, pEffect, pMaster); 260 IF_VST_UI_ON(vup = new VSTUIStreamPort(port, vp);) 261 break; 262 263 case R_FBUFFER: 264 vp = new VSTFrameBufferPort(port, pEffect, pMaster); 265 IF_VST_UI_ON(vup = new VSTUIFrameBufferPort(port, vp);) 266 break; 267 268 case R_MIDI: 269 if (IS_OUT_PORT(port)) 270 vp = new VSTMidiOutputPort(port, pEffect, pMaster); 271 else 272 { 273 pEffect->flags |= effFlagsIsSynth; 274 vp = new VSTMidiInputPort(port, pEffect, pMaster); 275 } 276 break; 277 278 case R_OSC: 279 vp = new VSTOscPort(port, pEffect, pMaster); 280 IF_VST_UI_ON( 281 if (IS_OUT_PORT(port)) 282 vup = new VSTUIOscPortIn(port, vp); 283 else 284 vup = new VSTUIOscPortOut(port, vp); 285 ) 286 break; 287 288 case R_PATH: 289 vp = new VSTPathPort(port, pEffect, pMaster); 290 IF_VST_UI_ON(vup = new VSTUIPathPort(port, vp);) 291 break; 292 293 case R_AUDIO: 294 vp = new VSTAudioPort(port, pEffect, pMaster); 295 break; 296 297 case R_CONTROL: 298 case R_METER: 299 case R_BYPASS: 300 // VST specifies only INPUT parameters, output should be read in different way 301 if (IS_OUT_PORT(port)) 302 { 303 vp = new VSTMeterPort(port, pEffect, pMaster); 304 IF_VST_UI_ON(vup = new VSTUIMeterPort(port, vp);) 305 } 306 else 307 { 308 vp = new VSTParameterPort(port, pEffect, pMaster); 309 IF_VST_UI_ON(vup = new VSTUIParameterPort(port, static_cast<VSTParameterPort *>(vp));) 310 } 311 if (port->role == R_BYPASS) 312 pBypass = vp; 313 break; 314 315 case R_PORT_SET: 316 { 317 char postfix_buf[LSP_MAX_PARAM_ID_BYTES]; 318 VSTPortGroup *pg = new VSTPortGroup(port, pEffect, pMaster); 319 pPlugin->add_port(pg); 320 321 IF_VST_UI_ON( 322 VSTUIPortGroup *upg = new VSTUIPortGroup(pg); 323 vUIPorts.add(upg); 324 ) 325 326 for (size_t row=0; row<pg->rows(); ++row) 327 { 328 // Generate postfix 329 snprintf(postfix_buf, sizeof(postfix_buf)-1, "%s_%d", (postfix != NULL) ? postfix : "", int(row)); 330 331 // Clone port metadata 332 port_t *cm = clone_port_metadata(port->members, postfix_buf); 333 if (cm != NULL) 334 { 335 vGenMetadata.add(cm); 336 337 for (; cm->id != NULL; ++cm) 338 { 339 if (IS_GROWING_PORT(cm)) 340 cm->start = cm->min + ((cm->max - cm->min) * row) / float(pg->rows()); 341 else if (IS_LOWERING_PORT(cm)) 342 cm->start = cm->max - ((cm->max - cm->min) * row) / float(pg->rows()); 343 344 VSTPort *p = create_port(cm, postfix_buf); 345 if ((p != NULL) && (p->metadata()->role != R_PORT_SET)) 346 pPlugin->add_port(p); 347 } 348 } 349 } 350 351 vp = pg; 352 break; 353 } 354 355 default: 356 break; 357 } 358 359 if (vp != NULL) 360 vPorts.add(vp); 361 IF_VST_UI_ON( 362 if (vup != NULL) 363 vUIPorts.add(vup); 364 ) 365 366 return vp; 367 } 368 create_ports(const port_t * meta)369 void VSTWrapper::create_ports(const port_t *meta) 370 { 371 for ( ; meta->id != NULL; ++meta) 372 { 373 VSTPort *vp = create_port(meta, NULL); 374 if (vp == NULL) 375 continue; 376 377 switch (meta->role) 378 { 379 case R_PORT_SET: 380 break; 381 382 case R_MESH: 383 case R_STREAM: 384 case R_FBUFFER: 385 case R_MIDI: 386 case R_PATH: 387 pPlugin->add_port(vp); 388 break; 389 390 case R_AUDIO: 391 pPlugin->add_port(vp); 392 if (IS_OUT_PORT(meta)) 393 vOutputs.add(static_cast<VSTAudioPort *>(vp)); 394 else 395 vInputs.add(static_cast<VSTAudioPort *>(vp)); 396 break; 397 398 case R_CONTROL: 399 case R_BYPASS: 400 case R_METER: 401 pPlugin->add_port(vp); 402 if (IS_IN_PORT(meta)) // VST specifies only INPUT parameters, output should be read in different way 403 vParams.add(static_cast<VSTParameterPort *>(vp)); 404 break; 405 406 default: 407 break; 408 } 409 } 410 } 411 init()412 void VSTWrapper::init() 413 { 414 AEffect *e = pEffect; 415 const plugin_metadata_t *m = pPlugin->get_metadata(); 416 417 // Bind ports 418 lsp_trace("Binding ports"); 419 create_ports(m->ports); 420 421 // Get buffer size 422 ssize_t blk_size = pMaster(pEffect, audioMasterGetBlockSize, 0, 0, 0, 0); 423 if (blk_size > 0) 424 set_block_size(blk_size); 425 426 // Update instance parameters 427 e->numInputs = vInputs.size(); 428 e->numOutputs = vOutputs.size(); 429 e->numParams = vParams.size(); 430 431 // Generate IDs for parameter ports 432 for (ssize_t id=0; id < e->numParams; ++id) 433 vParams[id]->setID(id); 434 435 // Initialize state chunk 436 pEffect->flags |= effFlagsProgramChunks; 437 438 // Initialize plugin 439 pPlugin->init(this); 440 } 441 destroy()442 void VSTWrapper::destroy() 443 { 444 #ifndef LSP_NO_VST_UI 445 // First destroy the UI 446 destroy_ui(); 447 #endif 448 449 // Shutdown and delete executor if exists 450 if (pExecutor != NULL) 451 { 452 pExecutor->shutdown(); 453 delete pExecutor; 454 pExecutor = NULL; 455 } 456 457 // Destrop plugin 458 lsp_trace("destroying plugin"); 459 if (pPlugin != NULL) 460 { 461 pPlugin->destroy(); 462 delete pPlugin; 463 464 pPlugin = NULL; 465 } 466 467 // Destroy UI ports 468 #ifndef LSP_NO_VST_UI 469 for (size_t i=0; i<vUIPorts.size(); ++i) 470 { 471 lsp_trace("destroy ui port id=%s", vUIPorts[i]->metadata()->id); 472 delete vUIPorts[i]; 473 } 474 vUIPorts.clear(); 475 #endif 476 477 // Destroy ports 478 for (size_t i=0; i<vPorts.size(); ++i) 479 { 480 lsp_trace("destroy port id=%s", vPorts[i]->metadata()->id); 481 delete vPorts[i]; 482 } 483 vPorts.clear(); 484 485 // Cleanup generated metadata 486 for (size_t i=0; i<vGenMetadata.size(); ++i) 487 { 488 lsp_trace("destroy generated port metadata %p", vGenMetadata[i]); 489 drop_port_metadata(vGenMetadata[i]); 490 } 491 492 // Clear all port lists 493 vInputs.clear(); 494 vOutputs.clear(); 495 vParams.clear(); 496 497 pMaster = NULL; 498 pEffect = NULL; 499 500 lsp_trace("destroy complete"); 501 } 502 set_block_size(size_t size)503 void VSTWrapper::set_block_size(size_t size) 504 { 505 lsp_trace("Block size for audio processing: %d", int(size)); 506 507 // Sync buffer size to all input ports 508 for (size_t i=0, n=vInputs.size(); i<n; ++i) 509 { 510 VSTAudioPort *p = vInputs.at(i); 511 if (p != NULL) 512 p->set_blk_size(size); 513 } 514 } 515 sync_position()516 void VSTWrapper::sync_position() 517 { 518 VstTimeInfo *info = FromVstPtr<VstTimeInfo>(pMaster(pEffect, audioMasterGetTime, 0, kVstPpqPosValid | kVstTempoValid | kVstBarsValid | kVstCyclePosValid | kVstTimeSigValid, NULL, 0.0f)); 519 if (info == NULL) 520 return; 521 522 position_t npos = sPosition; 523 524 npos.sampleRate = info->sampleRate; 525 npos.speed = 1.0f; 526 npos.ticksPerBeat = DEFAULT_TICKS_PER_BEAT; 527 npos.frame = info->samplePos; 528 529 // lsp_trace("info->flags = 0x%08x", int(info->flags)); 530 // lsp_trace("info->sampleRate = %f", info->sampleRate); 531 // lsp_trace("info->samplePos = %f", info->samplePos); 532 // lsp_trace("info->numerator = %d", int(info->timeSigNumerator)); 533 // lsp_trace("info->denominator = %d", int(info->timeSigDenominator)); 534 // lsp_trace("info->bpm = %f", info->tempo); 535 536 if (info->flags & kVstTimeSigValid) 537 { 538 npos.numerator = info->timeSigNumerator; 539 npos.denominator = info->timeSigDenominator; 540 541 // lsp_trace("ppq_pos = %f, bar_start_pos = %f", float(info->ppqPos), float(info->barStartPos)); 542 if ((info->flags & (kVstPpqPosValid | kVstBarsValid)) == (kVstPpqPosValid | kVstBarsValid)) 543 { 544 double uppqPos = (info->ppqPos - info->barStartPos) * info->timeSigDenominator * 0.25; 545 npos.tick = npos.ticksPerBeat * (uppqPos - int64_t(uppqPos)); 546 } 547 } 548 549 if (info->flags & kVstTempoValid) 550 npos.beatsPerMinute = info->tempo; 551 552 // lsp_trace("position: sr=%f, frame=%ld, key=%f/%f tick=%f bpm=%f", 553 // float(npos.sampleRate), long(npos.frame), float(npos.numerator), 554 // float(npos.denominator), float(npos.tick), float(npos.beatsPerMinute)); 555 556 // Report new position to plugin and update position 557 if (pPlugin->set_position(&npos)) 558 bUpdateSettings = true; 559 sPosition = npos; 560 } 561 run(float ** inputs,float ** outputs,size_t samples)562 void VSTWrapper::run(float** inputs, float** outputs, size_t samples) 563 { 564 // DO NOTHING if sample_rate is not set (fill output buffers with zeros) 565 if (pPlugin->get_sample_rate() <= 0) 566 { 567 size_t n_outputs = vOutputs.size(); 568 for (size_t i=0; i < n_outputs; ++i) 569 dsp::fill_zero(outputs[i], samples); 570 return; 571 } 572 573 #ifndef LSP_NO_VST_UI 574 // Sync UI state 575 if (pUI != NULL) 576 { 577 if (!pPlugin->ui_active()) 578 pPlugin->activate_ui(); 579 } 580 else if (pPlugin->ui_active()) 581 pPlugin->deactivate_ui(); 582 #endif 583 584 // Synchronize position 585 sync_position(); 586 587 // Bind audio ports 588 size_t n_inputs = vInputs.size(); 589 for (size_t i=0; i < n_inputs; ++i) 590 { 591 VSTAudioPort *p = vInputs.at(i); 592 if (p != NULL) 593 p->bind(inputs[i], samples); 594 } 595 size_t n_outputs = vOutputs.size(); 596 for (size_t i=0; i < n_outputs; ++i) 597 { 598 VSTAudioPort *p = vOutputs.at(i); 599 if (p != NULL) 600 p->bind(outputs[i], samples); 601 } 602 603 // Process ALL ports for changes 604 size_t n_ports = vPorts.size(); 605 VSTPort **v_ports = vPorts.get_array(); 606 for (size_t i=0; i<n_ports; ++i) 607 { 608 // Get port 609 VSTPort *port = v_ports[i]; 610 if (port == NULL) 611 continue; 612 613 // Pre-process data in port 614 if (port->pre_process(samples)) 615 { 616 lsp_trace("port changed: %s", port->metadata()->id); 617 bUpdateSettings = true; 618 } 619 } 620 621 // Check that input parameters have changed 622 if (bUpdateSettings) 623 { 624 lsp_trace("updating settings"); 625 pPlugin->update_settings(); 626 bUpdateSettings = false; 627 } 628 629 // Need to dump state? 630 atomic_t dump_req = nDumpReq; 631 if (dump_req != nDumpResp) 632 { 633 dump_plugin_state(); 634 nDumpResp = dump_req; 635 } 636 637 // Call the main processing unit 638 pPlugin->process(samples); 639 640 // Report latency 641 float latency = pPlugin->get_latency(); 642 if (fLatency != latency) 643 { 644 pEffect->initialDelay = latency; 645 fLatency = latency; 646 if (pMaster) 647 { 648 lsp_trace("Reporting latency = %d samples to the host", int(latency)); 649 pMaster(pEffect, audioMasterIOChanged, 0, 0, 0, 0); 650 } 651 } 652 653 // Post-process ALL ports 654 for (size_t i=0; i<n_ports; ++i) 655 { 656 VSTPort *port = v_ports[i]; 657 if (port != NULL) 658 port->post_process(samples); 659 } 660 } 661 process_events(const VstEvents * e)662 void VSTWrapper::process_events(const VstEvents *e) 663 { 664 // We need to deliver MIDI events to MIDI ports 665 for (size_t i=0; i<vPorts.size(); ++i) 666 { 667 VSTPort *p = vPorts[i]; 668 const port_t *meta = p->metadata(); 669 670 // Find MIDI port(s) 671 if (!IS_IN_PORT(meta)) 672 continue; 673 if (meta->role != R_MIDI) 674 continue; 675 676 // Call for event processing 677 VSTMidiInputPort *mp = static_cast<VSTMidiInputPort *>(p); 678 mp->deserialize(e); 679 } 680 } 681 run_legacy(float ** inputs,float ** outputs,size_t samples)682 void VSTWrapper::run_legacy(float** inputs, float** outputs, size_t samples) 683 { 684 run(inputs, outputs, samples); 685 } 686 687 #ifndef LSP_NO_VST_UI show_ui(void * root_widget)688 bool VSTWrapper::show_ui(void *root_widget) 689 { 690 lsp_trace("show ui"); 691 const plugin_metadata_t *m = pPlugin->get_metadata(); 692 693 if (pUI == NULL) 694 { 695 // Create custom UI object 696 lsp_trace("create ui"); 697 #define MOD_PLUGIN(plugin, ui) \ 698 if ((!pUI) && (!strcmp(plugin::metadata.vst_uid, m->vst_uid))) \ 699 pUI = new ui(m, root_widget); 700 #include <metadata/modules.h> 701 702 if (pUI == NULL) 703 return false; 704 705 // Add pre-generated ports 706 for (size_t i=0; i<vUIPorts.size(); ++i) 707 { 708 VSTUIPort *vp = vUIPorts.at(i); 709 lsp_trace("Adding UI port id=%s", vp->metadata()->id); 710 vp->resync(); 711 pUI->add_port(vp); 712 } 713 714 // Initialize UI 715 lsp_trace("init ui"); 716 status_t res = pUI->init(this, 0, NULL); 717 if (res == STATUS_OK) 718 res = pUI->build(); 719 720 LSPWindow *wnd = pUI->root_window(); 721 if (wnd != NULL) 722 wnd->slots()->bind(LSPSLOT_RESIZE, slot_ui_resize, this); 723 } 724 725 // Force all parameters to be re-shipped to the UI 726 for (size_t i=0; i<vUIPorts.size(); ++i) 727 { 728 VSTUIPort *vp = vUIPorts.at(i); 729 if (vp != NULL) 730 vp->notify_all(); 731 } 732 733 if (sKVTMutex.lock()) 734 { 735 sKVT.touch_all(KVT_TO_UI); 736 sKVTMutex.unlock(); 737 } 738 transfer_dsp_to_ui(); 739 740 // Show the UI window 741 LSPWindow *wnd = pUI->root_window(); 742 size_request_t sr; 743 wnd->size_request(&sr); 744 745 sRect.top = 0; 746 sRect.left = 0; 747 sRect.right = sr.nMinWidth; 748 sRect.bottom = sr.nMinHeight; 749 750 realize_t r; 751 r.nLeft = 0; 752 r.nTop = 0; 753 r.nWidth = sr.nMinWidth; 754 r.nHeight = sr.nMinHeight; 755 resize_ui(&r); 756 757 pUI->show(); 758 759 return true; 760 } 761 destroy_ui()762 void VSTWrapper::destroy_ui() 763 { 764 lsp_trace("destroy ui"); 765 766 // Destroy UI 767 if (pUI != NULL) 768 { 769 pUI->destroy(); 770 delete pUI; 771 pUI = NULL; 772 } 773 774 // Unbind all UI ports 775 for (size_t i=0; i<vUIPorts.size(); ++i) 776 vUIPorts[i]->unbind_all(); 777 } 778 iterate_ui()779 void VSTWrapper::iterate_ui() 780 { 781 if (pUI != NULL) 782 { 783 transfer_dsp_to_ui(); 784 pUI->main_iteration(); 785 } 786 } 787 slot_ui_resize(LSPWidget * sender,void * ptr,void * data)788 status_t VSTWrapper::slot_ui_resize(LSPWidget *sender, void *ptr, void *data) 789 { 790 VSTWrapper *_this = static_cast<VSTWrapper *>(ptr); 791 _this->resize_ui(static_cast<realize_t *>(data)); 792 return STATUS_OK; 793 } 794 get_ui_rect()795 ERect *VSTWrapper::get_ui_rect() 796 { 797 lsp_trace("left=%d, top=%d, right=%d, bottom=%d", 798 int(sRect.left), int(sRect.top), int(sRect.right), int(sRect.bottom) 799 ); 800 return &sRect; 801 }; 802 resize_ui(const realize_t * r)803 void VSTWrapper::resize_ui(const realize_t *r) 804 { 805 lsp_trace("UI has been resized"); 806 if (pUI == NULL) 807 return; 808 809 LSPWindow *wnd = pUI->root_window(); 810 811 sRect.top = 0; 812 sRect.left = 0; 813 sRect.right = r->nWidth; 814 sRect.bottom = r->nHeight; 815 816 realize_t rr; 817 wnd->get_geometry(&rr); 818 lsp_trace("Get geometry: width=%d, height=%d", int(rr.nWidth), int(rr.nHeight)); 819 820 if ((rr.nWidth <= 0) || (rr.nHeight <= 0)) 821 { 822 size_request_t sr; 823 wnd->size_request(&sr); 824 lsp_trace("Size request: width=%d, height=%d", int(sr.nMinWidth), int(sr.nMinHeight)); 825 rr.nWidth = sr.nMinWidth; 826 rr.nHeight = sr.nMinHeight; 827 } 828 829 lsp_trace("audioMasterSizeWindow width=%d, height=%d", int(rr.nWidth), int(rr.nHeight)); 830 if (((sRect.right - sRect.left) != rr.nWidth) || 831 ((sRect.bottom - sRect.top) != rr.nHeight)) 832 pMaster(pEffect, audioMasterSizeWindow, rr.nWidth, rr.nHeight, 0, 0); 833 } 834 hide_ui()835 void VSTWrapper::hide_ui() 836 { 837 destroy_ui(); 838 } 839 transfer_dsp_to_ui()840 void VSTWrapper::transfer_dsp_to_ui() 841 { 842 // lsp_trace("pUI = %p", pUI); 843 // Get number of ports 844 if (pUI == NULL) 845 return; 846 847 // Try to sync position 848 pUI->position_updated(&sPosition); 849 pUI->sync_meta_ports(); 850 851 // DSP -> UI communication 852 for (size_t i=0, nports=vUIPorts.size(); i < nports; ++i) 853 { 854 // Get UI port 855 VSTUIPort *vup = vUIPorts[i]; 856 do { 857 if (vup->sync()) 858 vup->notify_all(); 859 } while (vup->sync_again()); 860 } // for port_id 861 862 // Perform KVT synchronization 863 if (sKVTMutex.try_lock()) 864 { 865 // Synchronize DSP -> UI transfer 866 size_t sync; 867 const char *kvt_name; 868 const kvt_param_t *kvt_value; 869 870 do 871 { 872 sync = 0; 873 874 KVTIterator *it = sKVT.enum_tx_pending(); 875 while (it->next() == STATUS_OK) 876 { 877 kvt_name = it->name(); 878 if (kvt_name == NULL) 879 break; 880 status_t res = it->get(&kvt_value); 881 if (res != STATUS_OK) 882 break; 883 if ((res = it->commit(KVT_TX)) != STATUS_OK) 884 break; 885 886 kvt_dump_parameter("TX kvt param (DSP->UI): %s = ", kvt_value, kvt_name); 887 pUI->kvt_write(&sKVT, kvt_name, kvt_value); 888 ++sync; 889 } 890 } while (sync > 0); 891 892 // Synchronize UI -> DSP transfer 893 #ifdef LSP_DEBUG 894 { 895 KVTIterator *it = sKVT.enum_rx_pending(); 896 while (it->next() == STATUS_OK) 897 { 898 kvt_name = it->name(); 899 if (kvt_name == NULL) 900 break; 901 status_t res = it->get(&kvt_value); 902 if (res != STATUS_OK) 903 break; 904 if ((res = it->commit(KVT_RX)) != STATUS_OK) 905 break; 906 907 kvt_dump_parameter("RX kvt param (UI->DSP): %s = ", kvt_value, kvt_name); 908 } 909 } 910 #else 911 sKVT.commit_all(KVT_RX); // Just clear all RX queue for non-debug version 912 #endif 913 914 // Call garbage collection and release KVT storage 915 sKVT.gc(); 916 sKVTMutex.unlock(); 917 } 918 } 919 920 #endif 921 922 #ifdef LSP_TRACE dump_vst_bank(const void * bank,size_t ck_size)923 static void dump_vst_bank(const void *bank, size_t ck_size) 924 { 925 const uint8_t *ddump = reinterpret_cast<const uint8_t *>(bank); 926 lsp_trace("Chunk dump:"); 927 928 for (size_t offset=0; offset < ck_size; offset += 16) 929 { 930 // Print HEX dump 931 lsp_nprintf("%08x: ", int(offset)); 932 for (size_t i=0; i<0x10; ++i) 933 { 934 if ((offset + i) < ck_size) 935 lsp_nprintf("%02x ", int(ddump[i])); 936 else 937 lsp_nprintf(" "); 938 } 939 lsp_nprintf(" "); 940 941 // Print character dump 942 for (size_t i=0; i<0x10; ++i) 943 { 944 if ((offset + i) < ck_size) 945 { 946 uint8_t c = ddump[i]; 947 if ((c < 0x20) || (c >= 0x7f)) 948 c = '.'; 949 lsp_nprintf("%c", c); 950 } 951 else 952 lsp_nprintf(" "); 953 } 954 lsp_printf(""); 955 956 // Move pointer 957 ddump += 0x10; 958 } 959 } 960 #else 961 #define dump_vst_bank(...) 962 #endif /* LSP_TRACE */ 963 serialize_port_data()964 status_t VSTWrapper::serialize_port_data() 965 { 966 size_t param_off = 0; 967 968 // Serialize all regular ports 969 for (size_t i=0; i<vPorts.size(); ++i) 970 { 971 // Get VST port 972 VSTPort *vp = vPorts[i]; 973 if (vp == NULL) 974 continue; 975 976 // Get metadata 977 const port_t *p = vp->metadata(); 978 if ((p == NULL) || (p->id == NULL) || (IS_OUT_PORT(p)) || (!vp->serializable())) 979 continue; 980 981 // Check that port is serializable 982 lsp_trace("Serializing port id=%s", p->id); 983 984 // Write port data to the chunk 985 param_off = sChunk.write(uint32_t(0)); // Reserve space for size 986 sChunk.write_string(p->id); // ID of the port 987 vp->serialize(&sChunk); // Value of the port 988 sChunk.write_at(param_off, uint32_t(sChunk.offset - param_off - sizeof(uint32_t))); // Write the actual size 989 990 if (sChunk.res != STATUS_OK) 991 { 992 lsp_warn("Error serializing parameter is=%s, code=%d", p->id, int(sChunk.res)); 993 return sChunk.res; 994 } 995 } 996 997 status_t res = STATUS_OK; 998 999 // Serialize KVT storage 1000 if (sKVTMutex.lock()) 1001 { 1002 const kvt_param_t *p; 1003 1004 // Read the whole KVT storage 1005 KVTIterator *it = sKVT.enum_all(); 1006 while (it->next() == STATUS_OK) 1007 { 1008 res = it->get(&p); 1009 if (res == STATUS_NOT_FOUND) // Not a parameter 1010 continue; 1011 else if (res != STATUS_OK) 1012 { 1013 lsp_warn("it->get() returned %d", int(res)); 1014 break; 1015 } 1016 else if (it->is_transient()) // Skip transient parameters 1017 continue; 1018 1019 const char *name = it->name(); 1020 if (name == NULL) 1021 { 1022 lsp_trace("it->name() returned NULL"); 1023 break; 1024 } 1025 1026 uint8_t flags = 0; 1027 if (it->is_private()) 1028 flags |= LSP_VST_PRIVATE; 1029 1030 kvt_dump_parameter("Saving state of KVT parameter: %s = ", p, name); 1031 1032 param_off = sChunk.write(uint32_t(0)); // Reserve space for size 1033 sChunk.write_string(name); // Name of the KVT parameter 1034 sChunk.write_byte(flags); 1035 1036 // Serialize parameter according to it's type 1037 switch (p->type) 1038 { 1039 case KVT_INT32: 1040 { 1041 sChunk.write_byte(LSP_VST_INT32); 1042 sChunk.write(p->i32); 1043 break; 1044 }; 1045 case KVT_UINT32: 1046 { 1047 sChunk.write_byte(LSP_VST_UINT32); 1048 sChunk.write(p->u32); 1049 break; 1050 } 1051 case KVT_INT64: 1052 { 1053 sChunk.write_byte(LSP_VST_INT64); 1054 sChunk.write(p->i64); 1055 break; 1056 }; 1057 case KVT_UINT64: 1058 { 1059 sChunk.write_byte(LSP_VST_UINT64); 1060 sChunk.write(p->u64); 1061 break; 1062 } 1063 case KVT_FLOAT32: 1064 { 1065 sChunk.write_byte(LSP_VST_FLOAT32); 1066 sChunk.write(p->f32); 1067 break; 1068 } 1069 case KVT_FLOAT64: 1070 { 1071 sChunk.write_byte(LSP_VST_FLOAT64); 1072 sChunk.write(p->f64); 1073 break; 1074 } 1075 case KVT_STRING: 1076 { 1077 sChunk.write_byte(LSP_VST_STRING); 1078 sChunk.write_string((p->str != NULL) ? p->str : ""); 1079 break; 1080 } 1081 case KVT_BLOB: 1082 { 1083 if ((p->blob.size > 0) && (p->blob.data == NULL)) 1084 { 1085 res = STATUS_INVALID_VALUE; 1086 break; 1087 } 1088 1089 sChunk.write_byte(LSP_VST_BLOB); 1090 sChunk.write_string((p->blob.ctype != NULL) ? p->blob.ctype : ""); 1091 if (p->blob.size > 0) 1092 sChunk.write(p->blob.data, p->blob.size); 1093 break; 1094 } 1095 1096 default: 1097 res = STATUS_BAD_TYPE; 1098 break; 1099 } 1100 1101 // Successful status? 1102 if (res != STATUS_OK) 1103 { 1104 lsp_trace("it->name() returned NULL"); 1105 break; 1106 } 1107 1108 // Complete the parameter size 1109 sChunk.write_at(param_off, uint32_t(sChunk.offset - param_off - sizeof(uint32_t))); // Write the actual size 1110 } 1111 1112 sKVT.gc(); 1113 sKVTMutex.unlock(); 1114 } 1115 1116 return res; 1117 } 1118 serialize_state(const void ** dst,bool program)1119 size_t VSTWrapper::serialize_state(const void **dst, bool program) 1120 { 1121 // Clear chunk 1122 status_t res; 1123 sChunk.clear(); 1124 1125 // Write the bank header 1126 if (program) 1127 { 1128 fxProgram prog; 1129 ::bzero(&prog, sizeof(prog)); 1130 1131 prog.chunkMagic = CPU_TO_BE(VstInt32(cMagic)); 1132 prog.byteSize = 0; 1133 prog.fxMagic = CPU_TO_BE(VstInt32(chunkPresetMagic)); 1134 prog.version = CPU_TO_BE(VstInt32(1)); // Version 1.0.0 of the program 1135 prog.fxID = CPU_TO_BE(VstInt32(pEffect->uniqueID)); 1136 prog.fxVersion = CPU_TO_BE(VstInt32(VST_FX_VERSION_JUCE_FIX)); 1137 prog.numParams = 0; 1138 prog.prgName[0] = '\0'; 1139 1140 size_t prog_off = sChunk.write(&prog, offsetof(fxProgram, content.data.chunk)); 1141 1142 vst_state_header hdr; 1143 ::bzero(&hdr, sizeof(hdr)); 1144 hdr.nMagic1 = CPU_TO_BE(VstInt32(LSP_VST_USER_MAGIC)); 1145 hdr.nSize = 0; 1146 hdr.nVersion = CPU_TO_BE(VstInt32(VST_FX_VERSION_JUCE_FIX)); 1147 hdr.nMagic2 = CPU_TO_BE(VstInt32(LSP_VST_USER_MAGIC)); 1148 size_t hdr_off = sChunk.write(&hdr, sizeof(hdr)); 1149 size_t data_off = sChunk.offset; 1150 1151 if ((res = serialize_port_data()) != STATUS_OK) 1152 { 1153 *dst = NULL; 1154 return 0; 1155 } 1156 1157 // Write the size of chunk 1158 fxProgram *pprog = sChunk.fetch<fxProgram>(prog_off); 1159 VstInt32 size = sChunk.offset - VST_PROGRAM_HDR_SKIP; 1160 pprog->content.data.size = CPU_TO_BE(VstInt32(sChunk.offset - hdr_off)); 1161 pprog->byteSize = CPU_TO_BE(size); 1162 1163 vst_state_header *phdr = sChunk.fetch<vst_state_header>(hdr_off); 1164 phdr->nSize = CPU_TO_BE(VstInt32(sChunk.offset - data_off)); 1165 1166 dump_vst_bank(pprog, sChunk.offset); 1167 *dst = pprog; 1168 } 1169 else 1170 { 1171 fxBank bank; 1172 ::bzero(&bank, sizeof(bank)); 1173 1174 bank.chunkMagic = CPU_TO_BE(VstInt32(cMagic)); 1175 bank.byteSize = 0; 1176 bank.fxMagic = CPU_TO_BE(VstInt32(chunkBankMagic)); 1177 bank.version = CPU_TO_BE(VstInt32(1)); // Version 2.0.0 of the bank 1178 bank.fxID = CPU_TO_BE(VstInt32(pEffect->uniqueID)); 1179 bank.fxVersion = CPU_TO_BE(VstInt32(VST_FX_VERSION_JUCE_FIX)); // Version 2.0.0 of the bank 1180 bank.numPrograms = 0; 1181 bank.currentProgram = 0; 1182 1183 size_t bank_off = sChunk.write(&bank, offsetof(fxBank, content.data.chunk)); 1184 1185 vst_state_header hdr; 1186 ::bzero(&hdr, sizeof(hdr)); 1187 hdr.nMagic1 = CPU_TO_BE(VstInt32(LSP_VST_USER_MAGIC)); 1188 hdr.nSize = 0; 1189 hdr.nVersion = CPU_TO_BE(VstInt32(VST_FX_VERSION_JUCE_FIX)); 1190 hdr.nMagic2 = CPU_TO_BE(VstInt32(LSP_VST_USER_MAGIC)); 1191 size_t hdr_off = sChunk.write(&hdr, sizeof(hdr)); 1192 size_t data_off = sChunk.offset; 1193 1194 if ((res = serialize_port_data()) != STATUS_OK) 1195 { 1196 *dst = NULL; 1197 return 0; 1198 } 1199 1200 // Write the size of chunk 1201 fxBank *pbank = sChunk.fetch<fxBank>(bank_off); 1202 VstInt32 size = sChunk.offset - VST_BANK_HDR_SKIP; 1203 pbank->content.data.size = CPU_TO_BE(VstInt32(sChunk.offset - hdr_off)); 1204 pbank->byteSize = CPU_TO_BE(size); 1205 1206 vst_state_header *phdr = sChunk.fetch<vst_state_header>(hdr_off); 1207 phdr->nSize = CPU_TO_BE(VstInt32(sChunk.offset - data_off)); 1208 1209 dump_vst_bank(pbank, sChunk.offset); 1210 *dst = pbank; 1211 } 1212 1213 // Issue callback 1214 pPlugin->state_saved(); 1215 lsp_trace("Plugin state has been saved"); 1216 1217 // Return result 1218 return sChunk.offset; 1219 } 1220 check_vst_bank_header(const fxBank * bank,size_t size)1221 status_t VSTWrapper::check_vst_bank_header(const fxBank *bank, size_t size) 1222 { 1223 // Validate size 1224 if (size < size_t(offsetof(fxBank, content.data.chunk))) 1225 { 1226 lsp_warn("block size too small (0x%08x bytes)", int(size)); 1227 return STATUS_NOT_FOUND; 1228 } 1229 1230 // Validate chunkMagic 1231 if (bank->chunkMagic != BE_TO_CPU(cMagic)) 1232 { 1233 lsp_warn("bank->chunkMagic (%08x) != BE_DATA(VST_CHUNK_MAGIC) (%08x)", int(bank->chunkMagic), int(BE_TO_CPU(cMagic))); 1234 return STATUS_NOT_FOUND; 1235 } 1236 1237 // Validate fxMagic 1238 if (bank->fxMagic != BE_TO_CPU(chunkBankMagic)) 1239 { 1240 lsp_warn("bank->fxMagic (%08x) != BE_DATA(VST_OPAQUE_BANK_MAGIC) (%08x)", int(bank->fxMagic), int(BE_TO_CPU(chunkBankMagic))); 1241 return STATUS_UNSUPPORTED_FORMAT; 1242 } 1243 1244 // Validate fxID 1245 if (bank->fxID != BE_TO_CPU(VstInt32(pEffect->uniqueID))) 1246 { 1247 lsp_warn("bank->fxID (%08x) != BE_DATA(VstInt32(pEffect->uniqueID)) (%08x)", int(bank->fxID), int(BE_TO_CPU(VstInt32(pEffect->uniqueID)))); 1248 return STATUS_UNSUPPORTED_FORMAT; 1249 } 1250 1251 // Validate the numParams 1252 if (bank->numPrograms != 0) 1253 { 1254 lsp_warn("bank->numPrograms (%d) != 0", int(bank->numPrograms)); 1255 return STATUS_UNSUPPORTED_FORMAT; 1256 } 1257 1258 return STATUS_OK; 1259 } 1260 check_vst_program_header(const fxProgram * prog,size_t size)1261 status_t VSTWrapper::check_vst_program_header(const fxProgram *prog, size_t size) 1262 { 1263 // Validate size 1264 if (size < size_t(offsetof(fxProgram, content.data.chunk))) 1265 { 1266 lsp_warn("block size too small (0x%08x bytes)", int(size)); 1267 return STATUS_NOT_FOUND; 1268 } 1269 1270 // Validate chunkMagic 1271 if (prog->chunkMagic != BE_TO_CPU(cMagic)) 1272 { 1273 lsp_warn("prog->chunkMagic (%08x) != BE_DATA(VST_CHUNK_MAGIC) (%08x)", int(prog->chunkMagic), int(BE_TO_CPU(cMagic))); 1274 return STATUS_NOT_FOUND; 1275 } 1276 1277 // Validate fxMagic 1278 if (prog->fxMagic != BE_TO_CPU(chunkPresetMagic)) 1279 { 1280 lsp_warn("prog->fxMagic (%08x) != BE_DATA(VST_OPAQUE_PRESET_MAGIC) (%08x)", int(prog->fxMagic), int(BE_TO_CPU(chunkPresetMagic))); 1281 return STATUS_UNSUPPORTED_FORMAT; 1282 } 1283 1284 // Validate fxID 1285 if (prog->fxID != BE_TO_CPU(VstInt32(pEffect->uniqueID))) 1286 { 1287 lsp_warn("prog->fxID (%08x) != BE_DATA(VstInt32(pEffect->uniqueID)) (%08x)", int(prog->fxID), int(BE_TO_CPU(VstInt32(pEffect->uniqueID)))); 1288 return STATUS_UNSUPPORTED_FORMAT; 1289 } 1290 1291 return STATUS_OK; 1292 } 1293 deserialize_state(const void * data,size_t size)1294 void VSTWrapper::deserialize_state(const void *data, size_t size) 1295 { 1296 const fxBank *bank = static_cast<const fxBank *>(data); 1297 const fxProgram *prog = static_cast<const fxProgram *>(data); 1298 const uint8_t *head = static_cast<const uint8_t *>(data); 1299 1300 status_t res; 1301 if ((res = check_vst_bank_header(bank, size)) == STATUS_OK) 1302 { 1303 lsp_warn("Found standard VST 2.x chunk header (bank)"); 1304 dump_vst_bank(bank, (BE_TO_CPU(bank->byteSize) + 2 * sizeof(VstInt32))); 1305 1306 // Check the version 1307 VstInt32 fxVersion = BE_TO_CPU(bank->fxVersion); 1308 if (fxVersion < VST_FX_VERSION_KVT_SUPPORT) 1309 deserialize_v1(bank); // Load V1 bank for legacy support 1310 else 1311 { 1312 // Get size of chunk 1313 size_t bytes = BE_TO_CPU(VstInt32(bank->byteSize)); 1314 if (bytes < offsetof(fxBank, content.data.chunk)) 1315 { 1316 lsp_trace("byte_size (%d) < VST_STATE_BUFFER_SIZE (%d)", int(bytes), int(VST_STATE_BUFFER_SIZE)); 1317 return; 1318 } 1319 1320 const uint8_t *tail = &head[bytes + VST_BANK_HDR_SKIP]; 1321 head += offsetof(fxBank, content.data.chunk); 1322 bytes = BE_TO_CPU(bank->content.data.size); 1323 if (size_t(tail - head) != bytes) 1324 { 1325 lsp_trace("Content size=0x%x does not match specified=0x%x", int(tail-head), int(bytes)); 1326 return; 1327 } 1328 1329 deserialize_new_chunk_format(head, bytes); 1330 } 1331 } 1332 else if ((res = check_vst_program_header(prog, size)) == STATUS_OK) 1333 { 1334 // VST Programs do support only new chunk format 1335 lsp_warn("Found standard VST 2.x chunk header (program)"); 1336 dump_vst_bank(prog, (BE_TO_CPU(prog->byteSize) + 2 * sizeof(VstInt32))); 1337 1338 // Get size of chunk 1339 size_t bytes = BE_TO_CPU(VstInt32(prog->byteSize)); 1340 if (bytes < offsetof(fxProgram, content.data.chunk)) 1341 { 1342 lsp_trace("byte_size (%d) < VST_STATE_BUFFER_SIZE (%d)", int(bytes), int(VST_STATE_BUFFER_SIZE)); 1343 return; 1344 } 1345 1346 const uint8_t *tail = &head[bytes + VST_PROGRAM_HDR_SKIP]; 1347 head += offsetof(fxProgram, content.data.chunk); 1348 bytes = BE_TO_CPU(prog->content.data.size); 1349 if (size_t(tail - head) != bytes) 1350 { 1351 lsp_trace("Content size=0x%x does not match specified=0x%x", int(tail-head), int(bytes)); 1352 return; 1353 } 1354 1355 deserialize_new_chunk_format(head, bytes); 1356 } 1357 else if (res == STATUS_NOT_FOUND) 1358 { 1359 // Do stuff considering that there is NO chunk headers, just raw data 1360 lsp_warn("No VST 2.x chunk header found, assuming the body is in valid state"); 1361 dump_vst_bank(head, size); 1362 deserialize_new_chunk_format(head, size); 1363 } 1364 else 1365 return; 1366 1367 // Call callback 1368 pPlugin->state_loaded(); 1369 lsp_trace("Plugin state has been loaded"); 1370 } 1371 deserialize_new_chunk_format(const uint8_t * data,size_t bytes)1372 void VSTWrapper::deserialize_new_chunk_format(const uint8_t *data, size_t bytes) 1373 { 1374 // Lookup extension header 1375 vst_state_header hdr; 1376 ::bzero(&hdr, sizeof(hdr)); 1377 if (bytes >= sizeof(vst_state_header)) 1378 { 1379 const vst_state_header *src = reinterpret_cast<const vst_state_header *>(data); 1380 hdr.nMagic1 = BE_TO_CPU(src->nMagic1); 1381 hdr.nSize = BE_TO_CPU(src->nSize); 1382 hdr.nVersion = BE_TO_CPU(src->nVersion); 1383 hdr.nMagic2 = BE_TO_CPU(src->nMagic2); 1384 } 1385 1386 // Analyze version 1387 if ((hdr.nMagic1 != LSP_VST_USER_MAGIC) || (hdr.nMagic2 != LSP_VST_USER_MAGIC)) 1388 { 1389 lsp_debug("Performing V2 parameter deserialization (0x%x bytes)", int(bytes)); 1390 deserialize_v2_v3(data, bytes); 1391 } 1392 else if (hdr.nVersion >= VST_FX_VERSION_JUCE_FIX) 1393 { 1394 lsp_debug("Performing V3 parameter deserialization"); 1395 deserialize_v2_v3(&data[sizeof(hdr)], hdr.nSize); 1396 } 1397 else 1398 lsp_warn("Unsupported format, don't know how to deserialize chunk"); 1399 } 1400 find_by_id(const char * id)1401 VSTPort *VSTWrapper::find_by_id(const char *id) 1402 { 1403 for (size_t i=0; i< vPorts.size(); ++i) 1404 { 1405 // Get VST port 1406 VSTPort *sp = vPorts[i]; 1407 if (sp == NULL) 1408 continue; 1409 1410 // Get port metadata 1411 const port_t *p = sp->metadata(); 1412 if ((p == NULL) || (p->id == NULL)) 1413 continue; 1414 1415 // Check that ID of the port matches 1416 if (!::strcmp(p->id, id)) 1417 return sp; 1418 } 1419 1420 return NULL; 1421 } 1422 deserialize_v1(const fxBank * bank)1423 void VSTWrapper::deserialize_v1(const fxBank *bank) 1424 { 1425 lsp_debug("Performing V1 parameter deserialization"); 1426 1427 // Get size of chunk 1428 size_t bytes = BE_TO_CPU(VstInt32(bank->byteSize)); 1429 if (bytes < VST_STATE_BUFFER_SIZE) 1430 { 1431 lsp_trace("byte_size (%d) < VST_STATE_BUFFER_SIZE (%d)", int(bytes), int(VST_STATE_BUFFER_SIZE)); 1432 return; 1433 } 1434 1435 // Ready to de-serialize 1436 const vst_state *state = reinterpret_cast<const vst_state *>(bank + 1); 1437 size_t params = BE_TO_CPU(state->nItems); 1438 const uint8_t *ptr = state->vData; 1439 const uint8_t *tail = reinterpret_cast<const uint8_t *>(state) + bytes - sizeof(vst_state); 1440 char param_id[LSP_MAX_PARAM_ID_BYTES]; 1441 1442 while ((params--) > 0) 1443 { 1444 // Deserialize port ID 1445 ssize_t delta = vst_deserialize_string(param_id, LSP_MAX_PARAM_ID_BYTES, ptr, tail - ptr); 1446 if (delta <= 0) 1447 { 1448 lsp_error("Bank data corrupted"); 1449 return; 1450 } 1451 ptr += delta; 1452 1453 // Find port 1454 lsp_trace("Deserializing port id=%s", param_id); 1455 VSTPort *vp = find_by_id(param_id); 1456 if (vp == NULL) 1457 { 1458 lsp_error("Bank data corrupted: port id=%s not found", param_id); 1459 return; 1460 } 1461 1462 // Deserialize port data 1463 delta = vp->deserialize_v1(ptr, tail - ptr); 1464 if (delta <= 0) 1465 { 1466 lsp_error("bank data corrupted, could not deserialize port id=%s", param_id); 1467 return; 1468 } 1469 ptr += delta; 1470 } 1471 } 1472 deserialize_v2_v3(const uint8_t * data,size_t bytes)1473 void VSTWrapper::deserialize_v2_v3(const uint8_t *data, size_t bytes) 1474 { 1475 const uint8_t *head = data; 1476 const uint8_t *tail = &head[bytes]; 1477 1478 lsp_debug("Reading regular ports..."); 1479 while (size_t(tail - head) >= sizeof(uint32_t)) 1480 { 1481 // Read parameter length 1482 uint32_t len = BE_TO_CPU(*(reinterpret_cast<const uint32_t *>(head))) + sizeof(uint32_t); 1483 if (len > size_t(tail - head)) 1484 { 1485 lsp_warn("Unexpected end of chunk while fetching parameter size"); 1486 return; 1487 } 1488 const uint8_t *next = &head[len]; 1489 1490 // Read name of port 1491 head += sizeof(uint32_t); 1492 const char *name = reinterpret_cast<const char *>(head); 1493 len = ::strnlen(name, next - head) + 1; 1494 if (len > size_t(next - head)) 1495 { 1496 lsp_warn("Unexpected end of chunk while fetching parameter name"); 1497 return; 1498 } 1499 if (name[0] == '/') // This is KVT port? 1500 { 1501 head -= sizeof(uint32_t); // Rollback head pointer 1502 break; 1503 } 1504 head += len; 1505 1506 // Find port 1507 lsp_trace("Deserializing port id=%s", name); 1508 VSTPort *vp = find_by_id(name); 1509 if (vp == NULL) 1510 { 1511 lsp_warn("Port id=%s not found, skipping", name); 1512 head = next; 1513 continue; 1514 } 1515 1516 // Deserialize port 1517 if (!vp->deserialize_v2(head, next - head)) 1518 { 1519 lsp_warn("Error deserializing port %s, skipping", name); 1520 head = next; 1521 continue; 1522 } 1523 1524 // Move to next parameter 1525 head = next; 1526 } 1527 1528 // Nothing to de-serialize more? 1529 if (head >= tail) 1530 return; 1531 1532 // Deserialize KVT state 1533 lsp_debug("Reading KVT ports..."); 1534 if (sKVTMutex.lock()) 1535 { 1536 sKVT.clear(); 1537 1538 while (size_t(tail - head) >= sizeof(uint32_t)) 1539 { 1540 // Read parameter length 1541 uint32_t len = BE_TO_CPU(*(reinterpret_cast<const uint32_t *>(head))) + sizeof(uint32_t); 1542 lsp_trace("Reading block: off=0x%x, size=%d", int(head - data), int(len)); 1543 if (len > size_t(tail - head)) 1544 { 1545 lsp_warn("Unexpected end of chunk while fetching KVT parameter size"); 1546 break; 1547 } 1548 const uint8_t *next = &head[len]; 1549 1550 // Read name of parameter 1551 head += sizeof(uint32_t); 1552 const char *name = reinterpret_cast<const char *>(head); 1553 len = ::strnlen(name, next - head) + 1; 1554 if (len > size_t(next - head)) 1555 { 1556 lsp_warn("Unexpected end of chunk while fetching KVT parameter name"); 1557 break; 1558 } 1559 head += len; 1560 1561 // Deserialize KVT parameter 1562 kvt_param_t p; 1563 p.type = KVT_ANY; 1564 uint8_t flags = *(head++); 1565 uint8_t type = *(head++); 1566 1567 lsp_trace("Deserializing KVT parameter id=%s, type=0x%x", name, int(type)); 1568 1569 switch (type) 1570 { 1571 case LSP_VST_INT32: 1572 if ((next - head) != sizeof(int32_t)) 1573 break; 1574 p.type = KVT_INT32; 1575 p.i32 = BE_TO_CPU(*(reinterpret_cast<const int32_t *>(head))); 1576 head += sizeof(int32_t); 1577 break; 1578 1579 case LSP_VST_UINT32: 1580 if ((next - head) != sizeof(uint32_t)) 1581 break; 1582 p.type = KVT_UINT32; 1583 p.u32 = BE_TO_CPU(*(reinterpret_cast<const uint32_t *>(head))); 1584 head += sizeof(uint32_t); 1585 break; 1586 1587 case LSP_VST_INT64: 1588 if ((next - head) != sizeof(int64_t)) 1589 break; 1590 p.type = KVT_INT64; 1591 p.i64 = BE_TO_CPU(*(reinterpret_cast<const int64_t *>(head))); 1592 head += sizeof(int64_t); 1593 break; 1594 1595 case LSP_VST_UINT64: 1596 if ((next - head) != sizeof(uint64_t)) 1597 break; 1598 p.type = KVT_UINT64; 1599 p.u64 = BE_TO_CPU(*(reinterpret_cast<const uint64_t *>(head))); 1600 head += sizeof(uint64_t); 1601 break; 1602 1603 case LSP_VST_FLOAT32: 1604 if ((next - head) != sizeof(float)) 1605 break; 1606 p.type = KVT_FLOAT32; 1607 p.f32 = BE_TO_CPU(*(reinterpret_cast<const float *>(head))); 1608 head += sizeof(float); 1609 break; 1610 1611 case LSP_VST_FLOAT64: 1612 if ((next - head) != sizeof(double)) 1613 break; 1614 p.type = KVT_FLOAT64; 1615 p.f64 = BE_TO_CPU(*(reinterpret_cast<const double *>(head))); 1616 head += sizeof(double); 1617 break; 1618 1619 case LSP_VST_STRING: 1620 p.str = reinterpret_cast<const char *>(head); 1621 if (::strnlen(p.str, next-head) < size_t(next - head)) 1622 p.type = KVT_STRING; 1623 break; 1624 1625 case LSP_VST_BLOB: 1626 p.blob.ctype = reinterpret_cast<const char *>(head); 1627 len = ::strnlen(p.blob.ctype, next-head) + 1; 1628 if (len > size_t(next - head)) 1629 { 1630 lsp_trace("BLOB: clen=%d out of range %d", int(len), int(next-head)); 1631 break; 1632 } 1633 1634 head += len; 1635 p.blob.size = next - head; 1636 p.blob.data = (p.blob.size > 0) ? head : NULL; 1637 p.type = KVT_BLOB; 1638 break; 1639 default: 1640 lsp_warn("Unknown KVT parameter type: %d ('%c') for id=%s", type, type, name); 1641 break; 1642 } 1643 1644 if (p.type != KVT_ANY) 1645 { 1646 size_t kflags = KVT_TX; 1647 if (flags & LSP_VST_PRIVATE) 1648 kflags |= KVT_PRIVATE; 1649 1650 kvt_dump_parameter("Fetched parameter %s = ", &p, name); 1651 sKVT.put(name, &p, kflags); 1652 } 1653 1654 // Move to next parameter 1655 head = next; 1656 } 1657 1658 sKVT.gc(); 1659 sKVTMutex.unlock(); 1660 } 1661 } 1662 set_bypass(bool bypass)1663 void VSTWrapper::set_bypass(bool bypass) 1664 { 1665 pBypass->writeValue((bypass) ? 1.0f : 0.0f); 1666 } 1667 create_canvas(ICanvas * & cv,size_t width,size_t height)1668 ICanvas *VSTWrapper::create_canvas(ICanvas *&cv, size_t width, size_t height) 1669 { 1670 return NULL; 1671 } 1672 kvt_lock()1673 KVTStorage *VSTWrapper::kvt_lock() 1674 { 1675 return (sKVTMutex.lock()) ? &sKVT : NULL; 1676 } 1677 kvt_trylock()1678 KVTStorage *VSTWrapper::kvt_trylock() 1679 { 1680 return (sKVTMutex.try_lock()) ? &sKVT : NULL; 1681 } 1682 kvt_release()1683 bool VSTWrapper::kvt_release() 1684 { 1685 return sKVTMutex.unlock(); 1686 } 1687 dump_state_request()1688 void VSTWrapper::dump_state_request() 1689 { 1690 atomic_add(&nDumpReq, 1); 1691 } 1692 } 1693 1694 #endif /* CONTAINER_VST_WRAPPER_H_ */ 1695