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_audio_signal.h>
21 
22 #include <ags/audio/ags_input.h>
23 #include <ags/audio/ags_port.h>
24 #include <ags/audio/ags_recall_channel_run.h>
25 #include <ags/audio/ags_audio_buffer_util.h>
26 
27 #include <ags/audio/recall/ags_volume_channel.h>
28 #include <ags/audio/recall/ags_volume_channel_run.h>
29 #include <ags/audio/recall/ags_volume_recycling.h>
30 
31 void ags_volume_audio_signal_class_init(AgsVolumeAudioSignalClass *volume_audio_signal);
32 void ags_volume_audio_signal_init(AgsVolumeAudioSignal *volume_audio_signal);
33 void ags_volume_audio_signal_finalize(GObject *gobject);
34 
35 void ags_volume_audio_signal_run_inter(AgsRecall *recall);
36 
37 /**
38  * SECTION:ags_volume_audio_signal
39  * @short_description: volumes audio signal
40  * @title: AgsVolumeAudioSignal
41  * @section_id:
42  * @include: ags/audio/recall/ags_volume_audio_signal.h
43  *
44  * The #AgsVolumeAudioSignal class volumes the audio signal.
45  */
46 
47 static gpointer ags_volume_audio_signal_parent_class = NULL;
48 
49 GType
ags_volume_audio_signal_get_type()50 ags_volume_audio_signal_get_type()
51 {
52   static volatile gsize g_define_type_id__volatile = 0;
53 
54   if(g_once_init_enter (&g_define_type_id__volatile)){
55     GType ags_type_volume_audio_signal = 0;
56 
57     static const GTypeInfo ags_volume_audio_signal_info = {
58       sizeof (AgsVolumeAudioSignalClass),
59       NULL, /* base_init */
60       NULL, /* base_finalize */
61       (GClassInitFunc) ags_volume_audio_signal_class_init,
62       NULL, /* class_finalize */
63       NULL, /* class_data */
64       sizeof (AgsVolumeAudioSignal),
65       0,    /* n_preallocs */
66       (GInstanceInitFunc) ags_volume_audio_signal_init,
67     };
68 
69     ags_type_volume_audio_signal = g_type_register_static(AGS_TYPE_RECALL_AUDIO_SIGNAL,
70 							  "AgsVolumeAudioSignal",
71 							  &ags_volume_audio_signal_info,
72 							  0);
73 
74     g_once_init_leave(&g_define_type_id__volatile, ags_type_volume_audio_signal);
75   }
76 
77   return g_define_type_id__volatile;
78 }
79 
80 void
ags_volume_audio_signal_class_init(AgsVolumeAudioSignalClass * volume_audio_signal)81 ags_volume_audio_signal_class_init(AgsVolumeAudioSignalClass *volume_audio_signal)
82 {
83   GObjectClass *gobject;
84   AgsRecallClass *recall;
85 
86   ags_volume_audio_signal_parent_class = g_type_class_peek_parent(volume_audio_signal);
87 
88   /* GObjectClass */
89   gobject = (GObjectClass *) volume_audio_signal;
90 
91   gobject->finalize = ags_volume_audio_signal_finalize;
92 
93   /* AgsRecallClass */
94   recall = (AgsRecallClass *) volume_audio_signal;
95 
96   recall->run_inter = ags_volume_audio_signal_run_inter;
97 }
98 
99 void
ags_volume_audio_signal_init(AgsVolumeAudioSignal * volume_audio_signal)100 ags_volume_audio_signal_init(AgsVolumeAudioSignal *volume_audio_signal)
101 {
102   AGS_RECALL(volume_audio_signal)->name = "ags-volume";
103   AGS_RECALL(volume_audio_signal)->version = AGS_RECALL_DEFAULT_VERSION;
104   AGS_RECALL(volume_audio_signal)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
105   AGS_RECALL(volume_audio_signal)->xml_type = "ags-volume-audio-signal";
106   AGS_RECALL(volume_audio_signal)->port = NULL;
107 }
108 
109 void
ags_volume_audio_signal_finalize(GObject * gobject)110 ags_volume_audio_signal_finalize(GObject *gobject)
111 {
112   /* call parent */
113   G_OBJECT_CLASS(ags_volume_audio_signal_parent_class)->finalize(gobject);
114 }
115 
116 void
ags_volume_audio_signal_run_inter(AgsRecall * recall)117 ags_volume_audio_signal_run_inter(AgsRecall *recall)
118 {
119   AgsAudioSignal *source;
120   AgsVolumeAudioSignal *volume_audio_signal;
121   AgsRecallID *recall_id;
122   AgsRecyclingContext *recycling_context, *parent_recycling_context;
123 
124   GList *start_note;
125 
126   void (*parent_class_run_inter)(AgsRecall *recall);
127 
128   volume_audio_signal = (AgsVolumeAudioSignal *) recall;
129 
130   /* get parent class */
131   parent_class_run_inter = AGS_RECALL_CLASS(ags_volume_audio_signal_parent_class)->run_inter;
132 
133   /* call parent */
134   parent_class_run_inter(recall);
135 
136   g_object_get(volume_audio_signal,
137 	       "source", &source,
138 	       "recall-id", &recall_id,
139 	       NULL);
140 
141   g_object_get(recall_id,
142 	       "recycling-context", &recycling_context,
143 	       NULL);
144 
145   g_object_get(recycling_context,
146 	       "parent", &parent_recycling_context,
147 	       NULL);
148 
149   g_object_get(source,
150 	       "note", &start_note,
151 	       NULL);
152 
153   if(ags_recall_global_get_rt_safe() &&
154      parent_recycling_context != NULL &&
155      start_note == NULL){
156     g_object_unref(source);
157 
158     g_object_unref(recall_id);
159 
160     g_object_unref(recycling_context);
161     g_object_unref(parent_recycling_context);
162 
163     return;
164   }
165 
166   if(source->stream_current != NULL){
167     AgsPort *port;
168     AgsVolumeChannel *volume_channel;
169     AgsVolumeChannelRun *volume_channel_run;
170     AgsVolumeRecycling *volume_recycling;
171 
172     void *buffer;
173 
174     gdouble volume;
175     guint buffer_size;
176     guint format;
177     guint limit;
178     guint i;
179 
180     GValue value = {0,};
181 
182     g_object_get(volume_audio_signal,
183 		 "parent", &volume_recycling,
184 		 NULL);
185 
186     g_object_get(volume_recycling,
187 		 "parent", &volume_channel_run,
188 		 NULL);
189 
190     g_object_get(volume_channel_run,
191 		 "recall-channel", &volume_channel,
192 		 NULL);
193 
194     g_object_get(source,
195 		 "buffer-size", &buffer_size,
196 		 "format", &format,
197 		 NULL);
198 
199     buffer = source->stream_current->data;
200 
201     g_object_get(volume_channel,
202 		 "volume", &port,
203 		 NULL);
204 
205     g_value_init(&value,
206 		 G_TYPE_FLOAT);
207 
208     ags_port_safe_read(port,
209 		       &value);
210 
211     volume = g_value_get_float(&value);
212 
213     g_value_unset(&value);
214 
215     g_object_unref(port);
216 
217     ags_audio_buffer_util_volume(buffer, 1,
218 				 ags_audio_buffer_util_format_from_soundcard(format),
219 				 buffer_size,
220 				 volume);
221 
222     g_object_unref(volume_recycling);
223 
224     g_object_unref(volume_channel_run);
225     g_object_unref(volume_channel);
226   }else{
227     ags_recall_done(recall);
228   }
229 
230   /* unref */
231   g_object_unref(source);
232 
233   g_object_unref(recall_id);
234 
235   g_object_unref(recycling_context);
236 
237   if(parent_recycling_context != NULL){
238     g_object_unref(parent_recycling_context);
239   }
240 
241   g_list_free_full(start_note,
242 		   g_object_unref);
243 }
244 
245 /**
246  * ags_volume_audio_signal_new:
247  * @source: the #AgsAudioSignal
248  *
249  * Create a new instance of #AgsVolumeAudioSignal
250  *
251  * Returns: the new #AgsVolumeAudioSignal
252  *
253  * Since: 3.0.0
254  */
255 AgsVolumeAudioSignal*
ags_volume_audio_signal_new(AgsAudioSignal * source)256 ags_volume_audio_signal_new(AgsAudioSignal *source)
257 {
258   AgsVolumeAudioSignal *volume_audio_signal;
259 
260   volume_audio_signal = (AgsVolumeAudioSignal *) g_object_new(AGS_TYPE_VOLUME_AUDIO_SIGNAL,
261 							      "source", source,
262 							      NULL);
263 
264   return(volume_audio_signal);
265 }
266