1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2021 Joël Krähemann
3 *
4 * This file is part of GSequencer.
5 *
6 * GSequencer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GSequencer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GSequencer. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <ags/plugin/ags_vst3_plugin.h>
21
22 #include <ags/plugin/ags_plugin_port.h>
23
24 #include <math.h>
25
26 #if defined(AGS_W32API)
27 #include <windows.h>
28 #else
29 #include <dlfcn.h>
30 #endif
31
32 void ags_vst3_plugin_class_init(AgsVst3PluginClass *vst3_plugin);
33 void ags_vst3_plugin_init (AgsVst3Plugin *vst3_plugin);
34 void ags_vst3_plugin_set_property(GObject *gobject,
35 guint prop_id,
36 const GValue *value,
37 GParamSpec *param_spec);
38 void ags_vst3_plugin_get_property(GObject *gobject,
39 guint prop_id,
40 GValue *value,
41 GParamSpec *param_spec);
42 void ags_vst3_plugin_finalize(GObject *gobject);
43
44 gpointer ags_vst3_plugin_instantiate(AgsBasePlugin *base_plugin,
45 guint samplerate, guint buffer_size);
46 void ags_vst3_plugin_connect_port(AgsBasePlugin *base_plugin,
47 gpointer plugin_handle,
48 guint port_index,
49 gpointer data_location);
50 void ags_vst3_plugin_activate(AgsBasePlugin *base_plugin,
51 gpointer plugin_handle);
52 void ags_vst3_plugin_deactivate(AgsBasePlugin *base_plugin,
53 gpointer plugin_handle);
54 void ags_vst3_plugin_run(AgsBasePlugin *base_plugin,
55 gpointer plugin_handle,
56 snd_seq_event_t *seq_event,
57 guint frame_count);
58 void ags_vst3_plugin_load_plugin(AgsBasePlugin *base_plugin);
59
60 /**
61 * SECTION:ags_vst3_plugin
62 * @short_description: The vst3 plugin class
63 * @title: AgsVst3Plugin
64 * @section_id:
65 * @include: ags/plugin/ags_vst3_plugin.h
66 *
67 * The #AgsVst3Plugin loads/unloads a Vst3 plugin.
68 */
69
70 enum{
71 PROP_0,
72 };
73
74 enum{
75 LAST_SIGNAL,
76 };
77
78 static gpointer ags_vst3_plugin_parent_class = NULL;
79 static guint vst3_plugin_signals[LAST_SIGNAL];
80
81 GType
ags_vst3_plugin_get_type(void)82 ags_vst3_plugin_get_type (void)
83 {
84 static volatile gsize g_define_type_id__volatile = 0;
85
86 if(g_once_init_enter (&g_define_type_id__volatile)){
87 GType ags_type_vst3_plugin = 0;
88
89 static const GTypeInfo ags_vst3_plugin_info = {
90 sizeof (AgsVst3PluginClass),
91 NULL, /* vst3_init */
92 NULL, /* vst3_finalize */
93 (GClassInitFunc) ags_vst3_plugin_class_init,
94 NULL, /* class_finalize */
95 NULL, /* class_data */
96 sizeof (AgsVst3Plugin),
97 0, /* n_preallocs */
98 (GInstanceInitFunc) ags_vst3_plugin_init,
99 };
100
101 ags_type_vst3_plugin = g_type_register_static(AGS_TYPE_BASE_PLUGIN,
102 "AgsVst3Plugin",
103 &ags_vst3_plugin_info,
104 0);
105
106 g_once_init_leave(&g_define_type_id__volatile, ags_type_vst3_plugin);
107 }
108
109 return g_define_type_id__volatile;
110 }
111
112 void
ags_vst3_plugin_class_init(AgsVst3PluginClass * vst3_plugin)113 ags_vst3_plugin_class_init(AgsVst3PluginClass *vst3_plugin)
114 {
115 AgsBasePluginClass *base_plugin;
116
117 GObjectClass *gobject;
118 GParamSpec *param_spec;
119
120 ags_vst3_plugin_parent_class = g_type_class_peek_parent(vst3_plugin);
121
122 /* GObjectClass */
123 gobject = (GObjectClass *) vst3_plugin;
124
125 gobject->set_property = ags_vst3_plugin_set_property;
126 gobject->get_property = ags_vst3_plugin_get_property;
127
128 gobject->finalize = ags_vst3_plugin_finalize;
129
130 /* properties */
131
132 /* AgsBasePluginClass */
133 base_plugin = (AgsBasePluginClass *) vst3_plugin;
134
135 base_plugin->instantiate = ags_vst3_plugin_instantiate;
136
137 base_plugin->connect_port = ags_vst3_plugin_connect_port;
138
139 base_plugin->activate = ags_vst3_plugin_activate;
140 base_plugin->deactivate = ags_vst3_plugin_deactivate;
141
142 base_plugin->run = ags_vst3_plugin_run;
143
144 base_plugin->load_plugin = ags_vst3_plugin_load_plugin;
145
146 /* AgsVst3PluginClass */
147 }
148
149 void
ags_vst3_plugin_init(AgsVst3Plugin * vst3_plugin)150 ags_vst3_plugin_init(AgsVst3Plugin *vst3_plugin)
151 {
152 vst3_plugin->get_plugin_factory = NULL;
153
154 vst3_plugin->host_context = NULL;
155
156 vst3_plugin->icomponent = NULL;
157 vst3_plugin->iedit_controller = NULL;
158 }
159
160 void
ags_vst3_plugin_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)161 ags_vst3_plugin_set_property(GObject *gobject,
162 guint prop_id,
163 const GValue *value,
164 GParamSpec *param_spec)
165 {
166 AgsVst3Plugin *vst3_plugin;
167
168 GRecMutex *base_plugin_mutex;
169
170 vst3_plugin = AGS_VST3_PLUGIN(gobject);
171
172 /* get base plugin mutex */
173 base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(vst3_plugin);
174
175 switch(prop_id){
176 default:
177 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
178 break;
179 }
180 }
181
182 void
ags_vst3_plugin_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)183 ags_vst3_plugin_get_property(GObject *gobject,
184 guint prop_id,
185 GValue *value,
186 GParamSpec *param_spec)
187 {
188 AgsVst3Plugin *vst3_plugin;
189
190 GRecMutex *base_plugin_mutex;
191
192 vst3_plugin = AGS_VST3_PLUGIN(gobject);
193
194 /* get base plugin mutex */
195 base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(vst3_plugin);
196
197 switch(prop_id){
198 default:
199 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
200 break;
201 }
202 }
203
204 void
ags_vst3_plugin_finalize(GObject * gobject)205 ags_vst3_plugin_finalize(GObject *gobject)
206 {
207 AgsVst3Plugin *vst3_plugin;
208
209 vst3_plugin = AGS_VST3_PLUGIN(gobject);
210
211 /* call parent */
212 G_OBJECT_CLASS(ags_vst3_plugin_parent_class)->finalize(gobject);
213 }
214
215 gpointer
ags_vst3_plugin_instantiate(AgsBasePlugin * base_plugin,guint samplerate,guint buffer_size)216 ags_vst3_plugin_instantiate(AgsBasePlugin *base_plugin,
217 guint samplerate, guint buffer_size)
218 {
219 AgsVstIPluginFactory *iplugin_factory;
220
221 gpointer retval;
222
223 guint i, i_stop;
224
225 AgsVstIPluginFactory* (*GetPluginFactory)();
226
227 GRecMutex *base_plugin_mutex;
228
229 /* get base plugin mutex */
230 base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(base_plugin);
231
232 /* get instantiate */
233 g_rec_mutex_lock(base_plugin_mutex);
234
235 GetPluginFactory = AGS_VST3_PLUGIN(base_plugin)->get_plugin_factory;
236
237 g_rec_mutex_unlock(base_plugin_mutex);
238
239 retval = NULL;
240
241 if(GetPluginFactory != NULL){
242 AgsVstPClassInfo *info;
243
244 AgsVstTResult val;
245
246 iplugin_factory = GetPluginFactory();
247
248 info = ags_vst_pclass_info_alloc();
249
250 i_stop = ags_vst_iplugin_factory_count_classes(iplugin_factory);
251
252 for(i = 0; i < i_stop; i++){
253 ags_vst_iplugin_factory_get_class_info(iplugin_factory,
254 i, info);
255
256 if(!g_strcmp0(ags_vst_pclass_info_get_category(&info), AGS_VST_KAUDIO_EFFECT_CLASS) == FALSE){
257 continue;
258 }
259
260 AGS_VST3_PLUGIN(base_plugin)->icomponent = NULL;
261
262 val = ags_vst_iplugin_factory_create_instance(iplugin_factory,
263 ags_vst_pclass_info_get_cid(&info),
264 ags_vst_icomponent_get_iid(),
265 (void **) &(AGS_VST3_PLUGIN(base_plugin)->icomponent));
266
267 if(val != AGS_VST_KRESULT_TRUE){
268 g_warning("failed to create VST3 instance with plugin factory");
269
270 break;
271 }
272
273 ags_vst_icomponent_set_io_mode(AGS_VST3_PLUGIN(base_plugin)->icomponent,
274 AGS_VST_KADVANCED);
275
276 AGS_VST3_PLUGIN(base_plugin)->host_context = ags_vst_host_context_get_instance();
277
278 ags_vst_iplugin_base_initialize((AgsVstIPluginBase *) AGS_VST3_PLUGIN(base_plugin)->icomponent,
279 AGS_VST3_PLUGIN(base_plugin)->host_context);
280
281
282 AGS_VST3_PLUGIN(base_plugin)->iedit_controller = NULL;
283
284 val = ags_vst_iplugin_factory_create_instance(iplugin_factory,
285 ags_vst_pclass_info_get_cid(&info),
286 ags_vst_iedit_controller_get_iid(),
287 (void **) &(AGS_VST3_PLUGIN(base_plugin)->iedit_controller));
288
289 if(val != AGS_VST_KRESULT_TRUE){
290 g_warning("failed to create VST3 instance with plugin factory");
291
292 break;
293 }
294
295 ags_vst_iplugin_base_initialize((AgsVstIPluginBase *) AGS_VST3_PLUGIN(base_plugin)->iedit_controller,
296 AGS_VST3_PLUGIN(base_plugin)->host_context);
297
298 break;
299 }
300 }
301
302
303 return(retval);
304 }
305
306 void
ags_vst3_plugin_connect_port(AgsBasePlugin * base_plugin,gpointer plugin_handle,guint port_index,gpointer data_location)307 ags_vst3_plugin_connect_port(AgsBasePlugin *base_plugin,
308 gpointer plugin_handle,
309 guint port_index,
310 gpointer data_location)
311 {
312 //TODO:JK: implement me
313 }
314
315 void
ags_vst3_plugin_activate(AgsBasePlugin * base_plugin,gpointer plugin_handle)316 ags_vst3_plugin_activate(AgsBasePlugin *base_plugin,
317 gpointer plugin_handle)
318 {
319 //TODO:JK: implement me
320 }
321
322 void
ags_vst3_plugin_deactivate(AgsBasePlugin * base_plugin,gpointer plugin_handle)323 ags_vst3_plugin_deactivate(AgsBasePlugin *base_plugin,
324 gpointer plugin_handle)
325 {
326 //TODO:JK: implement me
327 }
328
329 void
ags_vst3_plugin_run(AgsBasePlugin * base_plugin,gpointer plugin_handle,snd_seq_event_t * seq_event,guint frame_count)330 ags_vst3_plugin_run(AgsBasePlugin *base_plugin,
331 gpointer plugin_handle,
332 snd_seq_event_t *seq_event,
333 guint frame_count)
334 {
335 //TODO:JK: implement me
336 }
337
338 void
ags_vst3_plugin_load_plugin(AgsBasePlugin * base_plugin)339 ags_vst3_plugin_load_plugin(AgsBasePlugin *base_plugin)
340 {
341 AgsVstIPluginFactory *iplugin_factory;
342
343 GList *plugin_port;
344
345 gpointer retval;
346
347 guint i, i_stop;
348 gboolean success;
349
350 GError *error;
351
352 AgsVstIPluginFactory* (*GetPluginFactory)();
353
354 GRecMutex *base_plugin_mutex;
355
356 /* get base plugin mutex */
357 base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(base_plugin);
358
359 /* dlopen */
360 g_rec_mutex_lock(base_plugin_mutex);
361
362 #ifdef AGS_W32API
363 base_plugin->plugin_so = LoadLibrary(base_plugin->filename);
364 #else
365 base_plugin->plugin_so = dlopen(base_plugin->filename,
366 RTLD_NOW);
367 #endif
368
369 if(base_plugin->plugin_so == NULL){
370 g_warning("ags_vst3_plugin.c - failed to load static object file");
371
372 #ifndef AGS_W32API
373 dlerror();
374 #endif
375
376 g_rec_mutex_unlock(base_plugin_mutex);
377
378 return;
379 }
380
381 plugin_port = NULL;
382
383 success = FALSE;
384
385 #ifdef AGS_W32API
386 GetPluginFactory =
387 AGS_VST3_PLUGIN(base_plugin)->get_plugin_factory = GetProcAddress(base_plugin->plugin_so,
388 "GetPluginFactory");
389
390 success = (AGS_VST3_PLUGIN(base_plugin)->get_plugin_factory != NULL) ? TRUE: FALSE;
391 #else
392 GetPluginFactory =
393 AGS_VST3_PLUGIN(base_plugin)->get_plugin_factory = dlsym(base_plugin->plugin_so,
394 "GetPluginFactory");
395
396 success = (dlerror() == NULL) ? TRUE: FALSE;
397 #endif
398
399 g_rec_mutex_unlock(base_plugin_mutex);
400
401 if(success){
402 AgsVstPClassInfo *info;
403
404 AgsVstTResult val;
405
406 iplugin_factory = GetPluginFactory();
407
408 info = ags_vst_pclass_info_alloc();
409
410 i_stop = ags_vst_iplugin_factory_count_classes(iplugin_factory);
411
412 for(i = 0; i < i_stop; i++){
413 ags_vst_iplugin_factory_get_class_info(iplugin_factory,
414 i, info);
415
416 if(!g_strcmp0(ags_vst_pclass_info_get_category(&info), AGS_VST_KAUDIO_EFFECT_CLASS) == FALSE){
417 continue;
418 }
419
420 AGS_VST3_PLUGIN(base_plugin)->icomponent = NULL;
421
422 val = ags_vst_iplugin_factory_create_instance(iplugin_factory,
423 ags_vst_pclass_info_get_cid(&info),
424 ags_vst_icomponent_get_iid(),
425 (void **) &(AGS_VST3_PLUGIN(base_plugin)->icomponent));
426
427 if(val != AGS_VST_KRESULT_TRUE){
428 g_warning("failed to create VST3 instance with plugin factory");
429
430 break;
431 }
432
433 ags_vst_icomponent_set_io_mode(AGS_VST3_PLUGIN(base_plugin)->icomponent,
434 AGS_VST_KADVANCED);
435
436 AGS_VST3_PLUGIN(base_plugin)->host_context = ags_vst_host_context_get_instance();
437
438 ags_vst_iplugin_base_initialize((AgsVstIPluginBase *) AGS_VST3_PLUGIN(base_plugin)->icomponent,
439 AGS_VST3_PLUGIN(base_plugin)->host_context);
440
441
442 AGS_VST3_PLUGIN(base_plugin)->iedit_controller = NULL;
443
444 val = ags_vst_iplugin_factory_create_instance(iplugin_factory,
445 ags_vst_pclass_info_get_cid(&info),
446 ags_vst_iedit_controller_get_iid(),
447 (void **) &(AGS_VST3_PLUGIN(base_plugin)->iedit_controller));
448
449 if(val != AGS_VST_KRESULT_TRUE){
450 g_warning("failed to create VST3 instance with plugin factory");
451
452 break;
453 }
454
455 ags_vst_iplugin_base_initialize((AgsVstIPluginBase *) AGS_VST3_PLUGIN(base_plugin)->iedit_controller,
456 AGS_VST3_PLUGIN(base_plugin)->host_context);
457
458 break;
459 }
460
461 i_stop = ags_vst_iedit_controller_get_parameter_count(AGS_VST3_PLUGIN(base_plugin)->iedit_controller);
462
463 for(i = 0; i < i_stop; i++){
464 AgsPluginPort *current_plugin_port;
465
466 AgsVstParameterInfo *info;
467 AgsVstParamID *id;
468
469 guint flags;
470 gint32 step_count;
471 AgsVstParamValue default_normalized_value;
472
473 current_plugin_port = ags_plugin_port_new();
474 g_object_ref(current_plugin_port);
475
476 plugin_port = g_list_prepend(plugin_port,
477 current_plugin_port);
478
479 g_value_init(current_plugin_port->default_value,
480 G_TYPE_FLOAT);
481 g_value_init(current_plugin_port->lower_value,
482 G_TYPE_FLOAT);
483 g_value_init(current_plugin_port->upper_value,
484 G_TYPE_FLOAT);
485
486 info = ags_vst_parameter_info_alloc();
487
488 ags_vst_iedit_controller_get_parameter_info(AGS_VST3_PLUGIN(base_plugin)->iedit_controller,
489 i, info);
490
491 flags = ags_vst_parameter_info_get_flags(info);
492
493 step_count = ags_vst_parameter_info_get_step_count(info);
494
495 id = ags_vst_parameter_info_get_param_id(info);
496
497 current_plugin_port->port_index = i;
498
499 error = NULL;
500 current_plugin_port->port_name = g_utf16_to_utf8(ags_vst_parameter_info_get_title(info),
501 128,
502 NULL,
503 NULL,
504 &error);
505
506 if(error != NULL){
507 g_warning("%s", error->message);
508 }
509
510 default_normalized_value = ags_vst_parameter_info_get_default_normalized_value(info);
511
512 if(step_count == 0){
513 /* set lower */
514 g_value_set_float(current_plugin_port->lower_value,
515 0.0);
516
517 /* set upper */
518 g_value_set_float(current_plugin_port->upper_value,
519 1.0);
520
521 /* set default */
522 g_value_set_float(current_plugin_port->default_value,
523 ags_vst_iedit_controller_normalized_param_to_plain(AGS_VST3_PLUGIN(base_plugin)->iedit_controller,
524 id,
525 default_normalized_value));
526
527 current_plugin_port->scale_steps = -1;
528 }else if(step_count == 1){
529 /* set lower */
530 g_value_set_float(current_plugin_port->lower_value,
531 0.0);
532
533 /* set upper */
534 g_value_set_float(current_plugin_port->upper_value,
535 1.0);
536
537 /* set default */
538 current_plugin_port->flags |= AGS_PLUGIN_PORT_TOGGLED;
539
540 g_value_set_float(current_plugin_port->default_value,
541 default_normalized_value);
542
543 current_plugin_port->scale_steps = step_count;
544 }else{
545 /* set lower */
546 g_value_set_float(current_plugin_port->lower_value,
547 0.0);
548
549 /* set upper */
550 g_value_set_float(current_plugin_port->upper_value,
551 (gfloat) step_count);
552
553 /* set default */
554 g_value_set_float(current_plugin_port->default_value,
555 fmin(step_count, default_normalized_value * (step_count + 1)));
556
557 current_plugin_port->scale_steps = step_count;
558 }
559
560
561 if((AGS_VST_KCAN_AUTOMATE & (flags)) != 0){
562 //TODO:JK: implement me
563 }
564
565 if((AGS_VST_KIS_READ_ONLY & (flags)) != 0){
566 current_plugin_port->flags |= AGS_PLUGIN_PORT_OUTPUT;
567 }else{
568 current_plugin_port->flags |= AGS_PLUGIN_PORT_INPUT;
569 }
570
571 if((AGS_VST_KIS_WRAP_AROUND & (flags)) != 0){
572 //TODO:JK: implement me
573 }
574
575 if((AGS_VST_KIS_LIST & (flags)) != 0){
576 //TODO:JK: implement me
577 }
578
579 if((AGS_VST_KIS_HIDDEN & (flags)) != 0){
580 //TODO:JK: implement me
581 }
582
583 if((AGS_VST_KIS_PROGRAM_CHANGE & (flags)) != 0){
584 //TODO:JK: implement me
585 }
586
587 if((AGS_VST_KIS_BYPASS & (flags)) != 0){
588 current_plugin_port->flags |= AGS_PLUGIN_PORT_TOGGLED;
589 }
590
591 ags_vst_parameter_info_free(info);
592 }
593
594 ags_vst_pclass_info_free(info);
595
596 base_plugin->plugin_port = g_list_reverse(plugin_port);
597 }
598 }
599
600 /**
601 * ags_vst3_plugin_new:
602 * @filename: the plugin .so
603 * @effect: the effect's string representation
604 * @effect_index: the effect's index
605 *
606 * Create a new instance of #AgsVst3Plugin
607 *
608 * Returns: the new #AgsVst3Plugin
609 *
610 * Since: 3.10.2
611 */
612 AgsVst3Plugin*
ags_vst3_plugin_new(gchar * filename,gchar * effect,guint effect_index)613 ags_vst3_plugin_new(gchar *filename, gchar *effect, guint effect_index)
614 {
615 AgsVst3Plugin *vst3_plugin;
616
617 vst3_plugin = (AgsVst3Plugin *) g_object_new(AGS_TYPE_VST3_PLUGIN,
618 "filename", filename,
619 "effect", effect,
620 "effect-index", effect_index,
621 NULL);
622
623 return(vst3_plugin);
624 }
625