1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 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/task/ags_seek_soundcard.h>
21 
22 #include <ags/audio/ags_sound_provider.h>
23 #include <ags/audio/ags_audio.h>
24 #include <ags/audio/ags_notation.h>
25 
26 #include <ags/i18n.h>
27 
28 void ags_seek_soundcard_class_init(AgsSeekSoundcardClass *seek_soundcard);
29 void ags_seek_soundcard_init(AgsSeekSoundcard *seek_soundcard);
30 void ags_seek_soundcard_set_property(GObject *gobject,
31 				     guint prop_id,
32 				     const GValue *value,
33 				     GParamSpec *param_spec);
34 void ags_seek_soundcard_get_property(GObject *gobject,
35 				     guint prop_id,
36 				     GValue *value,
37 				     GParamSpec *param_spec);
38 void ags_seek_soundcard_dispose(GObject *gobject);
39 void ags_seek_soundcard_finalize(GObject *gobject);
40 
41 void ags_seek_soundcard_launch(AgsTask *task);
42 
43 /**
44  * SECTION:ags_seek_soundcard
45  * @short_description: seek soundcard object
46  * @title: AgsSeekSoundcard
47  * @section_id:
48  * @include: ags/audio/task/ags_seek_soundcard.h
49  *
50  * The #AgsSeekSoundcard task seeks #AgsSoundcard.
51  */
52 
53 static gpointer ags_seek_soundcard_parent_class = NULL;
54 
55 enum{
56   PROP_0,
57   PROP_SOUNDCARD,
58   PROP_OFFSET,
59   PROP_WHENCE,
60 };
61 
62 GType
ags_seek_soundcard_get_type()63 ags_seek_soundcard_get_type()
64 {
65   static volatile gsize g_define_type_id__volatile = 0;
66 
67   if(g_once_init_enter (&g_define_type_id__volatile)){
68     GType ags_type_seek_soundcard = 0;
69 
70     static const GTypeInfo ags_seek_soundcard_info = {
71       sizeof(AgsSeekSoundcardClass),
72       NULL, /* base_init */
73       NULL, /* base_finalize */
74       (GClassInitFunc) ags_seek_soundcard_class_init,
75       NULL, /* class_finalize */
76       NULL, /* class_data */
77       sizeof(AgsSeekSoundcard),
78       0,    /* n_preallocs */
79       (GInstanceInitFunc) ags_seek_soundcard_init,
80     };
81 
82 
83     ags_type_seek_soundcard = g_type_register_static(AGS_TYPE_TASK,
84 						     "AgsSeekSoundcard",
85 						     &ags_seek_soundcard_info,
86 						     0);
87 
88     g_once_init_leave(&g_define_type_id__volatile, ags_type_seek_soundcard);
89   }
90 
91   return g_define_type_id__volatile;
92 }
93 
94 void
ags_seek_soundcard_class_init(AgsSeekSoundcardClass * seek_soundcard)95 ags_seek_soundcard_class_init(AgsSeekSoundcardClass *seek_soundcard)
96 {
97   GObjectClass *gobject;
98   AgsTaskClass *task;
99   GParamSpec *param_spec;
100 
101   ags_seek_soundcard_parent_class = g_type_class_peek_parent(seek_soundcard);
102 
103   /* gobject */
104   gobject = (GObjectClass *) seek_soundcard;
105 
106   gobject->set_property = ags_seek_soundcard_set_property;
107   gobject->get_property = ags_seek_soundcard_get_property;
108 
109   gobject->dispose = ags_seek_soundcard_dispose;
110   gobject->finalize = ags_seek_soundcard_finalize;
111 
112   /* properties */
113   /**
114    * AgsSeekSoundcard:soundcard:
115    *
116    * The assigned #AgsSoundcard
117    *
118    * Since: 3.0.0
119    */
120   param_spec = g_param_spec_object("soundcard",
121 				   i18n_pspec("soundcard of seek soundcard"),
122 				   i18n_pspec("The soundcard of seek soundcard"),
123 				   G_TYPE_OBJECT,
124 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
125   g_object_class_install_property(gobject,
126 				  PROP_SOUNDCARD,
127 				  param_spec);
128 
129   /**
130    * AgsSeekSoundcard:offset:
131    *
132    * The offset to seek.
133    *
134    * Since: 3.0.0
135    */
136   param_spec = g_param_spec_int64("offset",
137 				 i18n_pspec("offset"),
138 				 i18n_pspec("The amount of offset"),
139 				 0,
140 				 G_MAXINT64,
141 				 0,
142 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
143   g_object_class_install_property(gobject,
144 				  PROP_OFFSET,
145 				  param_spec);
146 
147   /**
148    * AgsSeekSoundcard:whence:
149    *
150    * Whence either AGS_SEEK_SET, AGS_SEEK_CUR or AGS_SEEK_END
151    *
152    * Since: 3.0.0
153    */
154   param_spec = g_param_spec_uint("whence",
155 				 i18n_pspec("whence"),
156 				 i18n_pspec("whence"),
157 				 0,
158 				 G_MAXUINT,
159 				 AGS_SEEK_SET,
160 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
161   g_object_class_install_property(gobject,
162 				  PROP_WHENCE,
163 				  param_spec);
164 
165   /* task */
166   task = (AgsTaskClass *) seek_soundcard;
167 
168   task->launch = ags_seek_soundcard_launch;
169 }
170 
171 void
ags_seek_soundcard_init(AgsSeekSoundcard * seek_soundcard)172 ags_seek_soundcard_init(AgsSeekSoundcard *seek_soundcard)
173 {
174   seek_soundcard->soundcard = NULL;
175   seek_soundcard->offset = 0;
176   seek_soundcard->whence = AGS_SEEK_SET;
177 }
178 
179 void
ags_seek_soundcard_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)180 ags_seek_soundcard_set_property(GObject *gobject,
181 				guint prop_id,
182 				const GValue *value,
183 				GParamSpec *param_spec)
184 {
185   AgsSeekSoundcard *seek_soundcard;
186 
187   seek_soundcard = AGS_SEEK_SOUNDCARD(gobject);
188 
189   switch(prop_id){
190   case PROP_SOUNDCARD:
191     {
192       GObject *soundcard;
193 
194       soundcard = (GObject *) g_value_get_object(value);
195 
196       if(seek_soundcard->soundcard == (GObject *) soundcard){
197 	return;
198       }
199 
200       if(seek_soundcard->soundcard != NULL){
201 	g_object_unref(seek_soundcard->soundcard);
202       }
203 
204       if(soundcard != NULL){
205 	g_object_ref(soundcard);
206       }
207 
208       seek_soundcard->soundcard = (GObject *) soundcard;
209     }
210     break;
211   case PROP_OFFSET:
212     {
213       seek_soundcard->offset = g_value_get_int64(value);
214     }
215     break;
216   case PROP_WHENCE:
217     {
218       seek_soundcard->whence = g_value_get_uint(value);
219     }
220     break;
221   default:
222     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
223     break;
224   }
225 }
226 
227 void
ags_seek_soundcard_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)228 ags_seek_soundcard_get_property(GObject *gobject,
229 				guint prop_id,
230 				GValue *value,
231 				GParamSpec *param_spec)
232 {
233   AgsSeekSoundcard *seek_soundcard;
234 
235   seek_soundcard = AGS_SEEK_SOUNDCARD(gobject);
236 
237   switch(prop_id){
238   case PROP_SOUNDCARD:
239     {
240       g_value_set_object(value, seek_soundcard->soundcard);
241     }
242     break;
243   case PROP_OFFSET:
244     {
245       g_value_set_int64(value, seek_soundcard->offset);
246     }
247     break;
248   case PROP_WHENCE:
249     {
250       g_value_set_uint(value, seek_soundcard->whence);
251     }
252     break;
253   default:
254     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
255     break;
256   }
257 }
258 
259 void
ags_seek_soundcard_dispose(GObject * gobject)260 ags_seek_soundcard_dispose(GObject *gobject)
261 {
262   AgsSeekSoundcard *seek_soundcard;
263 
264   seek_soundcard = AGS_SEEK_SOUNDCARD(gobject);
265 
266   if(seek_soundcard->soundcard != NULL){
267     g_object_unref(seek_soundcard->soundcard);
268 
269     seek_soundcard->soundcard = NULL;
270   }
271 
272   /* call parent */
273   G_OBJECT_CLASS(ags_seek_soundcard_parent_class)->dispose(gobject);
274 }
275 
276 void
ags_seek_soundcard_finalize(GObject * gobject)277 ags_seek_soundcard_finalize(GObject *gobject)
278 {
279   AgsSeekSoundcard *seek_soundcard;
280 
281   seek_soundcard = AGS_SEEK_SOUNDCARD(gobject);
282 
283   if(seek_soundcard->soundcard != NULL){
284     g_object_unref(seek_soundcard->soundcard);
285   }
286 
287   /* call parent */
288   G_OBJECT_CLASS(ags_seek_soundcard_parent_class)->finalize(gobject);
289 }
290 
291 void
ags_seek_soundcard_launch(AgsTask * task)292 ags_seek_soundcard_launch(AgsTask *task)
293 {
294   AgsSeekSoundcard *seek_soundcard;
295 
296   AgsApplicationContext *application_context;
297 
298   GObject *soundcard;
299 
300   GList *audio_start, *audio;
301   GList *recall_start, *recall;
302 
303   guint note_offset;
304   guint note_offset_absolute;
305 
306   seek_soundcard = AGS_SEEK_SOUNDCARD(task);
307 
308   application_context = ags_application_context_get_instance();
309 
310   g_return_if_fail(AGS_IS_SOUND_PROVIDER(application_context));
311   g_return_if_fail(AGS_IS_SOUNDCARD(seek_soundcard->soundcard));
312 
313   soundcard = seek_soundcard->soundcard;
314 
315   audio =
316     audio_start = ags_sound_provider_get_audio(AGS_SOUND_PROVIDER(application_context));
317 
318   while(audio != NULL){
319     /* seek play context */
320     g_object_get(audio->data,
321 		 "play", &recall_start,
322 		 NULL);
323 
324     recall = recall_start;
325 
326     while(recall != NULL){
327       if(AGS_IS_SEEKABLE(recall->data)){
328 	ags_seekable_seek(AGS_SEEKABLE(recall->data),
329 			  seek_soundcard->offset,
330 			  seek_soundcard->whence);
331       }
332 
333       recall = recall->next;
334     }
335 
336     g_list_free_full(recall_start,
337 		     g_object_unref);
338 
339     /* seek recall context */
340     g_object_get(audio->data,
341 		 "recall", &recall_start,
342 		 NULL);
343 
344     recall = recall_start;
345 
346     while(recall != NULL){
347       if(AGS_IS_SEEKABLE(recall->data)){
348 	ags_seekable_seek(AGS_SEEKABLE(recall->data),
349 			  seek_soundcard->offset,
350 			  seek_soundcard->whence);
351       }
352 
353       recall = recall->next;
354     }
355 
356     g_list_free_full(recall_start,
357 		     g_object_unref);
358 
359     /* iterate */
360     audio = audio->next;
361   }
362 
363   g_list_free_full(audio_start,
364 		   g_object_unref);
365 
366   /* seek soundcard */
367   note_offset = ags_soundcard_get_note_offset(AGS_SOUNDCARD(seek_soundcard->soundcard));
368   note_offset_absolute = ags_soundcard_get_note_offset_absolute(AGS_SOUNDCARD(seek_soundcard->soundcard));
369 
370   switch(seek_soundcard->whence){
371   case AGS_SEEK_CUR:
372     {
373       ags_soundcard_set_note_offset(AGS_SOUNDCARD(seek_soundcard->soundcard),
374 				    note_offset + seek_soundcard->offset);
375       ags_soundcard_set_note_offset_absolute(AGS_SOUNDCARD(seek_soundcard->soundcard),
376 					     note_offset_absolute + seek_soundcard->offset);
377     }
378     break;
379   case AGS_SEEK_SET:
380     {
381       ags_soundcard_set_note_offset(AGS_SOUNDCARD(seek_soundcard->soundcard),
382 				    seek_soundcard->offset);
383       ags_soundcard_set_note_offset_absolute(AGS_SOUNDCARD(seek_soundcard->soundcard),
384 					     seek_soundcard->offset);
385     }
386     break;
387   case AGS_SEEK_END:
388     {
389       ags_soundcard_set_note_offset(AGS_SOUNDCARD(seek_soundcard->soundcard),
390 				    AGS_NOTATION_DEFAULT_END + seek_soundcard->offset);
391       ags_soundcard_set_note_offset_absolute(AGS_SOUNDCARD(seek_soundcard->soundcard),
392 					     AGS_NOTATION_DEFAULT_END + seek_soundcard->offset);
393     }
394     break;
395   }
396 }
397 
398 /**
399  * ags_seek_soundcard_new:
400  * @soundcard: the #GObject sub-type implementing #AgsSoundcard
401  * @offset: the offset
402  * @whence: whence see #AgsSeekType-enum
403  *
404  * Create a new instance of #AgsSeekSoundcard.
405  *
406  * Returns: the new #AgsSeekSoundcard
407  *
408  * Since: 3.0.0
409  */
410 AgsSeekSoundcard*
ags_seek_soundcard_new(GObject * soundcard,gint64 offset,guint whence)411 ags_seek_soundcard_new(GObject *soundcard,
412 		       gint64 offset,
413 		       guint whence)
414 {
415   AgsSeekSoundcard *seek_soundcard;
416 
417   seek_soundcard = (AgsSeekSoundcard *) g_object_new(AGS_TYPE_SEEK_SOUNDCARD,
418 						     "soundcard", soundcard,
419 						     "offset", offset,
420 						     "whence", whence,
421 						     NULL);
422 
423   return(seek_soundcard);
424 }
425