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/ags_track.h>
21
22 #include <ags/audio/ags_audio_signal.h>
23
24 #include <ags/i18n.h>
25
26 #include <stdlib.h>
27
28 void ags_track_class_init(AgsTrackClass *track);
29 void ags_track_init(AgsTrack *track);
30 void ags_track_set_property(GObject *gobject,
31 guint prop_id,
32 const GValue *value,
33 GParamSpec *param_spec);
34 void ags_track_get_property(GObject *gobject,
35 guint prop_id,
36 GValue *value,
37 GParamSpec *param_spec);
38 void ags_track_finalize(GObject *gobject);
39
40 /**
41 * SECTION:ags_track
42 * @short_description: Track class.
43 * @title: AgsTrack
44 * @section_id:
45 * @include: ags/audio/ags_track.h
46 *
47 * #AgsTrack represents a tone.
48 */
49
50 enum{
51 PROP_0,
52 PROP_X,
53 PROP_SMF_BUFFER,
54 };
55
56 static gpointer ags_track_parent_class = NULL;
57
58 GType
ags_track_get_type()59 ags_track_get_type()
60 {
61 static volatile gsize g_define_type_id__volatile = 0;
62
63 if(g_once_init_enter (&g_define_type_id__volatile)){
64 GType ags_type_track = 0;
65
66 static const GTypeInfo ags_track_info = {
67 sizeof(AgsTrackClass),
68 NULL,
69 NULL,
70 (GClassInitFunc) ags_track_class_init,
71 NULL,
72 NULL,
73 sizeof(AgsTrack),
74 0,
75 (GInstanceInitFunc) ags_track_init,
76 };
77
78 ags_type_track = g_type_register_static(G_TYPE_OBJECT,
79 "AgsTrack",
80 &ags_track_info,
81 0);
82
83 g_once_init_leave(&g_define_type_id__volatile, ags_type_track);
84 }
85
86 return g_define_type_id__volatile;
87 }
88
89 void
ags_track_class_init(AgsTrackClass * track)90 ags_track_class_init(AgsTrackClass *track)
91 {
92 GObjectClass *gobject;
93
94 GParamSpec *param_spec;
95
96 ags_track_parent_class = g_type_class_peek_parent(track);
97
98 gobject = (GObjectClass *) track;
99
100 gobject->set_property = ags_track_set_property;
101 gobject->get_property = ags_track_get_property;
102
103 gobject->finalize = ags_track_finalize;
104
105 /* properties */
106 /**
107 * AgsTrack:x:
108 *
109 * Track's x offset.
110 *
111 * Since: 3.0.0
112 */
113 param_spec = g_param_spec_uint64("x",
114 i18n_pspec("offset x"),
115 i18n_pspec("The x offset"),
116 0,
117 G_MAXUINT64,
118 0,
119 G_PARAM_READABLE | G_PARAM_WRITABLE);
120 g_object_class_install_property(gobject,
121 PROP_X,
122 param_spec);
123
124 /**
125 * AgsTrack:smf-buffer:
126 *
127 * Track's SMF buffer.
128 *
129 * Since: 3.0.0
130 */
131 param_spec = g_param_spec_pointer("smf-buffer",
132 i18n_pspec("SMF buffer"),
133 i18n_pspec("The SMF buffer"),
134 G_PARAM_READABLE | G_PARAM_WRITABLE);
135 g_object_class_install_property(gobject,
136 PROP_SMF_BUFFER,
137 param_spec);
138 }
139
140 void
ags_track_init(AgsTrack * track)141 ags_track_init(AgsTrack *track)
142 {
143 track->flags = 0;
144
145 /* track mutex */
146 g_rec_mutex_init(&(track->obj_mutex));
147
148 /* fields */
149 track->x = 0;
150
151 track->smf_buffer = NULL;
152 track->allocated_smf_buffer_length = 0;
153 track->smf_buffer_length = 0;
154 }
155
156 void
ags_track_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)157 ags_track_set_property(GObject *gobject,
158 guint prop_id,
159 const GValue *value,
160 GParamSpec *param_spec)
161 {
162 AgsTrack *track;
163
164 GRecMutex *track_mutex;
165
166 track = AGS_TRACK(gobject);
167
168 /* get track mutex */
169 track_mutex = AGS_TRACK_GET_OBJ_MUTEX(track);
170
171 switch(prop_id){
172 case PROP_X:
173 {
174 g_rec_mutex_lock(track_mutex);
175
176 track->x = g_value_get_uint64(value);
177
178 g_rec_mutex_unlock(track_mutex);
179 }
180 break;
181 case PROP_SMF_BUFFER:
182 {
183 g_rec_mutex_lock(track_mutex);
184
185 track->smf_buffer = g_value_get_pointer(value);
186
187 g_rec_mutex_unlock(track_mutex);
188 }
189 break;
190 default:
191 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
192 break;
193 }
194 }
195
196 void
ags_track_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)197 ags_track_get_property(GObject *gobject,
198 guint prop_id,
199 GValue *value,
200 GParamSpec *param_spec)
201 {
202 AgsTrack *track;
203
204 GRecMutex *track_mutex;
205
206 track = AGS_TRACK(gobject);
207
208 /* get track mutex */
209 track_mutex = AGS_TRACK_GET_OBJ_MUTEX(track);
210
211 switch(prop_id){
212 case PROP_X:
213 {
214 g_rec_mutex_lock(track_mutex);
215
216 g_value_set_uint64(value,
217 track->x);
218
219 g_rec_mutex_unlock(track_mutex);
220 }
221 break;
222 case PROP_SMF_BUFFER:
223 {
224 g_rec_mutex_lock(track_mutex);
225
226 g_value_set_pointer(value,
227 track->smf_buffer);
228
229 g_rec_mutex_unlock(track_mutex);
230 }
231 break;
232 default:
233 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
234 break;
235 }
236 }
237
238 void
ags_track_finalize(GObject * gobject)239 ags_track_finalize(GObject *gobject)
240 {
241 AgsTrack *track;
242
243 track = AGS_TRACK(gobject);
244
245 if(track->smf_buffer != NULL){
246 free(track->smf_buffer);
247 }
248
249 /* call parent */
250 G_OBJECT_CLASS(ags_track_parent_class)->finalize(gobject);
251 }
252
253 /**
254 * ags_track_get_obj_mutex:
255 * @track: the #AgsTrack
256 *
257 * Get object mutex.
258 *
259 * Returns: the #GRecMutex to lock @track
260 *
261 * Since: 3.1.0
262 */
263 GRecMutex*
ags_track_get_obj_mutex(AgsTrack * track)264 ags_track_get_obj_mutex(AgsTrack *track)
265 {
266 if(!AGS_IS_TRACK(track)){
267 return(NULL);
268 }
269
270 return(AGS_TRACK_GET_OBJ_MUTEX(track));
271 }
272
273 /**
274 * ags_track_lock:
275 * @track: the #AgsTrack
276 *
277 * Lock object mutex.
278 *
279 * Since: 3.1.0
280 */
281 void
ags_track_lock(AgsTrack * track)282 ags_track_lock(AgsTrack *track)
283 {
284 if(!AGS_IS_TRACK(track)){
285 return;
286 }
287
288 g_rec_mutex_lock(AGS_TRACK_GET_OBJ_MUTEX(track));
289 }
290
291 /**
292 * ags_track_unlock:
293 * @track: the #AgsTrack
294 *
295 * Unlock object mutex.
296 *
297 * Since: 3.1.0
298 */
299 void
ags_track_unlock(AgsTrack * track)300 ags_track_unlock(AgsTrack *track)
301 {
302 if(!AGS_IS_TRACK(track)){
303 return;
304 }
305
306 g_rec_mutex_unlock(AGS_TRACK_GET_OBJ_MUTEX(track));
307 }
308
309 /**
310 * ags_track_test_flags:
311 * @track: the #AgsTrack
312 * @flags: the flags
313 *
314 * Test @flags to be set on @track.
315 *
316 * Returns: %TRUE if flags are set, else %FALSE
317 *
318 * Since: 3.0.0
319 */
320 gboolean
ags_track_test_flags(AgsTrack * track,guint flags)321 ags_track_test_flags(AgsTrack *track, guint flags)
322 {
323 gboolean retval;
324
325 GRecMutex *track_mutex;
326
327 if(!AGS_IS_TRACK(track)){
328 return(FALSE);
329 }
330
331 /* get track mutex */
332 track_mutex = AGS_TRACK_GET_OBJ_MUTEX(track);
333
334 /* test */
335 g_rec_mutex_lock(track_mutex);
336
337 retval = (flags & (track->flags)) ? TRUE: FALSE;
338
339 g_rec_mutex_unlock(track_mutex);
340
341 return(retval);
342 }
343
344 /**
345 * ags_track_set_flags:
346 * @track: the #AgsTrack
347 * @flags: the flags
348 *
349 * Set @flags on @track.
350 *
351 * Since: 3.0.0
352 */
353 void
ags_track_set_flags(AgsTrack * track,guint flags)354 ags_track_set_flags(AgsTrack *track, guint flags)
355 {
356 GRecMutex *track_mutex;
357
358 if(!AGS_IS_TRACK(track)){
359 return;
360 }
361
362 /* get track mutex */
363 track_mutex = AGS_TRACK_GET_OBJ_MUTEX(track);
364
365 /* set */
366 g_rec_mutex_lock(track_mutex);
367
368 track->flags |= flags;
369
370 g_rec_mutex_unlock(track_mutex);
371 }
372
373 /**
374 * ags_track_unset_flags:
375 * @track: the #AgsTrack
376 * @flags: the flags
377 *
378 * Unset @flags on @track.
379 *
380 * Since: 3.0.0
381 */
382 void
ags_track_unset_flags(AgsTrack * track,guint flags)383 ags_track_unset_flags(AgsTrack *track, guint flags)
384 {
385 GRecMutex *track_mutex;
386
387 if(!AGS_IS_TRACK(track)){
388 return;
389 }
390
391 /* get track mutex */
392 track_mutex = AGS_TRACK_GET_OBJ_MUTEX(track);
393
394 /* unset */
395 g_rec_mutex_lock(track_mutex);
396
397 track->flags &= (~flags);
398
399 g_rec_mutex_unlock(track_mutex);
400 }
401
402 /**
403 * ags_track_sort_func:
404 * @a: an #AgsTrack
405 * @b: an #AgsTrack
406 *
407 * Sort tracks.
408 *
409 * Returns: 0 if equal, -1 if smaller and 1 if bigger offset
410 *
411 * Since: 3.0.0
412 */
413 gint
ags_track_sort_func(gconstpointer a,gconstpointer b)414 ags_track_sort_func(gconstpointer a,
415 gconstpointer b)
416 {
417 guint64 a_x, b_x ;
418
419 if(a == NULL || b == NULL){
420 return(0);
421 }
422
423 g_object_get(a,
424 "x", &a_x ,
425 NULL);
426
427 g_object_get(b,
428 "x", &b_x ,
429 NULL);
430
431 if(a_x == b_x){
432 return(0);
433 }
434
435 if(a_x < b_x){
436 return(-1);
437 }else{
438 return(1);
439 }
440 }
441
442 /**
443 * ags_track_get_x:
444 * @track: the #AgsTrack
445 *
446 * Gets x.
447 *
448 * Returns: the x
449 *
450 * Since: 3.1.0
451 */
452 guint64
ags_track_get_x(AgsTrack * track)453 ags_track_get_x(AgsTrack *track)
454 {
455 guint64 x;
456
457 if(!AGS_IS_TRACK(track)){
458 return(0);
459 }
460
461 g_object_get(track,
462 "x", &x,
463 NULL);
464
465 return(x);
466 }
467
468 /**
469 * ags_track_set_x:
470 * @track: the #AgsTrack
471 * @x: the x
472 *
473 * Sets x.
474 *
475 * Since: 3.1.0
476 */
477 void
ags_track_set_x(AgsTrack * track,guint64 x)478 ags_track_set_x(AgsTrack *track, guint64 x)
479 {
480 if(!AGS_IS_TRACK(track)){
481 return;
482 }
483
484 g_object_set(track,
485 "x", x,
486 NULL);
487 }
488
489 /**
490 * ags_track_get_data:
491 * @track: the #AgsTrack
492 * @smf_buffer_length: (out): the SMF buffer length return location
493 *
494 * Gets data.
495 *
496 * Returns: the data
497 *
498 * Since: 3.1.0
499 */
500 gpointer
ags_track_get_smf_buffer(AgsTrack * track,guint * smf_buffer_length)501 ags_track_get_smf_buffer(AgsTrack *track,
502 guint *smf_buffer_length)
503 {
504 gpointer smf_buffer;
505
506 GRecMutex *track_mutex;
507
508 if(!AGS_IS_TRACK(track)){
509 return(NULL);
510 }
511
512 /* get track mutex */
513 track_mutex = AGS_TRACK_GET_OBJ_MUTEX(track);
514
515 /* set format */
516 g_rec_mutex_lock(track_mutex);
517
518 smf_buffer = track->smf_buffer;
519
520 if(smf_buffer_length != NULL){
521 smf_buffer_length[0] = track->smf_buffer_length;
522 }
523
524 g_rec_mutex_unlock(track_mutex);
525
526 return(smf_buffer);
527 }
528
529 /**
530 * ags_track_duplicate:
531 * @track: an #AgsTrack
532 *
533 * Duplicate a track.
534 *
535 * Returns: (transfer full): the duplicated #AgsTrack.
536 *
537 * Since: 3.0.0
538 */
539 AgsTrack*
ags_track_duplicate(AgsTrack * track)540 ags_track_duplicate(AgsTrack *track)
541 {
542 AgsTrack *track_copy;
543
544 guint copy_mode;
545
546 GRecMutex *track_mutex;
547
548 if(!AGS_IS_TRACK(track)){
549 return(NULL);
550 }
551
552 /* get track mutex */
553 track_mutex = AGS_TRACK_GET_OBJ_MUTEX(track);
554
555 /* instantiate track */
556 track_copy = ags_track_new();
557
558 track_copy->flags = 0;
559
560 g_rec_mutex_lock(track_mutex);
561
562 track_copy->x = track->x;
563
564 // g_object_set(track_copy,
565 // NULL);
566
567 //TODO:JK: implement me
568
569 g_rec_mutex_unlock(track_mutex);
570
571 return(track_copy);
572 }
573
574 /**
575 * ags_track_alloc_smf_buffer:
576 * @track: the #AgsTrack
577 * @smf_buffer_length: SMF buffer length
578 *
579 * Allocate SMF buffer of @track.
580 *
581 * Returns: the newly allocated SMF buffer
582 *
583 * Since: 3.6.17
584 */
585 gpointer
ags_track_alloc_smf_buffer(AgsTrack * track,guint smf_buffer_length)586 ags_track_alloc_smf_buffer(AgsTrack *track,
587 guint smf_buffer_length)
588 {
589 guchar *smf_buffer;
590
591 GRecMutex *track_mutex;
592
593 if(!AGS_IS_TRACK(track) ||
594 smf_buffer_length == 0){
595 return(NULL);
596 }
597
598 /* get track mutex */
599 track_mutex = AGS_TRACK_GET_OBJ_MUTEX(track);
600
601 smf_buffer = NULL;
602
603 g_rec_mutex_lock(track_mutex);
604
605 if(track->smf_buffer == NULL){
606 smf_buffer =
607 track->smf_buffer = (guchar *) g_malloc(smf_buffer_length * sizeof(guchar));
608
609 track->allocated_smf_buffer_length = smf_buffer_length;
610 }
611
612 g_rec_mutex_lock(track_mutex);
613
614 return(smf_buffer);
615 }
616
617 /**
618 * ags_track_realloc_smf_buffer:
619 * @track: the #AgsTrack
620 * @smf_buffer_length: SMF buffer length
621 *
622 * Reallocate SMF buffer of @track.
623 *
624 * Returns: the reallocated SMF buffer
625 *
626 * Since: 3.6.17
627 */
628 gpointer
ags_track_realloc_smf_buffer(AgsTrack * track,guint smf_buffer_length)629 ags_track_realloc_smf_buffer(AgsTrack *track,
630 guint smf_buffer_length)
631 {
632 guchar *smf_buffer;
633
634 GRecMutex *track_mutex;
635
636 if(!AGS_IS_TRACK(track) ||
637 smf_buffer_length == 0){
638 return(NULL);
639 }
640
641 /* get track mutex */
642 track_mutex = AGS_TRACK_GET_OBJ_MUTEX(track);
643
644 smf_buffer = NULL;
645
646 g_rec_mutex_lock(track_mutex);
647
648 if(track->smf_buffer != NULL){
649 smf_buffer =
650 track->smf_buffer = (guchar *) g_realloc(track->smf_buffer,
651 smf_buffer_length * sizeof(guchar));
652
653 track->allocated_smf_buffer_length = smf_buffer_length;
654 }
655
656 g_rec_mutex_lock(track_mutex);
657
658 return(smf_buffer);
659 }
660
661 /**
662 * ags_track_new:
663 *
664 * Creates a new instance of #AgsTrack.
665 *
666 * Returns: the new #AgsTrack
667 *
668 * Since: 3.0.0
669 */
670 AgsTrack*
ags_track_new()671 ags_track_new()
672 {
673 AgsTrack *track;
674
675 track = (AgsTrack *) g_object_new(AGS_TYPE_TRACK,
676 NULL);
677
678 return(track);
679 }
680