1 /*
2  * Copyright (C) 2021 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2021 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 7 февр. 2021 г.
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 #include <ui/ctl/ctl.h>
23 #include <core/port_data.h>
24 
25 namespace lsp
26 {
27     namespace ctl
28     {
29         const ctl_class_t CtlStream::metadata = { "CtlStream", &CtlWidget::metadata };
30 
CtlStream(CtlRegistry * src,LSPMesh * mesh)31         CtlStream::CtlStream(CtlRegistry *src, LSPMesh *mesh): CtlWidget(src, mesh)
32         {
33             pClass          = &metadata;
34             pPort           = NULL;
35             nMaxDots        = -1;
36             fTransparency   = 0.0f;
37             pMesh           = NULL;
38         }
39 
~CtlStream()40         CtlStream::~CtlStream()
41         {
42             if (pMesh != NULL)
43             {
44                 mesh_t::destroy(pMesh);
45                 pMesh   = NULL;
46             }
47 
48             sStrobes.destroy();
49             sMaxDots.destroy();
50         }
51 
init()52         void CtlStream::init()
53         {
54             CtlWidget::init();
55 
56             LSPMesh *mesh       = widget_cast<LSPMesh>(pWidget);
57             if (mesh == NULL)
58                 return;
59 
60             // Initialize color controllers
61             sColor.init_hsl(pRegistry, mesh, mesh->color(), A_COLOR, A_HUE_ID, A_SAT_ID, A_LIGHT_ID);
62 
63             // Initialize expressions
64             sStrobes.init(pRegistry, this);
65             sMaxDots.init(pRegistry, this);
66         }
67 
set(widget_attribute_t att,const char * value)68         void CtlStream::set(widget_attribute_t att, const char *value)
69         {
70             LSPMesh *mesh = widget_cast<LSPMesh>(pWidget);
71 
72             switch (att)
73             {
74                 case A_ID:
75                     BIND_PORT(pRegistry, pPort, value);
76                     break;
77                 case A_WIDTH:
78                     if (mesh != NULL)
79                         PARSE_INT(value, mesh->set_line_width(__));
80                     break;
81                 case A_CENTER:
82                     if (mesh != NULL)
83                         PARSE_INT(value, mesh->set_center_id(__));
84                     break;
85                 case A_FILL:
86                     PARSE_FLOAT(value, fTransparency = __);
87                     break;
88                 case A_X_INDEX:
89                     if (mesh != NULL)
90                         PARSE_INT(value, mesh->set_x_index(__));
91                     break;
92                 case A_Y_INDEX:
93                     if (mesh != NULL)
94                         PARSE_INT(value, mesh->set_y_index(__));
95                     break;
96                 case A_S_INDEX:
97                     if (mesh != NULL)
98                         PARSE_INT(value, mesh->set_s_index(__));
99                     break;
100                 case A_STROBE:
101                     if (mesh != NULL)
102                         PARSE_BOOL(value, mesh->set_strobes(__));
103                     break;
104                 case A_STROBES:
105                     BIND_EXPR(sStrobes, value);
106                     break;
107                 case A_MAX_DOTS:
108                     BIND_EXPR(sMaxDots, value);
109                     break;
110                 default:
111                 {
112                     bool set = sColor.set(att, value);
113                     if (!set)
114                         CtlWidget::set(att, value);
115                     break;
116                 }
117             }
118         }
119 
end()120         void CtlStream::end()
121         {
122             sColor.set_alpha(fTransparency);
123             CtlWidget::end();
124 
125             trigger_expr();
126         }
127 
trigger_expr()128         void CtlStream::trigger_expr()
129         {
130             LSPMesh *mesh = widget_cast<LSPMesh>(pWidget);
131 
132             if (sMaxDots.valid())
133             {
134                 ssize_t dots = sMaxDots.evaluate();
135                 if (nMaxDots != dots)
136                 {
137                     nMaxDots = dots;
138                     commit_data();
139                 }
140             }
141 
142             if ((mesh != NULL) && (sStrobes.valid()))
143             {
144                 ssize_t value = sStrobes.evaluate();
145                 mesh->set_num_strobes(value);
146             }
147         }
148 
notify(CtlPort * port)149         void CtlStream::notify(CtlPort *port)
150         {
151             CtlWidget::notify(port);
152 
153             // Trigger expressions
154             trigger_expr();
155 
156             // Commit stream data
157             if ((port != NULL) && (port == pPort))
158                 commit_data();
159         }
160 
commit_data()161         void CtlStream::commit_data()
162         {
163             LSPMesh *mesh = widget_cast<LSPMesh>(pWidget);
164             if (mesh == NULL)
165                 return;
166 
167             const port_t *mdata = pPort->metadata();
168             if ((mdata == NULL) || (mdata->role != R_STREAM))
169                 return;
170 
171             stream_t *stream  = pPort->get_buffer<stream_t>();
172             if (stream == NULL)
173                 return;
174 
175             // Need to create mesh?
176             if (pMesh == NULL)
177             {
178                 pMesh   = mesh_t::create(stream->channels(), stream->capacity());
179                 if (pMesh == NULL)
180                     return;
181                 pMesh->nBuffers = stream->channels();
182             }
183 
184             // Perform read from stream to mesh
185             size_t last     = stream->frame_id();
186             ssize_t length  = stream->get_length(last);
187             ssize_t dots    = (nMaxDots >= 0) ? lsp_min(length, nMaxDots) : length;
188             ssize_t off     = length - dots;
189 
190             for (size_t i=0, n=stream->channels(); i<n; ++i)
191                 stream->read(i, pMesh->pvData[i], off, dots);
192 
193 //            #ifdef LSP_TRACE
194 //                const float *vx = pMesh->pvData[0];
195 //                const float *vy = pMesh->pvData[1];
196 //                const float *vs = pMesh->pvData[2];
197 //
198 //                for (ssize_t i=1; i < dots; ++i)
199 //                {
200 //                    float dx    = vx[i] - vx[i-1];
201 //                    float dy    = vy[i] - vy[i-1];
202 //                    float s     = dx*dx + dy*dy;
203 //                    if ((s >= 0.125f) && (vs[i] <= 0.5f))
204 //                    {
205 //                        lsp_trace("debug");
206 //                    }
207 //                }
208 //            #endif
209 
210             // Set data to mesh
211             mesh->set_data(pMesh->nBuffers, dots, const_cast<const float **>(pMesh->pvData));
212         }
213     } /* namespace ctl */
214 } /* namespace lsp */
215 
216 
217