1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2019 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/audio/recall/ags_volume_channel.h>
21 
22 #include <ags/plugin/ags_plugin_port.h>
23 
24 #include <ags/i18n.h>
25 
26 void ags_volume_channel_class_init(AgsVolumeChannelClass *volume_channel);
27 void ags_volume_channel_init(AgsVolumeChannel *volume_channel);
28 void ags_volume_channel_set_property(GObject *gobject,
29 				     guint prop_id,
30 				     const GValue *value,
31 				     GParamSpec *param_spec);
32 void ags_volume_channel_get_property(GObject *gobject,
33 				     guint prop_id,
34 				     GValue *value,
35 				     GParamSpec *param_spec);
36 void ags_volume_channel_dispose(GObject *gobject);
37 void ags_volume_channel_finalize(GObject *gobject);
38 
39 static AgsPluginPort* ags_volume_channel_get_volume_plugin_port();
40 
41 /**
42  * SECTION:ags_volume_channel
43  * @short_description: volumes channel
44  * @title: AgsVolumeChannel
45  * @section_id:
46  * @include: ags/audio/recall/ags_volume_channel.h
47  *
48  * The #AgsVolumeChannel class provides ports to the effect processor.
49  */
50 
51 enum{
52   PROP_0,
53   PROP_VOLUME,
54 };
55 
56 static gpointer ags_volume_channel_parent_class = NULL;
57 
58 const gchar *ags_volume_channel_plugin_name = "ags-volume";
59 const gchar *ags_volume_channel_specifier[] = {
60   "./volume[0]"
61 };
62 const gchar *ags_volume_channel_control_port[] = {
63   "1/1"
64 };
65 
66 GType
ags_volume_channel_get_type()67 ags_volume_channel_get_type()
68 {
69   static volatile gsize g_define_type_id__volatile = 0;
70 
71   if(g_once_init_enter (&g_define_type_id__volatile)){
72     GType ags_type_volume_channel = 0;
73 
74     static const GTypeInfo ags_volume_channel_info = {
75       sizeof (AgsVolumeChannelClass),
76       NULL, /* base_init */
77       NULL, /* base_finalize */
78       (GClassInitFunc) ags_volume_channel_class_init,
79       NULL, /* class_finalize */
80       NULL, /* class_data */
81       sizeof (AgsVolumeChannel),
82       0,    /* n_preallocs */
83       (GInstanceInitFunc) ags_volume_channel_init,
84     };
85 
86     ags_type_volume_channel = g_type_register_static(AGS_TYPE_RECALL_CHANNEL,
87 						     "AgsVolumeChannel",
88 						     &ags_volume_channel_info,
89 						     0);
90 
91     g_once_init_leave(&g_define_type_id__volatile, ags_type_volume_channel);
92   }
93 
94   return g_define_type_id__volatile;
95 }
96 
97 void
ags_volume_channel_class_init(AgsVolumeChannelClass * volume_channel)98 ags_volume_channel_class_init(AgsVolumeChannelClass *volume_channel)
99 {
100   GObjectClass *gobject;
101   AgsRecallClass *recall;
102   GParamSpec *param_spec;
103 
104   ags_volume_channel_parent_class = g_type_class_peek_parent(volume_channel);
105 
106   /* GObjectClass */
107   gobject = (GObjectClass *) volume_channel;
108 
109   gobject->set_property = ags_volume_channel_set_property;
110   gobject->get_property = ags_volume_channel_get_property;
111 
112   gobject->dispose = ags_volume_channel_dispose;
113   gobject->finalize = ags_volume_channel_finalize;
114 
115   /* properties */
116   /**
117    * AgsVolumeChannel:volume:
118    *
119    * The volume port.
120    *
121    * Since: 3.0.0
122    */
123   param_spec = g_param_spec_object("volume",
124 				   i18n_pspec("volume to apply"),
125 				   i18n_pspec("The volume to apply on the channel"),
126 				   AGS_TYPE_PORT,
127 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
128   g_object_class_install_property(gobject,
129 				  PROP_VOLUME,
130 				  param_spec);
131 }
132 
133 void
ags_volume_channel_init(AgsVolumeChannel * volume_channel)134 ags_volume_channel_init(AgsVolumeChannel *volume_channel)
135 {
136   GList *port;
137 
138   AGS_RECALL(volume_channel)->name = "ags-volume";
139   AGS_RECALL(volume_channel)->version = AGS_RECALL_DEFAULT_VERSION;
140   AGS_RECALL(volume_channel)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
141   AGS_RECALL(volume_channel)->xml_type = "ags-volume-channel";
142 
143   /* initialize the port */
144   port = NULL;
145 
146   /* volume */
147   volume_channel->volume = g_object_new(AGS_TYPE_PORT,
148 					"plugin-name", "ags-volume",
149 					"specifier", "./volume[0]",
150 					"control-port", "1/1",
151 					"port-value-is-pointer", FALSE,
152 					"port-value-type", G_TYPE_FLOAT,
153 					"port-value-size", sizeof(gfloat),
154 					"port-value-length", 1,
155 					NULL);
156   g_object_ref(volume_channel->volume);
157 
158   volume_channel->volume->port_value.ags_port_float = 1.0;
159 
160   /* port descriptor */
161   g_object_set(volume_channel->volume,
162 	       "plugin-port", ags_volume_channel_get_volume_plugin_port(),
163 	       NULL);
164 
165   /* add to port */
166   port = g_list_prepend(port, volume_channel->volume);
167   g_object_ref(volume_channel->volume);
168 
169   /* set port */
170   AGS_RECALL(volume_channel)->port = port;
171 }
172 
173 void
ags_volume_channel_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)174 ags_volume_channel_set_property(GObject *gobject,
175 				guint prop_id,
176 				const GValue *value,
177 				GParamSpec *param_spec)
178 {
179   AgsVolumeChannel *volume_channel;
180 
181   GRecMutex *recall_mutex;
182 
183   volume_channel = AGS_VOLUME_CHANNEL(gobject);
184 
185   /* get recall mutex */
186   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(volume_channel);
187 
188   switch(prop_id){
189   case PROP_VOLUME:
190     {
191       AgsPort *port;
192 
193       port = (AgsPort *) g_value_get_object(value);
194 
195       g_rec_mutex_lock(recall_mutex);
196 
197       if(port == volume_channel->volume){
198 	g_rec_mutex_unlock(recall_mutex);
199 
200 	return;
201       }
202 
203       if(volume_channel->volume != NULL){
204 	g_object_unref(G_OBJECT(volume_channel->volume));
205       }
206 
207       if(port != NULL){
208 	g_object_ref(G_OBJECT(port));
209       }
210 
211       volume_channel->volume = port;
212 
213       g_rec_mutex_unlock(recall_mutex);
214     }
215     break;
216   default:
217     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
218     break;
219   }
220 }
221 
222 void
ags_volume_channel_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)223 ags_volume_channel_get_property(GObject *gobject,
224 				guint prop_id,
225 				GValue *value,
226 				GParamSpec *param_spec)
227 {
228   AgsVolumeChannel *volume_channel;
229 
230   GRecMutex *recall_mutex;
231 
232   volume_channel = AGS_VOLUME_CHANNEL(gobject);
233 
234   /* get recall mutex */
235   recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(volume_channel);
236 
237   switch(prop_id){
238   case PROP_VOLUME:
239     {
240       g_rec_mutex_lock(recall_mutex);
241 
242       g_value_set_object(value, volume_channel->volume);
243 
244       g_rec_mutex_unlock(recall_mutex);
245     }
246     break;
247   default:
248     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
249     break;
250   }
251 }
252 
253 void
ags_volume_channel_dispose(GObject * gobject)254 ags_volume_channel_dispose(GObject *gobject)
255 {
256   AgsVolumeChannel *volume_channel;
257 
258   volume_channel = AGS_VOLUME_CHANNEL(gobject);
259 
260   /* volume */
261   if(volume_channel->volume != NULL){
262     g_object_unref(G_OBJECT(volume_channel->volume));
263   }
264 
265   /* call parent */
266   G_OBJECT_CLASS(ags_volume_channel_parent_class)->dispose(gobject);
267 }
268 
269 void
ags_volume_channel_finalize(GObject * gobject)270 ags_volume_channel_finalize(GObject *gobject)
271 {
272   AgsVolumeChannel *volume_channel;
273 
274   volume_channel = AGS_VOLUME_CHANNEL(gobject);
275 
276   /* volume */
277   if(volume_channel->volume != NULL){
278     g_object_unref(G_OBJECT(volume_channel->volume));
279   }
280 
281   /* call parent */
282   G_OBJECT_CLASS(ags_volume_channel_parent_class)->finalize(gobject);
283 }
284 
285 static AgsPluginPort*
ags_volume_channel_get_volume_plugin_port()286 ags_volume_channel_get_volume_plugin_port()
287 {
288   static AgsPluginPort *plugin_port = NULL;
289 
290   static GMutex mutex;
291 
292   g_mutex_lock(&mutex);
293 
294   if(plugin_port == NULL){
295     plugin_port = ags_plugin_port_new();
296     g_object_ref(plugin_port);
297 
298     plugin_port->flags |= (AGS_PLUGIN_PORT_INPUT |
299 			   AGS_PLUGIN_PORT_CONTROL);
300 
301     plugin_port->port_index = 0;
302 
303     /* range */
304     g_value_init(plugin_port->default_value,
305 		 G_TYPE_FLOAT);
306     g_value_init(plugin_port->lower_value,
307 		 G_TYPE_FLOAT);
308     g_value_init(plugin_port->upper_value,
309 		 G_TYPE_FLOAT);
310 
311     g_value_set_float(plugin_port->default_value,
312 		      1.0);
313     g_value_set_float(plugin_port->lower_value,
314 		      0.0);
315     g_value_set_float(plugin_port->upper_value,
316 		      2.0);
317   }
318 
319   g_mutex_unlock(&mutex);
320 
321   return(plugin_port);
322 }
323 
324 /**
325  * ags_volume_channel_new:
326  * @source: the #AgsAudioSignal
327  *
328  * Create a new instance of #AgsVolumeChannel
329  *
330  * Returns: the new #AgsVolumeChannel
331  *
332  * Since: 3.0.0
333  */
334 AgsVolumeChannel*
ags_volume_channel_new(AgsChannel * source)335 ags_volume_channel_new(AgsChannel *source)
336 {
337   AgsVolumeChannel *volume_channel;
338 
339   volume_channel = (AgsVolumeChannel *) g_object_new(AGS_TYPE_VOLUME_CHANNEL,
340 						     "source", source,
341 						     NULL);
342 
343   return(volume_channel);
344 }
345