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