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