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