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