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: 23 окт. 2015 г.
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_LV2_PORTS_H_
23 #define CONTAINER_LV2_PORTS_H_
24 
25 namespace lsp
26 {
27     // Specify port classes
28     class LV2Port: public IPort
29     {
30         protected:
31             LV2Extensions          *pExt;
32             LV2_URID                urid;
33             ssize_t                 nID;
34             bool                    bVirtual;
35 
36         public:
LV2Port(const port_t * meta,LV2Extensions * ext,bool virt)37             explicit LV2Port(const port_t *meta, LV2Extensions *ext, bool virt): IPort(meta)
38             {
39                 pExt            =   ext;
40                 urid            =   (meta != NULL) ? pExt->map_port(meta->id) : -1;
41                 nID             =   -1;
42                 bVirtual        =   virt;
43             }
~LV2Port()44             virtual ~LV2Port()
45             {
46                 pExt            =   NULL;
47                 urid            =   -1;
48                 nID             =   -1;
49             }
50 
51         public:
52             /** Bind generic port to generic data pointer
53              *
54              * @param data data pointer
55              */
bind(void * data)56             virtual void bind(void *data)               { };
57 
58             /** Save state of the port to LV2 state
59              *
60              */
save()61             virtual void save()                         { };
62 
63             /** Restore state of the port from LV2 state
64              *
65              */
restore()66             virtual void restore()                      { };
67 
68             /** Serialize state of the port to LV2 Atom
69              *
70              */
serialize()71             virtual void serialize()                    { };
72 
73             /** Deserialize state of the port from LV2 Atom
74              * @param flags additional flags
75              * @return true if internal state of the port has changed
76              */
deserialize(const void * data,size_t flags)77             virtual bool deserialize(const void *data, size_t flags)  { return false; };
78 
79             /** Get type of the LV2 port in terms of Atom
80              *
81              * @return type of the LV2 port in terms of Atom
82              */
get_type_urid()83             virtual LV2_URID get_type_urid()            { return 0;         };
84 
85             /** Check that the port is pending for transmission
86              *
87              * @return true if the port is pending for transmission
88              */
tx_pending()89             virtual bool tx_pending()                   { return false;     };
90 
91             /**
92              * Callback: UI has connected to backend
93              */
ui_connected()94             virtual void ui_connected()                 { };
95 
96             /** Get the URID of the port in terms of Atom
97              *
98              * @return UIRD of the port
99              */
get_urid()100             inline LV2_URID         get_urid() const    { return urid; }
101 
102             /** Get the URI of the port
103              *
104              * @return URI of the port
105              */
get_uri()106             inline const char      *get_uri() const     { return (pExt->unmap_urid(urid)); }
107 
108             /** Get port ID
109              *
110              * @return poirt ID
111              */
get_id()112             inline ssize_t          get_id() const      { return nID;   }
113 
114             /** Set port ID
115              *
116              * @param id port ID
117              */
set_id(size_t id)118             inline void             set_id(size_t id)   { nID = id;     }
119 
120             /**
121              * Check that port is virtual
122              * @return true if port is virtual (non controlled by DAW and stored in PLUGIN STATE)
123              */
is_virtual()124             inline bool            is_virtual() const  { return bVirtual; }
125     };
126 
127     class LV2PortGroup: public LV2Port
128     {
129         protected:
130             float                   nCurrRow;
131             size_t                  nCols;
132             size_t                  nRows;
133 
134         public:
LV2PortGroup(const port_t * meta,LV2Extensions * ext,bool virt)135             explicit LV2PortGroup(const port_t *meta, LV2Extensions *ext, bool virt) : LV2Port(meta, ext, virt)
136             {
137                 nCurrRow            = meta->start;
138                 nCols               = port_list_size(meta->members);
139                 nRows               = list_size(meta->items);
140             }
141 
~LV2PortGroup()142             virtual ~LV2PortGroup()
143             {
144                 nCurrRow            = 0;
145                 nCols               = 0;
146                 nRows               = 0;
147             }
148 
149         public:
getValue()150             virtual float getValue()
151             {
152                 return nCurrRow;
153             }
154 
setValue(float value)155             virtual void setValue(float value)
156             {
157                 nCurrRow            = value;
158             }
159 
serialize()160             virtual void serialize()
161             {
162                 // Serialize and reset pending flag
163                 pExt->forge_int(nCurrRow);
164             }
165 
deserialize(const void * data,size_t flags)166             virtual bool deserialize(const void *data, size_t flags)
167             {
168                 const LV2_Atom_Int *atom = reinterpret_cast<const LV2_Atom_Int *>(data);
169                 if ((atom->body >= 0) && (atom->body < int32_t(nRows)) && (nCurrRow != atom->body))
170                 {
171                     nCurrRow        = atom->body;
172                     return true;
173                 }
174 
175                 return false;
176             }
177 
save()178             virtual void save()
179             {
180                 if (nID >= 0)
181                     return;
182                 int32_t value   = nCurrRow;
183                 lsp_trace("save port id=%s, urid=%d (%s), value=%d", pMetadata->id, urid, get_uri(), int(value));
184                 pExt->store_value(urid, pExt->forge.Int, &value, sizeof(float));
185             }
186 
restore()187             virtual void restore()
188             {
189                 if (nID >= 0)
190                     return;
191                 lsp_trace("restore port id=%s, urid=%d (%s)", pMetadata->id, urid, get_uri());
192                 size_t count            = 0;
193                 const int32_t *data     = reinterpret_cast<const int32_t *>(pExt->restore_value(urid, pExt->forge.Int, &count));
194                 if ((count != sizeof(int32_t)) || (data == NULL))
195                     return;
196 
197                 if (((*data) >= 0) && ((*data) < int32_t(nRows)))
198                     nCurrRow        = *data;
199             }
200 
get_type_urid()201             virtual LV2_URID get_type_urid()
202             {
203                 return pExt->forge.Int;
204             }
205 
206         public:
rows()207             inline size_t rows() const  { return nRows; }
cols()208             inline size_t cols() const  { return nCols; }
209     };
210 
211     class LV2RawPort: public LV2Port
212     {
213         protected:
214             void       *pBuffer;
215 
216         public:
LV2RawPort(const port_t * meta,LV2Extensions * ext,bool virt)217             explicit LV2RawPort(const port_t *meta, LV2Extensions *ext, bool virt) : LV2Port(meta, ext, virt), pBuffer(NULL) { }
~LV2RawPort()218             virtual ~LV2RawPort() { pBuffer = NULL; };
219 
220         public:
getBuffer()221             virtual void *getBuffer() { return pBuffer; };
222 
bind(void * data)223             virtual void bind(void *data)
224             {
225                 pBuffer = data;
226             };
227     };
228 
229     class LV2AudioPort: public LV2RawPort
230     {
231         protected:
232             float      *pSanitized;
233             float      *pFrame;
234 
235         public:
LV2AudioPort(const port_t * meta,LV2Extensions * ext)236             explicit LV2AudioPort(const port_t *meta, LV2Extensions *ext) : LV2RawPort(meta, ext, false)
237             {
238                 pSanitized  = NULL;
239                 pFrame      = NULL;
240 
241                 if (IS_IN_PORT(pMetadata))
242                 {
243                     size_t length = pExt->nMaxBlockLength;
244                     pSanitized = reinterpret_cast<float *>(::malloc(sizeof(float) * length));
245                     if (pSanitized != NULL)
246                         dsp::fill_zero(pSanitized, length);
247                     else
248                         lsp_warn("Failed to allocate sanitize buffer for port %s", pMetadata->id);
249                 }
250             }
251 
~LV2AudioPort()252             virtual ~LV2AudioPort()
253             {
254                 if (pSanitized != NULL)
255                 {
256                     ::free(pSanitized);
257                     pSanitized = NULL;
258                 }
259             };
260 
getBuffer()261             virtual void *getBuffer() { return pFrame; };
262 
263             // Should be always called at least once after bind() and before processing
sanitize(size_t off,size_t samples)264             void sanitize(size_t off, size_t samples)
265             {
266                 pFrame  = reinterpret_cast<float *>(pBuffer) + off;
267                 if (pSanitized != NULL)
268                 {
269                     dsp::sanitize2(pSanitized, reinterpret_cast<float *>(pFrame), samples);
270                     pFrame      = pSanitized;
271                 }
272             }
273     };
274 
275     class LV2InputPort: public LV2Port
276     {
277         protected:
278             const float    *pData;
279             float           fValue;
280             float           fPrev;
281 
282         public:
LV2InputPort(const port_t * meta,LV2Extensions * ext,bool virt)283             explicit LV2InputPort(const port_t *meta, LV2Extensions *ext, bool virt) : LV2Port(meta, ext, virt)
284             {
285                 pData       = NULL;
286                 fValue      = meta->start;
287                 fPrev       = meta->start;
288             }
289 
~LV2InputPort()290             virtual ~LV2InputPort()
291             {
292                 pData       = NULL;
293                 fValue      = pMetadata->start;
294                 fPrev       = pMetadata->start;
295             }
296 
297         public:
getValue()298             virtual float getValue()
299             {
300                 return fValue;
301             }
302 
setValue(float value)303             virtual void setValue(float value)
304             {
305                 fValue      = value;
306             }
307 
bind(void * data)308             virtual void bind(void *data)
309             {
310                 pData = reinterpret_cast<const float *>(data);
311             };
312 
pre_process(size_t samples)313             virtual bool pre_process(size_t samples)
314             {
315                 if ((nID >= 0) && (pData != NULL))
316                     fValue      = limit_value(pMetadata, *pData);
317                 float old       = fPrev;
318                 fPrev           = fValue;
319                 #ifdef LSP_TRACE
320                 if (fPrev != old)
321                     lsp_trace("Port %s has been changed, value=%f", pMetadata->id, fValue);
322                 #endif
323                 return fPrev != old; // Value has changed?
324             }
325 
save()326             virtual void save()
327             {
328                 if (nID >= 0)
329                     return;
330                 lsp_trace("save port id=%s, urid=%d (%s), value=%f", pMetadata->id, urid, get_uri(), fValue);
331                 pExt->store_value(urid, pExt->forge.Float, &fValue, sizeof(float));
332             }
333 
restore()334             virtual void restore()
335             {
336                 if (nID >= 0)
337                     return;
338                 lsp_trace("restore port id=%s, urid=%d (%s)", pMetadata->id, urid, get_uri());
339                 size_t count            = 0;
340                 const void *data        = pExt->restore_value(urid, pExt->forge.Float, &count);
341                 if ((count == sizeof(float)) && (data != NULL))
342                     fValue      = limit_value(pMetadata, *(reinterpret_cast<const float *>(data)));
343             }
344 
deserialize(const void * data,size_t flags)345             virtual bool deserialize(const void *data, size_t flags)
346             {
347                 const LV2_Atom_Float *atom = reinterpret_cast<const LV2_Atom_Float *>(data);
348                 if (fValue == atom->body)
349                     return false;
350 
351                 fValue      = atom->body;
352                 return true;
353             }
354 
serialize()355             virtual void serialize()
356             {
357                 // Serialize and reset pending flag
358                 pExt->forge_float(fValue);
359                 fPrev       = fValue;
360             }
361 
get_type_urid()362             virtual LV2_URID get_type_urid()
363             {
364                 return pExt->forge.Float;
365             }
366     };
367 
368     class LV2BypassPort: public LV2InputPort
369     {
370         public:
LV2BypassPort(const port_t * meta,LV2Extensions * ext)371             explicit LV2BypassPort(const port_t *meta, LV2Extensions *ext) : LV2InputPort(meta, ext, false) { }
372 
~LV2BypassPort()373             virtual ~LV2BypassPort() {}
374 
375         public:
getValue()376             virtual float getValue()
377             {
378                 return pMetadata->max - fValue;
379             }
380 
setValue(float value)381             virtual void setValue(float value)
382             {
383                 fValue      = pMetadata->max - value;
384             }
385 
save()386             virtual void save()
387             {
388                 if (nID >= 0)
389                     return;
390                 float value = pMetadata->max - fValue;
391                 lsp_trace("save port id=%s, urid=%d (%s), value=%f", pMetadata->id, urid, get_uri(), value);
392                 pExt->store_value(urid, pExt->forge.Float, &value, sizeof(float));
393             }
394 
restore()395             virtual void restore()
396             {
397                 if (nID >= 0)
398                     return;
399                 lsp_trace("restore port id=%s, urid=%d (%s)", pMetadata->id, urid, get_uri());
400                 size_t count            = 0;
401                 const void *data        = pExt->restore_value(urid, pExt->forge.Float, &count);
402                 if ((count == sizeof(float)) && (data != NULL))
403                     fValue      = limit_value(pMetadata, pMetadata->max - *(reinterpret_cast<const float *>(data)));
404             }
405 
deserialize(const void * data,size_t flags)406             virtual bool deserialize(const void *data, size_t flags)
407             {
408                 const LV2_Atom_Float *atom = reinterpret_cast<const LV2_Atom_Float *>(data);
409                 float v = pMetadata->max - atom->body;
410                 if (fValue == v)
411                     return false;
412 
413                 fValue      = v;
414                 return true;
415             }
416     };
417 
418     class LV2OutputPort: public LV2Port
419     {
420         protected:
421             float  *pData;
422             float   fPrev;
423             float   fValue;
424 
425         public:
LV2OutputPort(const port_t * meta,LV2Extensions * ext)426             explicit LV2OutputPort(const port_t *meta, LV2Extensions *ext) : LV2Port(meta, ext, false)
427             {
428                 pData       = NULL;
429                 fPrev       = meta->start;
430                 fValue      = meta->start;
431             }
432 
~LV2OutputPort()433             virtual ~LV2OutputPort()
434             {
435                 pData = NULL;
436             };
437 
438         public:
getValue()439             virtual float getValue()
440             {
441                 return fValue;
442             }
443 
setValue(float value)444             virtual void setValue(float value)
445             {
446                 value       = limit_value(pMetadata, value);
447                 if (pMetadata->flags & F_PEAK)
448                 {
449                     if (fabs(fValue) < fabs(value))
450                         fValue = value;
451                 }
452                 else
453                     fValue = value;
454             }
455 
bind(void * data)456             virtual void bind(void *data)
457             {
458                 pData       = reinterpret_cast<float *>(data);
459             };
460 
pre_process(size_t samples)461             virtual bool pre_process(size_t samples)
462             {
463                 if (pMetadata->flags & F_PEAK)
464                     fValue      = 0.0f;
465                 return false;
466             }
467 
post_process(size_t samples)468             virtual void post_process(size_t samples)
469             {
470                 // Store data i the port
471                 if (pData != NULL)
472                     *pData      = fValue;
473 
474                 // Serialize data and reset tx_pending flag
475                 fPrev       = fValue;
476 
477 //                // Update data according to peak protocol, only for direct-mapped ports
478 //                if ((nID >= 0) && (pMetadata->flags & F_PEAK))
479 //                    fValue      = 0.0f;
480             }
481 
tx_pending()482             virtual bool tx_pending()
483             {
484                 if (fValue != fPrev)
485                     lsp_trace("pending_value id=%s, prev=%f, value=%f", pMetadata->id, fPrev, fValue);
486                 return fValue != fPrev;
487             }
488 
serialize()489             virtual void serialize()
490             {
491                 // Serialize and reset pending flag
492                 pExt->forge_float(fValue);
493 
494                 // Update data according to peak protocol, only for Atom transport ports
495                 if ((nID < 0) && (pMetadata->flags & F_PEAK))
496                     fValue      = 0.0f;
497             }
498 
get_type_urid()499             virtual LV2_URID get_type_urid()
500             {
501                 return pExt->forge.Float;
502             }
503     };
504 
505     class LV2MeshPort: public LV2Port
506     {
507         protected:
508             LV2Mesh                 sMesh;
509 
510         public:
LV2MeshPort(const port_t * meta,LV2Extensions * ext)511             explicit LV2MeshPort(const port_t *meta, LV2Extensions *ext): LV2Port(meta, ext, false)
512             {
513                 sMesh.init(meta, ext);
514             }
515 
~LV2MeshPort()516             virtual ~LV2MeshPort()
517             {
518             };
519 
520         public:
get_type_urid()521             virtual LV2_URID get_type_urid()        { return pExt->uridMeshType; };
522 
getBuffer()523             virtual void *getBuffer()
524             {
525                 return sMesh.pMesh;
526             }
527 
tx_pending()528             virtual bool tx_pending()
529             {
530                 mesh_t *mesh = sMesh.pMesh;
531                 if (mesh == NULL)
532                     return false;
533 
534                 // Return true only if mesh contains data
535                 return mesh->containsData();
536             };
537 
serialize()538             virtual void serialize()
539             {
540                 mesh_t *mesh = sMesh.pMesh;
541 
542                 // Forge number of vectors (dimensions)
543                 pExt->forge_key(pExt->uridMeshDimensions);
544                 pExt->forge_int(mesh->nBuffers);
545 
546                 // Forge number of items per vector
547                 pExt->forge_key(pExt->uridMeshItems);
548                 pExt->forge_int(mesh->nItems);
549 
550                 // Forge vectors
551                 for (size_t i=0; i < mesh->nBuffers; ++i)
552                 {
553                     pExt->forge_key(pExt->uridMeshData);
554                     pExt->forge_vector(sizeof(float), pExt->forge.Float, mesh->nItems, mesh->pvData[i]);
555                 }
556 
557                 // Set mesh waiting until next frame is allowed
558                 mesh->setWaiting();
559             }
560     };
561 
562     class LV2StreamPort: public LV2Port
563     {
564         protected:
565             stream_t           *pStream;
566             uint32_t            nFrameID;
567             float              *pData;
568 
569         public:
LV2StreamPort(const port_t * meta,LV2Extensions * ext)570             explicit LV2StreamPort(const port_t *meta, LV2Extensions *ext): LV2Port(meta, ext, false)
571             {
572                 pStream     = stream_t::create(pMetadata->min, pMetadata->max, pMetadata->start);
573                 pData       = reinterpret_cast<float *>(::malloc(sizeof(float) * STREAM_MAX_FRAME_SIZE));
574                 nFrameID    = 0;
575             }
576 
~LV2StreamPort()577             virtual ~LV2StreamPort()
578             {
579                 stream_t::destroy(pStream);
580                 pStream     = NULL;
581 
582                 if (pData != NULL)
583                 {
584                     ::free(pData);
585                     pData       = NULL;
586                 }
587             };
588 
589         public:
get_type_urid()590             virtual LV2_URID get_type_urid()        { return pExt->uridFrameBufferType; };
591 
getBuffer()592             virtual void *getBuffer()
593             {
594                 return pStream;
595             }
596 
tx_pending()597             virtual bool tx_pending()
598             {
599                 return nFrameID != pStream->frame_id();
600             }
601 
ui_connected()602             virtual void ui_connected()
603             {
604                 // We need to replay buffer contents for the connected client
605                 lsp_trace("UI connected event");
606                 nFrameID    = pStream->frame_id() - pStream->frames();
607             }
608 
serialize()609             virtual void serialize()
610             {
611                 // Serialize not more than number of predefined frames
612                 uint32_t frame_id   = nFrameID;
613                 size_t src_id       = pStream->frame_id();
614                 size_t delta        = src_id - nFrameID;
615                 if (delta > pStream->frames())
616                     frame_id            = src_id - pStream->frames();
617                 if (delta > STREAM_BULK_MAX)
618                     delta = STREAM_BULK_MAX;
619                 size_t last_id          = frame_id + delta;
620 
621                 lsp_trace("id = %s, first=%d, last=%d", pMetadata->id, int(frame_id), int(last_id));
622 
623                 // Forge frame buffer parameters
624                 size_t nbuffers = pStream->channels();
625 
626                 pExt->forge_key(pExt->uridStreamDimensions);
627                 pExt->forge_int(nbuffers);
628 
629                 // Forge vectors
630                 for ( ; frame_id != last_id; ++frame_id)
631                 {
632                     LV2_Atom_Forge_Frame frame;
633                     size_t size = pStream->get_size(frame_id);
634 //                    lsp_trace("frame id=%d, size=%d", int(frame_id), int(size));
635 
636                     pExt->forge_key(pExt->uridStreamFrame);
637                     pExt->forge_object(&frame, pExt->uridBlank, pExt->uridStreamFrameType);
638                     {
639                         pExt->forge_key(pExt->uridStreamFrameId);
640                         pExt->forge_int(frame_id);
641 
642                         pExt->forge_key(pExt->uridStreamFrameSize);
643                         pExt->forge_int(size);
644 
645                         // Forge vectors
646                         for (size_t i=0; i < nbuffers; ++i)
647                         {
648                             pStream->read(i, pData, 0, size);
649 
650                             pExt->forge_key(pExt->uridStreamFrameData);
651                             pExt->forge_vector(sizeof(float), pExt->forge.Float, size, pData);
652                         }
653                     }
654                     pExt->forge_pop(&frame);
655                 }
656 
657                 // Update current RowID
658                 nFrameID    = frame_id;
659             }
660     };
661 
662 
663     class LV2FrameBufferPort: public LV2Port
664     {
665         protected:
666             frame_buffer_t      sFB;
667             size_t              nRowID;
668 
669         public:
LV2FrameBufferPort(const port_t * meta,LV2Extensions * ext)670             explicit LV2FrameBufferPort(const port_t *meta, LV2Extensions *ext): LV2Port(meta, ext, false)
671             {
672                 sFB.init(meta->start, meta->step);
673                 nRowID = 0;
674             }
675 
~LV2FrameBufferPort()676             virtual ~LV2FrameBufferPort()
677             {
678             };
679 
680         public:
get_type_urid()681             virtual LV2_URID get_type_urid()        { return pExt->uridFrameBufferType; };
682 
getBuffer()683             virtual void *getBuffer()
684             {
685                 return &sFB;
686             }
687 
tx_pending()688             virtual bool tx_pending()
689             {
690                 return sFB.next_rowid() != nRowID;
691             }
692 
ui_connected()693             virtual void ui_connected()
694             {
695                 // We need to replay buffer contents for the connected client
696                 lsp_trace("UI connected event");
697                 nRowID      = sFB.next_rowid() - sFB.rows();
698             }
699 
serialize()700             virtual void serialize()
701             {
702                 // Serialize not more than 4 rows
703                 size_t delta = sFB.next_rowid() - nRowID;
704                 uint32_t first_row = (delta > sFB.rows()) ? sFB.next_rowid() - sFB.rows() : nRowID;
705                 if (delta > FRAMEBUFFER_BULK_MAX)
706                     delta = FRAMEBUFFER_BULK_MAX;
707                 uint32_t last_row = first_row + delta;
708 
709                 lsp_trace("id = %s, first=%d, last=%d", pMetadata->id, int(first_row), int(last_row));
710 
711                 // Forge frame buffer parameters
712                 pExt->forge_key(pExt->uridFrameBufferRows);
713                 pExt->forge_int(sFB.rows());
714                 pExt->forge_key(pExt->uridFrameBufferCols);
715                 pExt->forge_int(sFB.cols());
716                 pExt->forge_key(pExt->uridFrameBufferFirstRowID);
717                 pExt->forge_int(first_row);
718                 pExt->forge_key(pExt->uridFrameBufferLastRowID);
719                 pExt->forge_int(last_row);
720 
721                 // Forge vectors
722                 while (first_row != last_row)
723                 {
724                     pExt->forge_key(pExt->uridFrameBufferData);
725                     pExt->forge_vector(sizeof(float), pExt->forge.Float, sFB.cols(), sFB.get_row(first_row++));
726                 }
727 
728                 // Update current RowID
729                 nRowID = first_row;
730             }
731     };
732 
733     class LV2PathPort: public LV2Port
734     {
735         protected:
736             lv2_path_t          sPath;
737             atomic_t            nLastChange;
738 
set_string(const char * string,size_t len,size_t flags)739             inline void set_string(const char *string, size_t len, size_t flags)
740             {
741                 lsp_trace("submitting path to '%s' (length = %d), flags=0x%x", string, int(len), int(flags));
742                 sPath.submit(string, len, flags);
743             }
744 
745         public:
LV2PathPort(const port_t * meta,LV2Extensions * ext)746             explicit LV2PathPort(const port_t *meta, LV2Extensions *ext): LV2Port(meta, ext, true)
747             {
748                 sPath.init();
749                 nLastChange = sPath.nChanges;
750             }
751 
752         public:
getBuffer()753             virtual void *getBuffer()
754             {
755                 return static_cast<path_t *>(&sPath);
756             }
757 
save()758             virtual void save()
759             {
760                 const char *path = sPath.sPath;
761 
762                 lsp_trace("save port id=%s, urid=%d (%s), value=%s", pMetadata->id, urid, get_uri(), path);
763 
764                 if (::strlen(path) > 0)
765                 {
766                     char *mapped = NULL;
767 
768                     // We need to translate absolute path to relative path?
769                     if ((pExt->mapPath != NULL) && (::strstr(path, LSP_BUILTIN_PREFIX) != path))
770                     {
771                         mapped = pExt->mapPath->abstract_path(pExt->mapPath->handle, path);
772                         if (mapped != NULL)
773                         {
774                             lsp_trace("mapped path: %s -> %s", path, mapped);
775                             path = mapped;
776                         }
777                     }
778 
779                     // Store the actual value of the path
780                     pExt->store_value(urid, pExt->uridPathType, path, ::strlen(path) + sizeof(char));
781 
782                     if (mapped != NULL)
783                         ::free(mapped);
784                 }
785             }
786 
tx_request()787             void tx_request()
788             {
789                 lsp_trace("tx_request");
790                 atomic_add(&sPath.nChanges, 1);
791             }
792 
restore()793             virtual void restore()
794             {
795                 lsp_trace("restore port id=%s, urid=%d (%s)", pMetadata->id, urid, get_uri());
796                 size_t count            = 0;
797                 uint32_t type           = -1;
798 
799                 const char *path        = reinterpret_cast<const char *>(pExt->retrieve_value(urid, &type, &count));
800                 char *mapped            = NULL;
801                 if (path != NULL)
802                 {
803                     if (type == pExt->forge.URID)
804                     {
805                         const LV2_URID *urid    = reinterpret_cast<const LV2_URID *>(path);
806                         path                = pExt->unmap_urid(*urid);
807                         if (path != NULL)
808                             count               = ::strnlen(path, PATH_MAX-1);
809                     }
810                     else if ((type != pExt->uridPathType) && (type != pExt->forge.String))
811                     {
812                         if (path != NULL)
813                             lsp_trace("Invalid type: %d = %s", int(type), pExt->unmap_urid(type));
814                         path                    = NULL;
815                     }
816                 }
817 
818                 if ((path != NULL) && (count > 0))
819                 {
820                     // Save path as temporary variable
821                     char tmp_path[PATH_MAX];
822                     ::strncpy(tmp_path, path, count);
823                     tmp_path[count] = '\0';
824                     path        = tmp_path;
825 
826                     // We need to translate relative path to absolute path?
827                     if ((pExt->mapPath != NULL) && (::strstr(path, LSP_BUILTIN_PREFIX) != path))
828                     {
829                         mapped = pExt->mapPath->absolute_path(pExt->mapPath->handle, path);
830                         if (mapped != NULL)
831                         {
832                             lsp_trace("unmapped path: %s -> %s", path, mapped);
833                             path  = mapped;
834                             count = ::strnlen(path, PATH_MAX-1);
835                         }
836                     }
837 
838                     // Restore the actual value of the path
839                     set_string(path, count, PF_STATE_IMPORT);
840                 }
841                 else
842                     set_string("", 0, PF_STATE_IMPORT);
843                 tx_request();
844 
845                 if (mapped != NULL)
846                     ::free(mapped);
847             }
848 
tx_pending()849             virtual bool tx_pending()
850             {
851                 return sPath.nChanges != nLastChange;
852             }
853 
reset_tx_pending()854             void reset_tx_pending()
855             {
856                 lsp_trace("reset_tx_pending");
857                 nLastChange     = sPath.nChanges;
858             }
859 
serialize()860             virtual void serialize()
861             {
862                 pExt->forge_path(sPath.get_path());
863                 reset_tx_pending();
864             }
865 
deserialize(const void * data,size_t flags)866             virtual bool deserialize(const void *data, size_t flags)
867             {
868                 const LV2_Atom *atom = static_cast<const LV2_Atom *>(data);
869                 if (atom->type != pExt->uridPathType)
870                     return false;
871 
872                 set_string(reinterpret_cast<const char *>(atom + 1), atom->size, flags);
873                 return true;
874             }
875 
get_type_urid()876             virtual LV2_URID get_type_urid()    { return pExt->uridPathType; }
877 
pre_process(size_t samples)878             virtual bool pre_process(size_t samples)
879             {
880                 return sPath.pending();
881             }
882     };
883 
884     class LV2MidiPort: public LV2Port
885     {
886         protected:
887             midi_t      sQueue;
888 
889         public:
LV2MidiPort(const port_t * meta,LV2Extensions * ext)890             explicit LV2MidiPort(const port_t *meta, LV2Extensions *ext): LV2Port(meta, ext, false)
891             {
892                 sQueue.clear();
893             }
894 
895         public:
getBuffer()896             virtual void *getBuffer()
897             {
898                 return &sQueue;
899             }
900     };
901 
902     class LV2OscPort: public LV2Port
903     {
904         protected:
905             osc_buffer_t     *pFB;
906 
907         public:
LV2OscPort(const port_t * meta,LV2Extensions * ext)908             explicit LV2OscPort(const port_t *meta, LV2Extensions *ext) : LV2Port(meta, ext, false)
909             {
910                 pFB     = NULL;
911             }
912 
~LV2OscPort()913             virtual ~LV2OscPort()
914             {
915             }
916 
917         public:
getBuffer()918             virtual void *getBuffer()
919             {
920                 return pFB;
921             }
922 
init()923             virtual int init()
924             {
925                 pFB = osc_buffer_t::create(OSC_BUFFER_MAX);
926                 return (pFB == NULL) ? STATUS_NO_MEM : STATUS_OK;
927             }
928 
destroy()929             virtual void destroy()
930             {
931                 if (pFB != NULL)
932                 {
933                     osc_buffer_t::destroy(pFB);
934                     pFB     = NULL;
935                 }
936             }
937     };
938 
939 }
940 
941 
942 #endif /* CONTAINER_LV2_PORTS_H_ */
943