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_wave.h>
21 
22 #include <ags/audio/ags_audio.h>
23 #include <ags/audio/ags_audio_buffer_util.h>
24 
25 #include <ags/i18n.h>
26 
27 #include <errno.h>
28 
29 void ags_wave_class_init(AgsWaveClass *wave);
30 void ags_wave_init(AgsWave *wave);
31 void ags_wave_set_property(GObject *gobject,
32 			   guint prop_id,
33 			   const GValue *value,
34 			   GParamSpec *param_spec);
35 void ags_wave_get_property(GObject *gobject,
36 			   guint prop_id,
37 			   GValue *value,
38 			   GParamSpec *param_spec);
39 void ags_wave_dispose(GObject *gobject);
40 void ags_wave_finalize(GObject *gobject);
41 
42 void ags_wave_insert_native_level_from_clipboard_version_1_4_0(AgsWave *wave,
43 							       xmlNode *root_node, char *version,
44 							       char *x_boundary,
45 							       gboolean reset_x_offset, guint64 x_offset,
46 							       gdouble delay, guint attack,
47 							       gboolean match_line, gboolean do_replace,
48 							       guint current_line,
49 							       guint64 relative_offset,
50 							       guint wave_samplerate,
51 							       guint wave_buffer_size,
52 							       guint wave_format,
53 							       gboolean match_timestamp);
54 
55 void ags_wave_insert_native_level_from_clipboard(AgsWave *wave,
56 						 xmlNode *root_node, char *version,
57 						 char *x_boundary,
58 						 gboolean reset_x_offset, guint64 x_offset,
59 						 gdouble delay, guint attack,
60 						 gboolean match_line, gboolean do_replace);
61 
62 /**
63  * SECTION:ags_wave
64  * @short_description: Wave class supporting selection and clipboard.
65  * @title: AgsWave
66  * @section_id:
67  * @include: ags/audio/ags_wave.h
68  *
69  * #AgsWave acts as a container of #AgsBuffer.
70  */
71 
72 enum{
73   PROP_0,
74   PROP_AUDIO,
75   PROP_LINE,
76   PROP_SAMPLERATE,
77   PROP_BUFFER_SIZE,
78   PROP_FORMAT,
79   PROP_TIMESTAMP,
80   PROP_BUFFER,
81 };
82 
83 static gpointer ags_wave_parent_class = NULL;
84 
85 GType
ags_wave_get_type()86 ags_wave_get_type()
87 {
88   static volatile gsize g_define_type_id__volatile = 0;
89 
90   if(g_once_init_enter (&g_define_type_id__volatile)){
91     GType ags_type_wave = 0;
92 
93     static const GTypeInfo ags_wave_info = {
94       sizeof(AgsWaveClass),
95       NULL,
96       NULL,
97       (GClassInitFunc) ags_wave_class_init,
98       NULL,
99       NULL,
100       sizeof(AgsWave),
101       0,
102       (GInstanceInitFunc) ags_wave_init,
103     };
104 
105     ags_type_wave = g_type_register_static(G_TYPE_OBJECT,
106 					   "AgsWave",
107 					   &ags_wave_info,
108 					   0);
109 
110     g_once_init_leave(&g_define_type_id__volatile, ags_type_wave);
111   }
112 
113   return g_define_type_id__volatile;
114 }
115 
116 void
ags_wave_class_init(AgsWaveClass * wave)117 ags_wave_class_init(AgsWaveClass *wave)
118 {
119   GObjectClass *gobject;
120   GParamSpec *param_spec;
121 
122   ags_wave_parent_class = g_type_class_peek_parent(wave);
123 
124   gobject = (GObjectClass *) wave;
125 
126   gobject->set_property = ags_wave_set_property;
127   gobject->get_property = ags_wave_get_property;
128 
129   gobject->dispose = ags_wave_dispose;
130   gobject->finalize = ags_wave_finalize;
131 
132   /* properties */
133   /**
134    * AgsWave:audio:
135    *
136    * The assigned #AgsAudio
137    *
138    * Since: 3.0.0
139    */
140   param_spec = g_param_spec_object("audio",
141 				   i18n_pspec("audio of wave"),
142 				   i18n_pspec("The audio of wave"),
143 				   AGS_TYPE_AUDIO,
144 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
145   g_object_class_install_property(gobject,
146 				  PROP_AUDIO,
147 				  param_spec);
148 
149   /**
150    * AgsWave:line:
151    *
152    * The wave's line.
153    *
154    * Since: 3.0.0
155    */
156   param_spec =  g_param_spec_uint("line",
157 				  i18n_pspec("line of wave"),
158 				  i18n_pspec("The numerical line of wave"),
159 				  0,
160 				  G_MAXUINT32,
161 				  0,
162 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
163   g_object_class_install_property(gobject,
164 				  PROP_LINE,
165 				  param_spec);
166 
167   /**
168    * AgsWave:samplerate:
169    *
170    * The audio buffer's samplerate.
171    *
172    * Since: 3.0.0
173    */
174   param_spec =  g_param_spec_uint("samplerate",
175 				  i18n_pspec("samplerate of audio buffer"),
176 				  i18n_pspec("The samplerate of audio buffer"),
177 				  0,
178 				  G_MAXUINT32,
179 				  AGS_SOUNDCARD_DEFAULT_SAMPLERATE,
180 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
181   g_object_class_install_property(gobject,
182 				  PROP_SAMPLERATE,
183 				  param_spec);
184 
185   /**
186    * AgsWave:buffer-size:
187    *
188    * The audio buffer's buffer size.
189    *
190    * Since: 3.0.0
191    */
192   param_spec =  g_param_spec_uint("buffer-size",
193 				  i18n_pspec("buffer size of audio buffer"),
194 				  i18n_pspec("The buffer size of audio buffer"),
195 				  0,
196 				  G_MAXUINT32,
197 				  AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE,
198 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
199   g_object_class_install_property(gobject,
200 				  PROP_BUFFER_SIZE,
201 				  param_spec);
202 
203   /**
204    * AgsWave:format:
205    *
206    * The audio buffer's format.
207    *
208    * Since: 3.0.0
209    */
210   param_spec =  g_param_spec_uint("format",
211 				  i18n_pspec("format of audio buffer"),
212 				  i18n_pspec("The format of audio buffer"),
213 				  0,
214 				  G_MAXUINT32,
215 				  AGS_SOUNDCARD_DEFAULT_FORMAT,
216 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
217   g_object_class_install_property(gobject,
218 				  PROP_FORMAT,
219 				  param_spec);
220 
221   /**
222    * AgsWave:timestamp:
223    *
224    * The pattern's timestamp.
225    *
226    * Since: 3.0.0
227    */
228   param_spec = g_param_spec_object("timestamp",
229 				   i18n_pspec("timestamp of pattern"),
230 				   i18n_pspec("The timestamp of pattern"),
231 				   AGS_TYPE_TIMESTAMP,
232 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
233   g_object_class_install_property(gobject,
234 				  PROP_TIMESTAMP,
235 				  param_spec);
236 
237   /**
238    * AgsWave:buffer: (type GList(AgsBuffer)) (transfer full)
239    *
240    * The assigned #AgsBuffer
241    *
242    * Since: 3.0.0
243    */
244   param_spec = g_param_spec_pointer("buffer",
245 				    i18n_pspec("buffer of wave"),
246 				    i18n_pspec("The buffer of wave"),
247 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
248   g_object_class_install_property(gobject,
249 				  PROP_BUFFER,
250 				  param_spec);
251 }
252 
253 void
ags_wave_init(AgsWave * wave)254 ags_wave_init(AgsWave *wave)
255 {
256   AgsConfig *config;
257 
258   wave->flags = 0;
259 
260   /* wave mutex */
261   g_rec_mutex_init(&(wave->obj_mutex));
262 
263   /* config */
264   config = ags_config_get_instance();
265 
266   /* fields */
267   wave->audio = NULL;
268   wave->line = 0;
269 
270   wave->samplerate = (guint) ags_soundcard_helper_config_get_samplerate(config);
271   wave->buffer_size = (guint) ags_soundcard_helper_config_get_buffer_size(config);
272   wave->format = (guint) ags_soundcard_helper_config_get_format(config);
273 
274   wave->timestamp = ags_timestamp_new();
275 
276   wave->timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
277   wave->timestamp->flags |= AGS_TIMESTAMP_OFFSET;
278 
279   wave->timestamp->timer.ags_offset.offset = 0;
280 
281   g_object_ref(wave->timestamp);
282 
283   wave->buffer = NULL;
284   wave->selection = NULL;
285 }
286 
287 void
ags_wave_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)288 ags_wave_set_property(GObject *gobject,
289 		      guint prop_id,
290 		      const GValue *value,
291 		      GParamSpec *param_spec)
292 {
293   AgsWave *wave;
294 
295   GRecMutex *wave_mutex;
296 
297   wave = AGS_WAVE(gobject);
298 
299   /* get wave mutex */
300   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
301 
302   switch(prop_id){
303   case PROP_AUDIO:
304     {
305       AgsAudio *audio;
306 
307       audio = (AgsAudio *) g_value_get_object(value);
308 
309       g_rec_mutex_lock(wave_mutex);
310 
311       if(wave->audio == (GObject *) audio){
312 	g_rec_mutex_unlock(wave_mutex);
313 
314 	return;
315       }
316 
317       if(wave->audio != NULL){
318 	g_object_unref(wave->audio);
319       }
320 
321       if(audio != NULL){
322 	g_object_ref(audio);
323       }
324 
325       wave->audio = (GObject *) audio;
326 
327       g_rec_mutex_unlock(wave_mutex);
328     }
329     break;
330   case PROP_LINE:
331     {
332       guint line;
333 
334       line = g_value_get_uint(value);
335 
336       g_rec_mutex_lock(wave_mutex);
337 
338       wave->line = line;
339 
340       g_rec_mutex_unlock(wave_mutex);
341     }
342     break;
343   case PROP_SAMPLERATE:
344     {
345       guint samplerate;
346 
347       samplerate = g_value_get_uint(value);
348 
349       ags_wave_set_samplerate(wave,
350 			      samplerate);
351     }
352     break;
353   case PROP_BUFFER_SIZE:
354     {
355       guint buffer_size;
356 
357       buffer_size = g_value_get_uint(value);
358 
359       ags_wave_set_buffer_size(wave,
360 			       buffer_size);
361     }
362     break;
363   case PROP_FORMAT:
364     {
365       guint format;
366 
367       format = g_value_get_uint(value);
368 
369       ags_wave_set_format(wave,
370 			  format);
371     }
372     break;
373   case PROP_TIMESTAMP:
374     {
375       AgsTimestamp *timestamp;
376 
377       timestamp = (AgsTimestamp *) g_value_get_object(value);
378 
379       g_rec_mutex_lock(wave_mutex);
380 
381       if(timestamp == wave->timestamp){
382 	g_rec_mutex_unlock(wave_mutex);
383 
384 	return;
385       }
386 
387       if(wave->timestamp != NULL){
388 	g_object_unref(G_OBJECT(wave->timestamp));
389       }
390 
391       if(timestamp != NULL){
392 	g_object_ref(G_OBJECT(timestamp));
393       }
394 
395       wave->timestamp = timestamp;
396 
397       g_rec_mutex_unlock(wave_mutex);
398     }
399     break;
400   case PROP_BUFFER:
401     {
402       AgsBuffer *buffer;
403 
404       buffer = (AgsBuffer *) g_value_get_pointer(value);
405 
406       g_rec_mutex_lock(wave_mutex);
407 
408       if(buffer == NULL ||
409 	 g_list_find(wave->buffer, buffer) != NULL){
410 	g_rec_mutex_unlock(wave_mutex);
411 
412 	return;
413       }
414 
415       g_rec_mutex_unlock(wave_mutex);
416 
417       ags_wave_add_buffer(wave,
418 			  buffer,
419 			  FALSE);
420     }
421     break;
422   default:
423     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
424     break;
425   }
426 }
427 
428 void
ags_wave_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)429 ags_wave_get_property(GObject *gobject,
430 		      guint prop_id,
431 		      GValue *value,
432 		      GParamSpec *param_spec)
433 {
434   AgsWave *wave;
435 
436   GRecMutex *wave_mutex;
437 
438   wave = AGS_WAVE(gobject);
439 
440   /* get wave mutex */
441   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
442 
443   switch(prop_id){
444   case PROP_AUDIO:
445     {
446       g_rec_mutex_lock(wave_mutex);
447 
448       g_value_set_object(value, wave->audio);
449 
450       g_rec_mutex_unlock(wave_mutex);
451     }
452     break;
453   case PROP_LINE:
454     {
455       g_rec_mutex_lock(wave_mutex);
456 
457       g_value_set_uint(value, wave->line);
458 
459       g_rec_mutex_unlock(wave_mutex);
460     }
461     break;
462   case PROP_SAMPLERATE:
463     {
464       g_rec_mutex_lock(wave_mutex);
465 
466       g_value_set_uint(value, wave->samplerate);
467 
468       g_rec_mutex_unlock(wave_mutex);
469     }
470     break;
471   case PROP_BUFFER_SIZE:
472     {
473       g_rec_mutex_lock(wave_mutex);
474 
475       g_value_set_uint(value, wave->buffer_size);
476 
477       g_rec_mutex_unlock(wave_mutex);
478     }
479     break;
480   case PROP_FORMAT:
481     {
482       g_rec_mutex_lock(wave_mutex);
483 
484       g_value_set_uint(value, wave->format);
485 
486       g_rec_mutex_unlock(wave_mutex);
487     }
488     break;
489   case PROP_TIMESTAMP:
490     {
491       g_rec_mutex_lock(wave_mutex);
492 
493       g_value_set_object(value, wave->timestamp);
494 
495       g_rec_mutex_unlock(wave_mutex);
496     }
497     break;
498   case PROP_BUFFER:
499     {
500       g_rec_mutex_lock(wave_mutex);
501 
502       g_value_set_pointer(value, g_list_copy_deep(wave->buffer,
503 						  (GCopyFunc) g_object_ref,
504 						  NULL));
505 
506       g_rec_mutex_unlock(wave_mutex);
507     }
508     break;
509   default:
510     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
511     break;
512   }
513 }
514 
515 void
ags_wave_dispose(GObject * gobject)516 ags_wave_dispose(GObject *gobject)
517 {
518   AgsWave *wave;
519 
520   GList *list;
521 
522   wave = AGS_WAVE(gobject);
523 
524   /* audio */
525   if(wave->audio != NULL){
526     g_object_unref(wave->audio);
527 
528     wave->audio = NULL;
529   }
530 
531   /* timestamp */
532   if(wave->timestamp != NULL){
533     g_object_unref(wave->timestamp);
534 
535     wave->timestamp = NULL;
536   }
537 
538   /* buffer and selection */
539   list = wave->buffer;
540 
541   while(list != NULL){
542     g_object_run_dispose(G_OBJECT(list->data));
543 
544     list = list->next;
545   }
546 
547   g_list_free_full(wave->buffer,
548 		   g_object_unref);
549   g_list_free_full(wave->selection,
550 		   g_object_unref);
551 
552   wave->buffer = NULL;
553   wave->selection = NULL;
554 
555   /* call parent */
556   G_OBJECT_CLASS(ags_wave_parent_class)->dispose(gobject);
557 }
558 
559 void
ags_wave_finalize(GObject * gobject)560 ags_wave_finalize(GObject *gobject)
561 {
562   AgsWave *wave;
563 
564   wave = AGS_WAVE(gobject);
565 
566   /* audio */
567   if(wave->audio != NULL){
568     g_object_unref(wave->audio);
569   }
570 
571   /* timestamp */
572   if(wave->timestamp != NULL){
573     g_object_unref(wave->timestamp);
574   }
575 
576   /* buffer and selection */
577   g_list_free_full(wave->buffer,
578 		   g_object_unref);
579 
580   g_list_free_full(wave->selection,
581 		   g_object_unref);
582 
583   /* call parent */
584   G_OBJECT_CLASS(ags_wave_parent_class)->finalize(gobject);
585 }
586 
587 /**
588  * ags_wave_get_obj_mutex:
589  * @wave: the #AgsWave
590  *
591  * Get object mutex.
592  *
593  * Returns: the #GRecMutex to lock @wave
594  *
595  * Since: 3.1.0
596  */
597 GRecMutex*
ags_wave_get_obj_mutex(AgsWave * wave)598 ags_wave_get_obj_mutex(AgsWave *wave)
599 {
600   if(!AGS_IS_WAVE(wave)){
601     return(NULL);
602   }
603 
604   return(AGS_WAVE_GET_OBJ_MUTEX(wave));
605 }
606 
607 /**
608  * ags_wave_test_flags:
609  * @wave: the #AgsWave
610  * @flags: the flags
611  *
612  * Test @flags to be set on @wave.
613  *
614  * Returns: %TRUE if flags are set, else %FALSE
615  *
616  * Since: 3.0.0
617  */
618 gboolean
ags_wave_test_flags(AgsWave * wave,guint flags)619 ags_wave_test_flags(AgsWave *wave, guint flags)
620 {
621   gboolean retval;
622 
623   GRecMutex *wave_mutex;
624 
625   if(!AGS_IS_WAVE(wave)){
626     return(FALSE);
627   }
628 
629   /* get wave mutex */
630   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
631 
632   /* test */
633   g_rec_mutex_lock(wave_mutex);
634 
635   retval = (flags & (wave->flags)) ? TRUE: FALSE;
636 
637   g_rec_mutex_unlock(wave_mutex);
638 
639   return(retval);
640 }
641 
642 /**
643  * ags_wave_set_flags:
644  * @wave: the #AgsWave
645  * @flags: the flags
646  *
647  * Set @flags on @wave.
648  *
649  * Since: 3.0.0
650  */
651 void
ags_wave_set_flags(AgsWave * wave,guint flags)652 ags_wave_set_flags(AgsWave *wave, guint flags)
653 {
654   GRecMutex *wave_mutex;
655 
656   if(!AGS_IS_WAVE(wave)){
657     return;
658   }
659 
660   /* get wave mutex */
661   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
662 
663   /* set */
664   g_rec_mutex_lock(wave_mutex);
665 
666   wave->flags |= flags;
667 
668   g_rec_mutex_unlock(wave_mutex);
669 }
670 
671 /**
672  * ags_wave_unset_flags:
673  * @wave: the #AgsWave
674  * @flags: the flags
675  *
676  * Unset @flags on @wave.
677  *
678  * Since: 3.0.0
679  */
680 void
ags_wave_unset_flags(AgsWave * wave,guint flags)681 ags_wave_unset_flags(AgsWave *wave, guint flags)
682 {
683   GRecMutex *wave_mutex;
684 
685   if(!AGS_IS_WAVE(wave)){
686     return;
687   }
688 
689   /* get wave mutex */
690   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
691 
692   /* set */
693   g_rec_mutex_lock(wave_mutex);
694 
695   wave->flags &= (~flags);
696 
697   g_rec_mutex_unlock(wave_mutex);
698 }
699 
700 /**
701  * ags_wave_find_near_timestamp:
702  * @wave: (element-type AgsAudio.Wave) (transfer none): the #GList-struct containing #AgsWave
703  * @line: the matching audio channel
704  * @timestamp: the matching #AgsTimestamp, or %NULL to match any timestamp
705  *
706  * Retrieve appropriate wave for timestamp.
707  *
708  * Returns: (element-type AgsAudio.Wave) (transfer none): Next matching #GList-struct or %NULL if not found
709  *
710  * Since: 3.0.0
711  */
712 GList*
ags_wave_find_near_timestamp(GList * wave,guint line,AgsTimestamp * timestamp)713 ags_wave_find_near_timestamp(GList *wave, guint line,
714 			     AgsTimestamp *timestamp)
715 {
716   AgsTimestamp *current_timestamp;
717 
718   GList *retval;
719   GList *current_start, *current_end, *current;
720 
721   guint current_line;
722   guint64 current_x, x;
723   guint length, position;
724   gboolean use_ags_offset;
725   gboolean success;
726 
727   if(wave == NULL){
728     return(NULL);
729   }
730 
731   current_start = wave;
732   current_end = g_list_last(wave);
733 
734   length = g_list_length(wave);
735   position = (length - 1) / 2;
736 
737   current = g_list_nth(current_start,
738 		       position);
739 
740   if(ags_timestamp_test_flags(timestamp,
741 			      AGS_TIMESTAMP_OFFSET)){
742     x = ags_timestamp_get_ags_offset(timestamp);
743 
744     use_ags_offset = TRUE;
745   }else if(ags_timestamp_test_flags(timestamp,
746 				    AGS_TIMESTAMP_UNIX)){
747     x = ags_timestamp_get_unix_time(timestamp);
748 
749     use_ags_offset = FALSE;
750   }else{
751     return(NULL);
752   }
753 
754   current_x = 0;
755 
756   retval = NULL;
757   success = FALSE;
758 
759   while(!success && current != NULL){
760     guint64 relative_offset;
761     guint samplerate;
762 
763     /* check current - start */
764     g_object_get(current_start->data,
765 		 "line", &current_line,
766 		 NULL);
767 
768     if(current_line == line){
769       if(timestamp == NULL){
770 	retval = current_start;
771 
772 	break;
773       }
774 
775       g_object_get(current_start->data,
776 		   "samplerate", &samplerate,
777 		   "timestamp", &current_timestamp,
778 		   NULL);
779 
780       relative_offset = AGS_WAVE_DEFAULT_BUFFER_LENGTH * samplerate;
781 
782       if(current_timestamp != NULL){
783 	if(use_ags_offset){
784 	  current_x = ags_timestamp_get_ags_offset(current_timestamp);
785 
786 	  g_object_unref(current_timestamp);
787 
788 	  if(current_x > x + relative_offset){
789 	    break;
790 	  }
791 	}else{
792 	  current_x = ags_timestamp_get_unix_time(current_timestamp);
793 
794 	  g_object_unref(current_timestamp);
795 
796 	  if(current_x > x){
797 	    break;
798 	  }
799 	}
800 
801 	if(use_ags_offset){
802 	  if(current_x >= x &&
803 	     current_x < x + relative_offset){
804 	    retval = current_start;
805 
806 	    break;
807 	  }
808 	}else{
809 	  if(current_x >= x &&
810 	     current_x < x + AGS_WAVE_DEFAULT_DURATION){
811 	    retval = current_start;
812 
813 	    break;
814 	  }
815 	}
816       }else{
817 	g_warning("inconsistent data");
818       }
819     }
820 
821     /* check current - end */
822     g_object_get(current_end->data,
823 		 "line", &current_line,
824 		 NULL);
825 
826     if(current_line == line){
827       if(timestamp == NULL){
828 	retval = current_end;
829 
830 	break;
831       }
832 
833       g_object_get(current_end->data,
834 		   "samplerate", &samplerate,
835 		   "timestamp", &current_timestamp,
836 		   NULL);
837 
838       relative_offset = AGS_WAVE_DEFAULT_BUFFER_LENGTH * samplerate;
839 
840       if(current_timestamp != NULL){
841 	if(use_ags_offset){
842 	  current_x = ags_timestamp_get_ags_offset(current_timestamp);
843 
844 	  g_object_unref(current_timestamp);
845 
846 	  if(current_x < x){
847 	    break;
848 	  }
849 	}else{
850 	  current_x = ags_timestamp_get_unix_time(current_timestamp);
851 
852 	  g_object_unref(current_timestamp);
853 
854 	  if(current_x < x){
855 	    break;
856 	  }
857 	}
858 
859 	if(use_ags_offset){
860 	  if(current_x >= x &&
861 	     current_x < x + relative_offset){
862 	    retval = current_end;
863 
864 	    break;
865 	  }
866 	}else{
867 	  if(current_x >= x &&
868 	     current_x < x + AGS_WAVE_DEFAULT_DURATION){
869 	    retval = current_end;
870 
871 	    break;
872 	  }
873 	}
874       }else{
875 	g_warning("inconsistent data");
876       }
877     }
878 
879     /* check current - center */
880     g_object_get(current->data,
881 		 "line", &current_line,
882 		 NULL);
883 
884     if(current_line == line){
885       if(timestamp == NULL){
886 	retval = current;
887 
888 	break;
889       }
890     }
891 
892     g_object_get(current->data,
893 		 "samplerate", &samplerate,
894 		 "timestamp", &current_timestamp,
895 		 NULL);
896 
897     relative_offset = AGS_WAVE_DEFAULT_BUFFER_LENGTH * samplerate;
898 
899     if(current_timestamp != NULL){
900       if(use_ags_offset){
901 	current_x = ags_timestamp_get_ags_offset(current_timestamp);
902 
903 	g_object_unref(current_timestamp);
904 
905 	if(current_x >= x &&
906 	   current_x < x + relative_offset &&
907 	   current_line == line){
908 	  retval = current;
909 
910 	  break;
911 	}
912       }else{
913 	current_x = ags_timestamp_get_unix_time(current_timestamp);
914 
915 	g_object_unref(current_timestamp);
916 
917 	if(current_x >= x &&
918 	   current_x < x + AGS_WAVE_DEFAULT_DURATION &&
919 	   current_line == line){
920 	  retval = current;
921 
922 	  break;
923 	}
924       }
925     }else{
926       g_warning("inconsistent data");
927     }
928 
929     if(length <= 3){
930       break;
931     }
932 
933     if(current_x < x){
934       current_start = current->next;
935       current_end = current_end->prev;
936     }else if(current_x > x){
937       current_start = current_start->next;
938       current_end = current->prev;
939     }else{
940       current_start = current_start->next;
941       //NOTE:JK: we want progression
942       //current_end = current_end->prev;
943     }
944 
945     length = g_list_position(current_start,
946 			     current_end) + 1;
947     position = (length - 1) / 2;
948 
949     current = g_list_nth(current_start,
950 			 position);
951   }
952 
953   return(retval);
954 }
955 
956 /**
957  * ags_wave_sort_func:
958  * @a: the #AgsWave
959  * @b: another #AgsWave
960  *
961  * Compare @a and @b.
962  *
963  * Returns: 0 if equal, -1 if smaller and 1 if bigger timestamp
964  *
965  * Since: 3.0.0
966  */
967 gint
ags_wave_sort_func(gconstpointer a,gconstpointer b)968 ags_wave_sort_func(gconstpointer a,
969 		   gconstpointer b)
970 {
971   AgsTimestamp *timestamp_a, *timestamp_b;
972 
973   guint64 offset_a, offset_b;
974 
975   g_object_get(a,
976 	       "timestamp", &timestamp_a,
977 	       NULL);
978 
979   g_object_get(b,
980 	       "timestamp", &timestamp_b,
981 	       NULL);
982 
983   offset_a = ags_timestamp_get_ags_offset(timestamp_a);
984   offset_b = ags_timestamp_get_ags_offset(timestamp_b);
985 
986   g_object_unref(timestamp_a);
987   g_object_unref(timestamp_b);
988 
989   if(offset_a == offset_b){
990     return(0);
991   }else if(offset_a < offset_b){
992     return(-1);
993   }else if(offset_a > offset_b){
994     return(1);
995   }
996 
997   return(0);
998 }
999 
1000 /**
1001  * ags_wave_get_audio:
1002  * @wave: the #AgsWave
1003  *
1004  * Get audio.
1005  *
1006  * Returns: (transfer full): the #AgsAudio
1007  *
1008  * Since: 3.1.0
1009  */
1010 GObject*
ags_wave_get_audio(AgsWave * wave)1011 ags_wave_get_audio(AgsWave *wave)
1012 {
1013   GObject *audio;
1014 
1015   if(!AGS_IS_WAVE(wave)){
1016     return(NULL);
1017   }
1018 
1019   g_object_get(wave,
1020 	       "audio", &audio,
1021 	       NULL);
1022 
1023   return(audio);
1024 }
1025 
1026 /**
1027  * ags_wave_set_audio:
1028  * @wave: the #AgsWave
1029  * @audio: the #AgsAudio
1030  *
1031  * Set audio.
1032  *
1033  * Since: 3.1.0
1034  */
1035 void
ags_wave_set_audio(AgsWave * wave,GObject * audio)1036 ags_wave_set_audio(AgsWave *wave, GObject *audio)
1037 {
1038   if(!AGS_IS_WAVE(wave)){
1039     return;
1040   }
1041 
1042   g_object_set(wave,
1043 	       "audio", audio,
1044 	       NULL);
1045 }
1046 
1047 /**
1048  * ags_wave_get_line:
1049  * @wave: the #AgsWave
1050  *
1051  * Gets line.
1052  *
1053  * Returns: the line
1054  *
1055  * Since: 3.1.0
1056  */
1057 guint
ags_wave_get_line(AgsWave * wave)1058 ags_wave_get_line(AgsWave *wave)
1059 {
1060   guint line;
1061 
1062   if(!AGS_IS_WAVE(wave)){
1063     return(0);
1064   }
1065 
1066   g_object_get(wave,
1067 	       "line", &line,
1068 	       NULL);
1069 
1070   return(line);
1071 }
1072 
1073 /**
1074  * ags_wave_set_line:
1075  * @wave: the #AgsWave
1076  * @line: the line
1077  *
1078  * Sets line.
1079  *
1080  * Since: 3.1.0
1081  */
1082 void
ags_wave_set_line(AgsWave * wave,guint line)1083 ags_wave_set_line(AgsWave *wave, guint line)
1084 {
1085   if(!AGS_IS_WAVE(wave)){
1086     return;
1087   }
1088 
1089   g_object_set(wave,
1090 	       "line", line,
1091 	       NULL);
1092 }
1093 
1094 /**
1095  * ags_wave_get_samplerate:
1096  * @wave: the #AgsWave
1097  *
1098  * Gets samplerate.
1099  *
1100  * Returns: the samplerate
1101  *
1102  * Since: 3.1.0
1103  */
1104 guint
ags_wave_get_samplerate(AgsWave * wave)1105 ags_wave_get_samplerate(AgsWave *wave)
1106 {
1107   guint samplerate;
1108 
1109   if(!AGS_IS_WAVE(wave)){
1110     return(0);
1111   }
1112 
1113   g_object_get(wave,
1114 	       "samplerate", &samplerate,
1115 	       NULL);
1116 
1117   return(samplerate);
1118 }
1119 
1120 /**
1121  * ags_wave_set_samplerate:
1122  * @wave: the #AgsWave
1123  * @samplerate: the samplerate
1124  *
1125  * Set samplerate.
1126  *
1127  * Since: 3.0.0
1128  */
1129 void
ags_wave_set_samplerate(AgsWave * wave,guint samplerate)1130 ags_wave_set_samplerate(AgsWave *wave,
1131 			guint samplerate)
1132 {
1133   GList *start_list, *list;
1134 
1135   void *data, *resampled_data;
1136 
1137   guint64 x;
1138   guint end_offset;
1139   guint buffer_length;
1140   guint new_buffer_length;
1141   guint buffer_size;
1142   guint old_samplerate;
1143   guint format;
1144   guint offset;
1145   guint copy_mode;
1146   guint i;
1147 
1148   GRecMutex *wave_mutex;
1149 
1150   if(!AGS_IS_WAVE(wave)){
1151     return;
1152   }
1153 
1154   /* get wave mutex */
1155   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
1156 
1157   /* check resample */
1158   g_rec_mutex_lock(wave_mutex);
1159 
1160   old_samplerate = wave->samplerate;
1161 
1162   g_rec_mutex_unlock(wave_mutex);
1163 
1164   if(old_samplerate == samplerate){
1165     return;
1166   }
1167 
1168   /* apply samplerate */
1169   g_rec_mutex_lock(wave_mutex);
1170 
1171   x = ags_timestamp_get_ags_offset(wave->timestamp);
1172 
1173   buffer_size = wave->buffer_size;
1174   format = wave->format;
1175 
1176   wave->samplerate = samplerate;
1177 
1178   start_list = g_list_copy(wave->buffer);
1179 
1180   g_rec_mutex_unlock(wave_mutex);
1181 
1182   data = NULL;
1183 
1184   buffer_length = g_list_length(start_list);
1185 
1186   new_buffer_length = (guint) ceil((samplerate * (buffer_length * buffer_size / old_samplerate)) / buffer_size);
1187 
1188   copy_mode = G_MAXUINT;
1189 
1190   switch(format){
1191   case AGS_SOUNDCARD_SIGNED_8_BIT:
1192     {
1193       data = (gint8 *) malloc(buffer_length * buffer_size * sizeof(gint8));
1194       memset(data, 0, buffer_length * buffer_size * sizeof(gint8));
1195 
1196       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_S8_TO_S8;
1197     }
1198     break;
1199   case AGS_SOUNDCARD_SIGNED_16_BIT:
1200     {
1201       data = (gint16 *) malloc(buffer_length * buffer_size * sizeof(gint16));
1202       memset(data, 0, buffer_length * buffer_size * sizeof(gint16));
1203 
1204       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_S16_TO_S16;
1205     }
1206     break;
1207   case AGS_SOUNDCARD_SIGNED_24_BIT:
1208     {
1209       data = (gint32 *) malloc(buffer_length * buffer_size * sizeof(gint32));
1210       memset(data, 0, buffer_length * buffer_size * sizeof(gint32));
1211 
1212       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_S32_TO_S32;
1213     }
1214     break;
1215   case AGS_SOUNDCARD_SIGNED_32_BIT:
1216     {
1217       data = (gint32 *) malloc(buffer_length * buffer_size * sizeof(gint32));
1218       memset(data, 0, buffer_length * buffer_size * sizeof(gint32));
1219 
1220       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_S32_TO_S32;
1221     }
1222     break;
1223   case AGS_SOUNDCARD_SIGNED_64_BIT:
1224     {
1225       data = (gint64 *) malloc(buffer_length * buffer_size * sizeof(gint64));
1226       memset(data, 0, buffer_length * buffer_size * sizeof(gint64));
1227 
1228       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_S64_TO_S64;
1229     }
1230     break;
1231   case AGS_SOUNDCARD_FLOAT:
1232     {
1233       data = (gfloat *) malloc(buffer_length * buffer_size * sizeof(gfloat));
1234       memset(data, 0, buffer_length * buffer_size * sizeof(gfloat));
1235 
1236       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_FLOAT_TO_FLOAT;
1237     }
1238     break;
1239   case AGS_SOUNDCARD_DOUBLE:
1240     {
1241       data = (gdouble *) malloc(buffer_length * buffer_size * sizeof(gdouble));
1242       memset(data, 0, buffer_length * buffer_size * sizeof(gdouble));
1243 
1244       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_DOUBLE_TO_DOUBLE;
1245     }
1246     break;
1247   default:
1248     g_warning("ags_audio_signal_set_buffer_samplerate() - unsupported format");
1249   }
1250 
1251   list = start_list;
1252   offset = 0;
1253 
1254   while(list != NULL){
1255     GRecMutex *buffer_mutex;
1256 
1257     /* get buffer mutex */
1258     buffer_mutex = AGS_BUFFER_GET_OBJ_MUTEX(list->data);
1259 
1260     /*  */
1261     g_rec_mutex_lock(buffer_mutex);
1262 
1263     ags_audio_buffer_util_copy_buffer_to_buffer(data, 1, offset,
1264 						AGS_BUFFER(list->data)->data, 1, 0,
1265 						buffer_size, copy_mode);
1266 
1267     g_rec_mutex_unlock(buffer_mutex);
1268 
1269     /* iterate */
1270     list = list->next;
1271 
1272     offset += buffer_size;
1273   }
1274 
1275   resampled_data = ags_stream_alloc(new_buffer_length * buffer_size,
1276 				    format);
1277 
1278   ags_audio_buffer_util_resample_with_buffer(data, 1,
1279 					     ags_audio_buffer_util_format_from_soundcard(format), old_samplerate,
1280 					     buffer_length * buffer_size,
1281 					     samplerate,
1282 					     new_buffer_length * buffer_size,
1283 					     resampled_data);
1284 
1285   if(data != NULL){
1286     free(data);
1287   }
1288 
1289   if(samplerate < old_samplerate){
1290     list = g_list_nth(start_list,
1291 		      new_buffer_length);
1292 
1293     for(i = 0; i < buffer_length - new_buffer_length && list != NULL; i++){
1294       ags_wave_remove_buffer(wave,
1295 			     list->data,
1296 			     FALSE);
1297 
1298       list = list->next;
1299     }
1300   }else{
1301     for(i = 0; i < new_buffer_length - buffer_length; i++){
1302       AgsBuffer *current;
1303 
1304       current = ags_buffer_new();
1305       g_object_set(current,
1306 		   "x", x + i * buffer_size,
1307 		   NULL);
1308       ags_buffer_set_buffer_size(current,
1309 				 buffer_size);
1310 
1311       ags_wave_add_buffer(wave,
1312 			  current,
1313 			  FALSE);
1314     }
1315   }
1316 
1317   g_list_free(start_list);
1318 
1319   g_object_get(wave,
1320 	       "buffer", &start_list,
1321 	       NULL);
1322 
1323   list = start_list;
1324 
1325   offset = 0;
1326   end_offset = (buffer_length * buffer_size);
1327 
1328   while(list != NULL && offset < buffer_length * buffer_size){
1329     GRecMutex *buffer_mutex;
1330 
1331     /* get buffer mutex */
1332     buffer_mutex = AGS_BUFFER_GET_OBJ_MUTEX(list->data);
1333 
1334     /*  */
1335     ags_buffer_set_samplerate(list->data,
1336 			      samplerate);
1337 
1338     g_rec_mutex_lock(buffer_mutex);
1339 
1340     ags_audio_buffer_util_clear_buffer(AGS_BUFFER(list->data)->data, 1,
1341 				       buffer_size, ags_audio_buffer_util_format_from_soundcard(format));
1342 
1343     if(offset + buffer_size < buffer_length * buffer_size){
1344       ags_audio_buffer_util_copy_buffer_to_buffer(AGS_BUFFER(list->data)->data, 1, 0,
1345 						  resampled_data, 1, offset,
1346 						  buffer_size, copy_mode);
1347     }else{
1348       if(end_offset > offset){
1349 	ags_audio_buffer_util_copy_buffer_to_buffer(AGS_BUFFER(list->data)->data, 1, 0,
1350 						    resampled_data, 1, offset,
1351 						    end_offset - offset, copy_mode);
1352 
1353 	ags_audio_buffer_util_clear_buffer(AGS_BUFFER(list->data)->data + (end_offset - offset), 1,
1354 					   buffer_size - (end_offset - offset), ags_audio_buffer_util_format_from_soundcard(format));
1355       }
1356     }
1357 
1358     g_rec_mutex_unlock(buffer_mutex);
1359 
1360     /* iterate */
1361     list = list->next;
1362 
1363     offset += buffer_size;
1364   }
1365 
1366   g_list_free_full(start_list,
1367 		   g_object_unref);
1368 
1369   if(resampled_data != NULL){
1370     free(resampled_data);
1371   }
1372 }
1373 
1374 /**
1375  * ags_wave_get_buffer_size:
1376  * @wave: the #AgsWave
1377  *
1378  * Gets buffer size.
1379  *
1380  * Returns: the buffer size
1381  *
1382  * Since: 3.1.0
1383  */
1384 guint
ags_wave_get_buffer_size(AgsWave * wave)1385 ags_wave_get_buffer_size(AgsWave *wave)
1386 {
1387   guint buffer_size;
1388 
1389   if(!AGS_IS_WAVE(wave)){
1390     return(0);
1391   }
1392 
1393   g_object_get(wave,
1394 	       "buffer-size", &buffer_size,
1395 	       NULL);
1396 
1397   return(buffer_size);
1398 }
1399 
1400 /**
1401  * ags_wave_set_buffer_size:
1402  * @wave: the #AgsWave
1403  * @buffer_size: the buffer size
1404  *
1405  * Set buffer size.
1406  *
1407  * Since: 3.0.0
1408  */
1409 void
ags_wave_set_buffer_size(AgsWave * wave,guint buffer_size)1410 ags_wave_set_buffer_size(AgsWave *wave,
1411 			 guint buffer_size)
1412 {
1413   GList *start_list, *list;
1414 
1415   void *data;
1416 
1417   guint64 x;
1418   guint end_offset;
1419   guint buffer_length;
1420   guint new_buffer_length;
1421   guint offset;
1422   guint format;
1423   guint old_buffer_size;
1424   guint word_size;
1425   guint copy_mode;
1426   guint i;
1427 
1428   GRecMutex *wave_mutex;
1429 
1430   if(!AGS_IS_WAVE(wave)){
1431     return;
1432   }
1433 
1434   /* get wave mutex */
1435   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
1436 
1437   g_rec_mutex_lock(wave_mutex);
1438 
1439   old_buffer_size = wave->buffer_size;
1440 
1441   g_rec_mutex_unlock(wave_mutex);
1442 
1443   if(buffer_size == old_buffer_size){
1444     return;
1445   }
1446 
1447   /* apply buffer size */
1448   g_rec_mutex_lock(wave_mutex);
1449 
1450   x = ags_timestamp_get_ags_offset(wave->timestamp);
1451 
1452   format = wave->format;
1453 
1454   wave->buffer_size = buffer_size;
1455 
1456   start_list = g_list_copy(wave->buffer);
1457 
1458   g_rec_mutex_unlock(wave_mutex);
1459 
1460   /* resize buffer */
1461   data = NULL;
1462 
1463   buffer_length = g_list_length(start_list);
1464   word_size = 1;
1465 
1466   copy_mode = G_MAXUINT;
1467 
1468   switch(format){
1469   case AGS_SOUNDCARD_SIGNED_8_BIT:
1470     {
1471       data = (gint8 *) malloc(buffer_length * old_buffer_size * sizeof(gint8));
1472       memset(data, 0, buffer_length * old_buffer_size * sizeof(gint8));
1473 
1474       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_S8_TO_S8;
1475     }
1476     break;
1477   case AGS_SOUNDCARD_SIGNED_16_BIT:
1478     {
1479       data = (gint16 *) malloc(buffer_length * old_buffer_size * sizeof(gint16));
1480       memset(data, 0, buffer_length * old_buffer_size * sizeof(gint16));
1481 
1482       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_S16_TO_S16;
1483     }
1484     break;
1485   case AGS_SOUNDCARD_SIGNED_24_BIT:
1486     {
1487       data = (gint32 *) malloc(buffer_length * old_buffer_size * sizeof(gint32));
1488       memset(data, 0, buffer_length * old_buffer_size * sizeof(gint32));
1489 
1490       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_S32_TO_S32;
1491     }
1492     break;
1493   case AGS_SOUNDCARD_SIGNED_32_BIT:
1494     {
1495       data = (gint32 *) malloc(buffer_length * old_buffer_size * sizeof(gint32));
1496       memset(data, 0, buffer_length * old_buffer_size * sizeof(gint32));
1497 
1498       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_S32_TO_S32;
1499     }
1500     break;
1501   case AGS_SOUNDCARD_SIGNED_64_BIT:
1502     {
1503       data = (gint64 *) malloc(buffer_length * old_buffer_size * sizeof(gint64));
1504       memset(data, 0, buffer_length * old_buffer_size * sizeof(gint64));
1505 
1506       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_S64_TO_S64;
1507     }
1508     break;
1509   case AGS_SOUNDCARD_FLOAT:
1510     {
1511       data = (gfloat *) malloc(buffer_length * old_buffer_size * sizeof(gfloat));
1512       memset(data, 0, buffer_length * old_buffer_size * sizeof(gfloat));
1513 
1514       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_FLOAT_TO_FLOAT;
1515     }
1516     break;
1517   case AGS_SOUNDCARD_DOUBLE:
1518     {
1519       data = (gdouble *) malloc(buffer_length * old_buffer_size * sizeof(gdouble));
1520       memset(data, 0, buffer_length * old_buffer_size * sizeof(gdouble));
1521 
1522       copy_mode = AGS_AUDIO_BUFFER_UTIL_COPY_DOUBLE_TO_DOUBLE;
1523     }
1524     break;
1525   default:
1526     g_warning("ags_wave_set_buffer_size() - unsupported format");
1527   }
1528 
1529   list = start_list;
1530 
1531   offset = 0;
1532 
1533   while(list != NULL){
1534     GRecMutex *buffer_mutex;
1535 
1536     /* get buffer mutex */
1537     buffer_mutex = AGS_BUFFER_GET_OBJ_MUTEX(list->data);
1538 
1539     /*  */
1540     g_rec_mutex_lock(buffer_mutex);
1541 
1542     ags_audio_buffer_util_copy_buffer_to_buffer(data, 1, offset,
1543 						AGS_BUFFER(list->data)->data, 1, 0,
1544 						old_buffer_size, copy_mode);
1545 
1546     g_rec_mutex_unlock(buffer_mutex);
1547 
1548     /* iterate */
1549     list = list->next;
1550 
1551     offset += old_buffer_size;
1552   }
1553 
1554   new_buffer_length = (guint) ceil((buffer_length * old_buffer_size) / buffer_size);
1555 
1556   if(old_buffer_size < buffer_size){
1557     list = g_list_nth(start_list,
1558 		      new_buffer_length);
1559 
1560     for(i = 0; i < buffer_length - new_buffer_length && list != NULL; i++){
1561       ags_wave_remove_buffer(wave,
1562 			     list->data,
1563 			     FALSE);
1564 
1565       list = list->next;
1566     }
1567   }else{
1568     for(i = 0; i < new_buffer_length - buffer_length; i++){
1569       AgsBuffer *current;
1570 
1571       current = ags_buffer_new();
1572       g_object_set(current,
1573 		   "x", x + i * buffer_size,
1574 		   NULL);
1575       ags_buffer_set_buffer_size(current,
1576 				 buffer_size);
1577 
1578       ags_wave_add_buffer(wave,
1579 			  current,
1580 			  FALSE);
1581     }
1582   }
1583 
1584   g_list_free(start_list);
1585 
1586   g_object_get(wave,
1587 	       "buffer", &start_list,
1588 	       NULL);
1589 
1590   list = start_list;
1591 
1592   offset = 0;
1593   end_offset = (buffer_length * buffer_size);
1594 
1595   while(list != NULL){
1596     GRecMutex *buffer_mutex;
1597 
1598     /* get buffer mutex */
1599     buffer_mutex = AGS_BUFFER_GET_OBJ_MUTEX(list->data);
1600 
1601     /*  */
1602     g_object_set(list->data,
1603 		 "x", x + offset,
1604 		 NULL);
1605     ags_buffer_set_buffer_size(list->data,
1606 			       buffer_size);
1607 
1608     g_rec_mutex_lock(buffer_mutex);
1609 
1610     ags_audio_buffer_util_clear_buffer(AGS_BUFFER(list->data)->data, 1,
1611 				       buffer_size, ags_audio_buffer_util_format_from_soundcard(format));
1612 
1613     if(offset + buffer_size < buffer_length * buffer_size){
1614       ags_audio_buffer_util_copy_buffer_to_buffer(AGS_BUFFER(list->data)->data, 1, 0,
1615 						  data, 1, offset,
1616 						  buffer_size, copy_mode);
1617     }else{
1618       if(end_offset > offset){
1619 	ags_audio_buffer_util_copy_buffer_to_buffer(AGS_BUFFER(list->data)->data, 1, 0,
1620 						    data, 1, offset,
1621 						    end_offset - offset, copy_mode);
1622       }
1623     }
1624 
1625     g_rec_mutex_unlock(buffer_mutex);
1626 
1627     /* iterate */
1628     list = list->next;
1629 
1630     offset += buffer_size;
1631   }
1632 
1633   g_list_free_full(start_list,
1634 		   g_object_unref);
1635 
1636   if(data != NULL){
1637     free(data);
1638   }
1639 }
1640 
1641 /**
1642  * ags_wave_get_format:
1643  * @wave: the #AgsWave
1644  *
1645  * Gets format.
1646  *
1647  * Returns: the format
1648  *
1649  * Since: 3.1.0
1650  */
1651 guint
ags_wave_get_format(AgsWave * wave)1652 ags_wave_get_format(AgsWave *wave)
1653 {
1654   guint format;
1655 
1656   if(!AGS_IS_WAVE(wave)){
1657     return(0);
1658   }
1659 
1660   g_object_get(wave,
1661 	       "format", &format,
1662 	       NULL);
1663 
1664   return(format);
1665 }
1666 
1667 /**
1668  * ags_wave_set_format:
1669  * @wave: the #AgsWave
1670  * @format: the format
1671  *
1672  * Set format.
1673  *
1674  * Since: 3.0.0
1675  */
1676 void
ags_wave_set_format(AgsWave * wave,guint format)1677 ags_wave_set_format(AgsWave *wave,
1678 		    guint format)
1679 {
1680   GList *list_start, *list;
1681 
1682   GRecMutex *wave_mutex;
1683 
1684   if(!AGS_IS_WAVE(wave)){
1685     return;
1686   }
1687 
1688   /* get wave mutex */
1689   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
1690 
1691   /* apply format */
1692   g_rec_mutex_lock(wave_mutex);
1693 
1694   wave->format = format;
1695 
1696   list =
1697     list_start = g_list_copy(wave->buffer);
1698 
1699   g_rec_mutex_unlock(wave_mutex);
1700 
1701   while(list != NULL){
1702     ags_buffer_set_format(list->data,
1703 			  format);
1704 
1705     list = list->next;
1706   }
1707 
1708   g_list_free(list_start);
1709 }
1710 
1711 /**
1712  * ags_wave_get_timestamp:
1713  * @wave: the #AgsWave
1714  *
1715  * Get timestamp.
1716  *
1717  * Returns: (transfer full): the #AgsTimestamp
1718  *
1719  * Since: 3.1.0
1720  */
1721 AgsTimestamp*
ags_wave_get_timestamp(AgsWave * wave)1722 ags_wave_get_timestamp(AgsWave *wave)
1723 {
1724   AgsTimestamp *timestamp;
1725 
1726   if(!AGS_IS_WAVE(wave)){
1727     return(NULL);
1728   }
1729 
1730   g_object_get(wave,
1731 	       "timestamp", &timestamp,
1732 	       NULL);
1733 
1734   return(timestamp);
1735 }
1736 
1737 /**
1738  * ags_wave_set_timestamp:
1739  * @wave: the #AgsWave
1740  * @timestamp: the #AgsTimestamp
1741  *
1742  * Set timestamp.
1743  *
1744  * Since: 3.1.0
1745  */
1746 void
ags_wave_set_timestamp(AgsWave * wave,AgsTimestamp * timestamp)1747 ags_wave_set_timestamp(AgsWave *wave, AgsTimestamp *timestamp)
1748 {
1749   if(!AGS_IS_WAVE(wave)){
1750     return;
1751   }
1752 
1753   g_object_set(wave,
1754 	       "timestamp", timestamp,
1755 	       NULL);
1756 }
1757 
1758 /**
1759  * ags_wave_get_buffer:
1760  * @wave: the #AgsWave
1761  *
1762  * Get buffer.
1763  *
1764  * Returns: (element-type AgsAudio.Buffer) (transfer full): the #GList-struct containig #AgsBuffer
1765  *
1766  * Since: 3.1.0
1767  */
1768 GList*
ags_wave_get_buffer(AgsWave * wave)1769 ags_wave_get_buffer(AgsWave *wave)
1770 {
1771   GList *buffer;
1772 
1773   if(!AGS_IS_WAVE(wave)){
1774     return(NULL);
1775   }
1776 
1777   g_object_get(wave,
1778 	       "buffer", &buffer,
1779 	       NULL);
1780 
1781   return(buffer);
1782 }
1783 
1784 /**
1785  * ags_wave_set_buffer:
1786  * @wave: the #AgsWave
1787  * @buffer: (element-type AgsAudio.Buffer) (transfer full): the #GList-struct containing #AgsBuffer
1788  *
1789  * Set buffer by replacing existing.
1790  *
1791  * Since: 3.1.0
1792  */
1793 void
ags_wave_set_buffer(AgsWave * wave,GList * buffer)1794 ags_wave_set_buffer(AgsWave *wave, GList *buffer)
1795 {
1796   GList *start_buffer;
1797 
1798   GRecMutex *wave_mutex;
1799 
1800   if(!AGS_IS_WAVE(wave)){
1801     return;
1802   }
1803 
1804   /* get wave mutex */
1805   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
1806 
1807   g_rec_mutex_lock(wave_mutex);
1808 
1809   start_buffer = wave->buffer;
1810   wave->buffer = buffer;
1811 
1812   g_rec_mutex_unlock(wave_mutex);
1813 
1814   g_list_free_full(start_buffer,
1815 		   (GDestroyNotify) g_object_unref);
1816 }
1817 
1818 /**
1819  * ags_wave_add:
1820  * @wave: (element-type AgsAudio.Wave) (transfer none): the #GList-struct containing #AgsWave
1821  * @new_wave: the #AgsWave to add
1822  *
1823  * Add @new_wave sorted to @wave
1824  *
1825  * Returns: (element-type AgsAudio.Wave) (transfer none): the new beginning of @wave
1826  *
1827  * Since: 3.0.0
1828  */
1829 GList*
ags_wave_add(GList * wave,AgsWave * new_wave)1830 ags_wave_add(GList *wave,
1831 	     AgsWave *new_wave)
1832 {
1833 
1834   if(!AGS_IS_WAVE(new_wave)){
1835     return(wave);
1836   }
1837 
1838   wave = g_list_insert_sorted(wave,
1839 			      new_wave,
1840 			      ags_wave_sort_func);
1841 
1842   return(wave);
1843 }
1844 
1845 /**
1846  * ags_wave_add_buffer:
1847  * @wave: the #AgsWave
1848  * @buffer: the #AgsBuffer to add
1849  * @use_selection_list: if %TRUE add to selection, else to default wave
1850  *
1851  * Add @buffer to @wave.
1852  *
1853  * Since: 3.0.0
1854  */
1855 void
ags_wave_add_buffer(AgsWave * wave,AgsBuffer * buffer,gboolean use_selection_list)1856 ags_wave_add_buffer(AgsWave *wave,
1857 		    AgsBuffer *buffer,
1858 		    gboolean use_selection_list)
1859 {
1860   GRecMutex *wave_mutex;
1861 
1862   if(!AGS_IS_WAVE(wave) ||
1863      !AGS_IS_BUFFER(buffer)){
1864     return;
1865   }
1866 
1867   /* get wave mutex */
1868   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
1869 
1870   /* insert sorted */
1871   g_object_ref(buffer);
1872 
1873   g_rec_mutex_lock(wave_mutex);
1874 
1875   if(use_selection_list){
1876     wave->selection = g_list_insert_sorted(wave->selection,
1877 					   buffer,
1878 					   (GCompareFunc) ags_buffer_sort_func);
1879     ags_buffer_set_flags(buffer,
1880 			 AGS_BUFFER_IS_SELECTED);
1881   }else{
1882     wave->buffer = g_list_insert_sorted(wave->buffer,
1883 					buffer,
1884 					(GCompareFunc) ags_buffer_sort_func);
1885   }
1886 
1887   g_rec_mutex_unlock(wave_mutex);
1888 }
1889 
1890 /**
1891  * ags_wave_remove_buffer:
1892  * @wave: the #AgsWave
1893  * @buffer: the #AgsBuffer to remove
1894  * @use_selection_list: if %TRUE remove from selection, else from default wave
1895  *
1896  * Removes @buffer from @wave.
1897  *
1898  * Since: 3.0.0
1899  */
1900 void
ags_wave_remove_buffer(AgsWave * wave,AgsBuffer * buffer,gboolean use_selection_list)1901 ags_wave_remove_buffer(AgsWave *wave,
1902 		       AgsBuffer *buffer,
1903 		       gboolean use_selection_list)
1904 {
1905   GRecMutex *wave_mutex;
1906 
1907   if(!AGS_IS_WAVE(wave) ||
1908      !AGS_IS_BUFFER(buffer)){
1909     return;
1910   }
1911 
1912   /* get wave mutex */
1913   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
1914 
1915   /* remove if found */
1916   g_rec_mutex_lock(wave_mutex);
1917 
1918   if(!use_selection_list){
1919     if(g_list_find(wave->buffer,
1920 		   buffer) != NULL){
1921       wave->buffer = g_list_remove(wave->buffer,
1922 				   buffer);
1923       g_object_unref(buffer);
1924     }
1925   }else{
1926     if(g_list_find(wave->selection,
1927 		   buffer) != NULL){
1928       wave->selection = g_list_remove(wave->selection,
1929 				      buffer);
1930       g_object_unref(buffer);
1931     }
1932   }
1933 
1934   g_rec_mutex_unlock(wave_mutex);
1935 }
1936 
1937 /**
1938  * ags_wave_get_selection:
1939  * @wave: the #AgsWave
1940  *
1941  * Retrieve selection.
1942  *
1943  * Returns: (element-type AgsAudio.Buffer) (transfer none): the selection.
1944  *
1945  * Since: 3.0.0
1946  */
1947 GList*
ags_wave_get_selection(AgsWave * wave)1948 ags_wave_get_selection(AgsWave *wave)
1949 {
1950   GList *selection;
1951 
1952   GRecMutex *wave_mutex;
1953 
1954   if(!AGS_IS_WAVE(wave)){
1955     return(NULL);
1956   }
1957 
1958   /* get wave mutex */
1959   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
1960 
1961   /* selection */
1962   g_rec_mutex_lock(wave_mutex);
1963 
1964   selection = wave->selection;
1965 
1966   g_rec_mutex_unlock(wave_mutex);
1967 
1968   return(selection);
1969 }
1970 
1971 /**
1972  * ags_wave_is_buffer_selected:
1973  * @wave: the #AgsWave
1974  * @buffer: the #AgsBuffer to check for
1975  *
1976  * Check selection for buffer.
1977  *
1978  * Returns: %TRUE if selected otherwise %FALSE
1979  *
1980  * Since: 3.0.0
1981  */
1982 gboolean
ags_wave_is_buffer_selected(AgsWave * wave,AgsBuffer * buffer)1983 ags_wave_is_buffer_selected(AgsWave *wave, AgsBuffer *buffer)
1984 {
1985   GList *selection;
1986 
1987   guint64 x;
1988   guint64 current_x;
1989   gboolean retval;
1990 
1991   GRecMutex *wave_mutex;
1992 
1993   if(!AGS_IS_WAVE(wave) ||
1994      !AGS_IS_BUFFER(buffer)){
1995     return(FALSE);
1996   }
1997 
1998   /* get wave mutex */
1999   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
2000 
2001   /* get x */
2002   g_object_get(buffer,
2003 	       "x", &x,
2004 	       NULL);
2005 
2006   /* match buffer */
2007   g_rec_mutex_lock(wave_mutex);
2008 
2009   selection = wave->selection;
2010   retval = FALSE;
2011 
2012   while(selection != NULL){
2013     /* get current x */
2014     g_object_get(selection->data,
2015 		 "x", &current_x,
2016 		 NULL);
2017 
2018     if(current_x > x){
2019       break;
2020     }
2021 
2022     if(selection->data == buffer){
2023       retval = TRUE;
2024 
2025       break;
2026     }
2027 
2028     selection = selection->next;
2029   }
2030 
2031   g_rec_mutex_unlock(wave_mutex);
2032 
2033   return(retval);
2034 }
2035 
2036 /**
2037  * ags_wave_find_point:
2038  * @wave: the #AgsWave
2039  * @x: offset
2040  * @use_selection_list: if %TRUE selection is searched
2041  *
2042  * Find buffers by offset.
2043  *
2044  * Returns: (transfer none): the matching buffer as #AgsBuffer.
2045  *
2046  * Since: 3.0.0
2047  */
2048 AgsBuffer*
ags_wave_find_point(AgsWave * wave,guint64 x,gboolean use_selection_list)2049 ags_wave_find_point(AgsWave *wave,
2050 		    guint64 x,
2051 		    gboolean use_selection_list)
2052 {
2053   AgsBuffer *retval;
2054 
2055   GList *buffer;
2056   GList *current_start, *current_end, *current;
2057 
2058   guint buffer_size;
2059   guint64 current_start_x, current_end_x, current_x;
2060   guint length, position;
2061   gboolean success;
2062 
2063   GRecMutex *wave_mutex;
2064 
2065   if(!AGS_IS_WAVE(wave)){
2066     return(NULL);
2067   }
2068 
2069   /* get wave mutex */
2070   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
2071 
2072   /* find buffer */
2073   g_rec_mutex_lock(wave_mutex);
2074 
2075   buffer_size = wave->buffer_size;
2076 
2077   if(use_selection_list){
2078     buffer = wave->selection;
2079   }else{
2080     buffer = wave->buffer;
2081   }
2082 
2083   current_start = buffer;
2084   current_end = g_list_last(buffer);
2085 
2086   length = g_list_length(buffer);
2087   position = (length - 1) / 2;
2088 
2089   current = g_list_nth(current_start,
2090 		       position);
2091 
2092   retval = NULL;
2093   success = FALSE;
2094 
2095   while(!success && current != NULL){
2096     g_object_get(current_start->data,
2097 		 "x", &current_start_x,
2098 		 NULL);
2099 
2100     if(current_start_x > x){
2101       break;
2102     }
2103 
2104     if(current_start_x <= x &&
2105        current_start_x + buffer_size > x){
2106       retval = current_start->data;
2107 
2108       break;
2109     }
2110 
2111     g_object_get(current_end->data,
2112 		 "x", &current_end_x,
2113 		 NULL);
2114 
2115     if(current_end_x + buffer_size < x){
2116       break;
2117     }
2118 
2119     if(current_end_x <= x &&
2120        current_end_x + buffer_size > x){
2121       retval = current_end->data;
2122 
2123       break;
2124     }
2125 
2126     g_object_get(current->data,
2127 		 "x", &current_x,
2128 		 NULL);
2129 
2130     if(current_x <= x &&
2131        current_x + buffer_size > x){
2132       retval = current->data;
2133 
2134       break;
2135     }
2136 
2137     if(length <= 3){
2138       break;
2139     }
2140 
2141     if(current_x < x){
2142       current_start = current->next;
2143       current_end = current_end->prev;
2144     }else if(current_x > x){
2145       current_start = current_start->next;
2146       current_end = current->prev;
2147     }else{
2148       current_start = current_start->next;
2149       //NOTE:JK: we want progression
2150       //current_end = current_end->prev;
2151     }
2152 
2153     length = g_list_position(current_start,
2154 			     current_end) + 1;
2155     position = (length - 1) / 2;
2156 
2157     current = g_list_nth(current_start,
2158 			 position);
2159   }
2160 
2161   g_rec_mutex_unlock(wave_mutex);
2162 
2163   return(retval);
2164 }
2165 
2166 /**
2167  * ags_wave_find_region:
2168  * @wave: the #AgsWave
2169  * @x0: x start offset
2170  * @x1: x end offset
2171  * @use_selection_list: if %TRUE selection is searched
2172  *
2173  * Find buffers by offset and region.
2174  *
2175  * Returns: (element-type AgsAudio.Buffer) (transfer container): the matching buffers as #GList.
2176  *
2177  * Since: 3.0.0
2178  */
2179 GList*
ags_wave_find_region(AgsWave * wave,guint64 x0,guint64 x1,gboolean use_selection_list)2180 ags_wave_find_region(AgsWave *wave,
2181 		     guint64 x0,
2182 		     guint64 x1,
2183 		     gboolean use_selection_list)
2184 {
2185   GList *buffer;
2186   GList *region;
2187 
2188   guint buffer_size;
2189   guint64 current_x;
2190 
2191   GRecMutex *wave_mutex;
2192 
2193   if(!AGS_IS_WAVE(wave)){
2194     return(NULL);
2195   }
2196 
2197   /* get wave mutex */
2198   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
2199 
2200   if(x0 > x1){
2201     guint tmp;
2202 
2203     tmp = x1;
2204     x1 = x0;
2205     x0 = x1;
2206   }
2207 
2208   /* find buffer */
2209   g_rec_mutex_lock(wave_mutex);
2210 
2211   if(use_selection_list){
2212     buffer = wave->selection;
2213   }else{
2214     buffer = wave->buffer;
2215   }
2216 
2217   while(buffer != NULL){
2218     g_object_get(buffer->data,
2219 		 "buffer-size", &buffer_size,
2220 		 "x", &current_x,
2221 		 NULL);
2222 
2223     if(current_x + buffer_size > x0){
2224       break;
2225     }
2226 
2227     buffer = buffer->next;
2228   }
2229 
2230   region = NULL;
2231 
2232   while(buffer != NULL){
2233     g_object_get(buffer->data,
2234 		 "x", &current_x,
2235 		 NULL);
2236 
2237     if(current_x > x1){
2238       break;
2239     }
2240 
2241     region = g_list_prepend(region,
2242 			    buffer->data);
2243 
2244     buffer = buffer->next;
2245   }
2246 
2247   g_rec_mutex_unlock(wave_mutex);
2248 
2249   region = g_list_reverse(region);
2250 
2251   return(region);
2252 }
2253 
2254 /**
2255  * ags_wave_free_selection:
2256  * @wave: the #AgsWave
2257  *
2258  * Clear selection.
2259  *
2260  * Since: 3.0.0
2261  */
2262 void
ags_wave_free_selection(AgsWave * wave)2263 ags_wave_free_selection(AgsWave *wave)
2264 {
2265   AgsBuffer *buffer;
2266 
2267   GList *list_start, *list;
2268 
2269   GRecMutex *wave_mutex;
2270 
2271   if(!AGS_IS_WAVE(wave)){
2272     return;
2273   }
2274 
2275   /* get wave mutex */
2276   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
2277 
2278   /* free selection */
2279   g_rec_mutex_lock(wave_mutex);
2280 
2281   list =
2282     list_start = wave->selection;
2283 
2284   while(list != NULL){
2285     ags_buffer_unset_flags(list->data,
2286 			   AGS_BUFFER_IS_SELECTED);
2287 
2288     list = list->next;
2289   }
2290 
2291   wave->selection = NULL;
2292 
2293   g_rec_mutex_unlock(wave_mutex);
2294 
2295   g_list_free_full(list_start,
2296 		   g_object_unref);
2297 }
2298 
2299 /**
2300  * ags_wave_add_region_to_selection:
2301  * @wave: the #AgsWave
2302  * @x0: x start offset
2303  * @x1: x end offset
2304  * @replace_current_selection: if %TRUE selection is replaced
2305  *
2306  * Add buffer within region to selection.
2307  *
2308  * Since: 3.0.0
2309  */
2310 void
ags_wave_add_region_to_selection(AgsWave * wave,guint64 x0,guint64 x1,gboolean replace_current_selection)2311 ags_wave_add_region_to_selection(AgsWave *wave,
2312 				 guint64 x0, guint64 x1,
2313 				 gboolean replace_current_selection)
2314 {
2315   AgsBuffer *buffer;
2316 
2317   GList *region, *list;
2318 
2319   GRecMutex *wave_mutex;
2320 
2321   if(!AGS_IS_WAVE(wave)){
2322     return;
2323   }
2324 
2325   /* get wave mutex */
2326   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
2327 
2328   /* find region */
2329   region = ags_wave_find_region(wave,
2330 				x0,
2331 				x1,
2332 				FALSE);
2333 
2334   if(replace_current_selection){
2335     ags_wave_free_selection(wave);
2336 
2337     list = region;
2338 
2339     while(list != NULL){
2340       guint buffer_size;
2341       guint64 current_x;
2342       guint64 selection_x0, selection_x1;
2343 
2344       g_object_get(list->data,
2345 		   "buffer-size", &buffer_size,
2346 		   "x", &current_x,
2347 		   NULL);
2348 
2349       if(current_x + buffer_size > x0){
2350 	selection_x0 = current_x;
2351       }else{
2352 	selection_x0 = x0;
2353       }
2354 
2355       if(current_x + buffer_size < x1){
2356 	selection_x1 = current_x + buffer_size;
2357       }else{
2358 	selection_x1 = current_x + ((current_x + buffer_size) - x1);
2359       }
2360 
2361       ags_buffer_set_flags(list->data,
2362 			   AGS_BUFFER_IS_SELECTED);
2363       g_object_ref(list->data);
2364 
2365       g_object_set(list->data,
2366 		   "selection-x0", selection_x0,
2367 		   "selection-x1", selection_x1,
2368 		   NULL);
2369 
2370       list = list->next;
2371     }
2372 
2373     /* replace */
2374     g_rec_mutex_lock(wave_mutex);
2375 
2376     wave->selection = region;
2377 
2378     g_rec_mutex_unlock(wave_mutex);
2379   }else{
2380     list = region;
2381 
2382     while(list != NULL){
2383       guint buffer_size;
2384       guint64 current_x;
2385       guint64 selection_x0, selection_x1;
2386 
2387       g_object_get(list->data,
2388 		   "buffer-size", &buffer_size,
2389 		   "x", &current_x,
2390 		   NULL);
2391 
2392       if(current_x + buffer_size > x0){
2393 	selection_x0 = current_x;
2394       }else{
2395 	selection_x0 = x0;
2396       }
2397 
2398       if(current_x + buffer_size < x1){
2399 	selection_x1 = current_x + buffer_size;
2400       }else{
2401 	selection_x1 = current_x + ((current_x + buffer_size) - x1);
2402       }
2403 
2404       if(!ags_wave_is_buffer_selected(wave, list->data)){
2405 	/* add */
2406 	ags_wave_add_buffer(wave,
2407 			    list->data,
2408 			    TRUE);
2409 
2410 	g_object_set(list->data,
2411 		     "selection-x0", selection_x0,
2412 		     "selection-x1", selection_x1,
2413 		     NULL);
2414       }else{
2415 	guint64 current_selection_x0, current_selection_x1;
2416 
2417 	g_object_get(list->data,
2418 		     "selection-x0", &current_selection_x0,
2419 		     "selection-x1", &current_selection_x1,
2420 		     NULL);
2421 
2422 	if(selection_x0 < current_selection_x0){
2423 	  g_object_set(list->data,
2424 		       "selection-x0", selection_x0,
2425 		       NULL);
2426 	}
2427 
2428 	if(selection_x1 > current_selection_x1){
2429 	  g_object_set(list->data,
2430 		       "selection-x1", selection_x1,
2431 		       NULL);
2432 	}
2433       }
2434 
2435       list = list->next;
2436     }
2437 
2438     g_list_free(region);
2439   }
2440 }
2441 
2442 /**
2443  * ags_wave_remove_region_from_selection:
2444  * @wave: the #AgsWave
2445  * @x0: x start offset
2446  * @x1: x end offset
2447  *
2448  * Remove buffers within region of selection.
2449  *
2450  * Since: 3.0.0
2451  */
2452 void
ags_wave_remove_region_from_selection(AgsWave * wave,guint64 x0,guint64 x1)2453 ags_wave_remove_region_from_selection(AgsWave *wave,
2454 				      guint64 x0, guint64 x1)
2455 {
2456   AgsBuffer *buffer;
2457 
2458   GList *region;
2459   GList *list;
2460 
2461   GRecMutex *wave_mutex;
2462 
2463   if(!AGS_IS_WAVE(wave)){
2464     return;
2465   }
2466 
2467   /* get wave mutex */
2468   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
2469 
2470   /* find region */
2471   region = ags_wave_find_region(wave,
2472 				x0,
2473 				x1,
2474 				TRUE);
2475 
2476   list = region;
2477 
2478   while(list != NULL){
2479     ags_buffer_unset_flags(list->data,
2480 			   AGS_BUFFER_IS_SELECTED);
2481 
2482     /* remove */
2483     g_rec_mutex_lock(wave_mutex);
2484 
2485     wave->selection = g_list_remove(wave->selection,
2486 				    list->data);
2487 
2488     g_rec_mutex_unlock(wave_mutex);
2489 
2490     g_object_unref(list->data);
2491 
2492     /* iterate */
2493     list = list->next;
2494   }
2495 
2496   g_list_free(region);
2497 }
2498 
2499 /**
2500  * ags_wave_add_all_to_selection:
2501  * @wave: the #AgsWave
2502  *
2503  * Select all buffer to selection.
2504  *
2505  * Since: 3.0.0
2506  */
2507 void
ags_wave_add_all_to_selection(AgsWave * wave)2508 ags_wave_add_all_to_selection(AgsWave *wave)
2509 {
2510   GList *list;
2511 
2512   GRecMutex *wave_mutex;
2513 
2514   if(!AGS_IS_WAVE(wave)){
2515     return;
2516   }
2517 
2518   /* get wave mutex */
2519   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
2520 
2521   /* select all */
2522   g_rec_mutex_lock(wave_mutex);
2523 
2524   list = wave->buffer;
2525 
2526   while(list != NULL){
2527     guint buffer_size;
2528     guint64 current_x;
2529 
2530     g_object_get(list->data,
2531 		 "buffer-size", &buffer_size,
2532 		 "x", &current_x,
2533 		 NULL);
2534 
2535     ags_wave_add_buffer(wave,
2536 			list->data, TRUE);
2537     g_object_set(list->data,
2538 		 "selection-x0", current_x,
2539 		 "selection-x1", current_x + buffer_size,
2540 		 NULL);
2541 
2542     list = list->next;
2543   }
2544 
2545   g_rec_mutex_unlock(wave_mutex);
2546 }
2547 
2548 /**
2549  * ags_wave_copy_selection:
2550  * @wave: the #AgsWave
2551  *
2552  * Copy selection to clipboard.
2553  *
2554  * Returns: (transfer none): the selection as XML.
2555  *
2556  * Since: 3.0.0
2557  */
2558 xmlNode*
ags_wave_copy_selection(AgsWave * wave)2559 ags_wave_copy_selection(AgsWave *wave)
2560 {
2561   AgsBuffer *buffer;
2562 
2563   AgsTimestamp *timestamp;
2564 
2565   xmlNode *wave_node, *current_buffer;
2566   xmlNode *timestamp_node;
2567 
2568   GList *start_selection, *selection;
2569 
2570   xmlChar *str;
2571 
2572   guint format;
2573   guint64 x_boundary;
2574 
2575   GRecMutex *wave_mutex;
2576 
2577   if(!AGS_IS_WAVE(wave)){
2578     return(NULL);
2579   }
2580 
2581   /* get wave mutex */
2582   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
2583 
2584   /* create root node */
2585   wave_node = xmlNewNode(NULL,
2586 			 BAD_CAST "wave");
2587 
2588   xmlNewProp(wave_node,
2589 	     BAD_CAST "program",
2590 	     BAD_CAST "ags");
2591   xmlNewProp(wave_node,
2592 	     BAD_CAST "type",
2593 	     BAD_CAST (AGS_WAVE_CLIPBOARD_TYPE));
2594   xmlNewProp(wave_node,
2595 	     BAD_CAST "version",
2596 	     BAD_CAST (AGS_WAVE_CLIPBOARD_VERSION));
2597   xmlNewProp(wave_node,
2598 	     BAD_CAST "format",
2599 	     BAD_CAST (AGS_WAVE_CLIPBOARD_FORMAT));
2600   xmlNewProp(wave_node,
2601 	     BAD_CAST "line",
2602 	     BAD_CAST (g_strdup_printf("%u", wave->line)));
2603 
2604   /* buffer format */
2605   g_object_get(wave,
2606 	       "format", &format,
2607 	       NULL);
2608 
2609   str = NULL;
2610 
2611   switch(format){
2612   case AGS_SOUNDCARD_SIGNED_8_BIT:
2613     {
2614       str = "s8";
2615     }
2616     break;
2617   case AGS_SOUNDCARD_SIGNED_16_BIT:
2618     {
2619       str = "s16";
2620     }
2621     break;
2622   case AGS_SOUNDCARD_SIGNED_24_BIT:
2623     {
2624       str = "s24";
2625     }
2626     break;
2627   case AGS_SOUNDCARD_SIGNED_32_BIT:
2628     {
2629       str = "s32";
2630     }
2631     break;
2632   case AGS_SOUNDCARD_SIGNED_64_BIT:
2633     {
2634       str = "s64";
2635     }
2636     break;
2637   case AGS_SOUNDCARD_FLOAT:
2638     {
2639       str = "float";
2640     }
2641     break;
2642   case AGS_SOUNDCARD_DOUBLE:
2643     {
2644       str = "double";
2645     }
2646     break;
2647   }
2648 
2649   xmlNewProp(wave_node,
2650 	     BAD_CAST "buffer-format",
2651 	     BAD_CAST (str));
2652 
2653   /* timestamp */
2654   g_object_get(wave,
2655 	       "timestamp", &timestamp,
2656 	       NULL);
2657 
2658   if(timestamp != NULL){
2659     timestamp_node = xmlNewNode(NULL,
2660 				BAD_CAST "timestamp");
2661     xmlAddChild(wave_node,
2662 		timestamp_node);
2663 
2664     xmlNewProp(timestamp_node,
2665 	       BAD_CAST "offset",
2666 	       BAD_CAST (g_strdup_printf("%lu", ags_timestamp_get_ags_offset(timestamp))));
2667 
2668     g_object_unref(timestamp);
2669   }
2670 
2671   /* selection */
2672   g_rec_mutex_lock(wave_mutex);
2673 
2674   selection =
2675     start_selection = g_list_copy(wave->selection);
2676 
2677   g_rec_mutex_unlock(wave_mutex);
2678 
2679   if(selection != NULL){
2680     g_object_get(selection->data,
2681 		 "selection-x0", &x_boundary,
2682 		 NULL);
2683     x_boundary = AGS_BUFFER(selection->data)->selection_x0;
2684   }else{
2685     x_boundary = 0;
2686   }
2687 
2688   while(selection != NULL){
2689     xmlChar *content;
2690     guchar *cbuffer;
2691 
2692     guint buffer_size;
2693 
2694     GRecMutex *buffer_mutex;
2695 
2696     buffer = AGS_BUFFER(selection->data);
2697 
2698     buffer_mutex = AGS_BUFFER_GET_OBJ_MUTEX(buffer);
2699 
2700     current_buffer = xmlNewChild(wave_node,
2701 				 NULL,
2702 				 BAD_CAST "buffer",
2703 				 NULL);
2704 
2705     g_rec_mutex_lock(buffer_mutex);
2706 
2707     xmlNewProp(current_buffer,
2708 	       BAD_CAST "samplerate",
2709 	       BAD_CAST (g_strdup_printf("%u", buffer->samplerate)));
2710 
2711     xmlNewProp(current_buffer,
2712 	       BAD_CAST "buffer-size",
2713 	       BAD_CAST (g_strdup_printf("%u", buffer->buffer_size)));
2714 
2715     switch(buffer->format){
2716     case AGS_SOUNDCARD_SIGNED_8_BIT:
2717       {
2718 	str = "s8";
2719       }
2720       break;
2721     case AGS_SOUNDCARD_SIGNED_16_BIT:
2722       {
2723 	str = "s16";
2724       }
2725       break;
2726     case AGS_SOUNDCARD_SIGNED_24_BIT:
2727       {
2728 	str = "s24";
2729       }
2730       break;
2731     case AGS_SOUNDCARD_SIGNED_32_BIT:
2732       {
2733 	str = "s32";
2734       }
2735       break;
2736     case AGS_SOUNDCARD_SIGNED_64_BIT:
2737       {
2738 	str = "s64";
2739       }
2740       break;
2741     case AGS_SOUNDCARD_FLOAT:
2742       {
2743 	str = "float";
2744       }
2745       break;
2746     case AGS_SOUNDCARD_DOUBLE:
2747       {
2748 	str = "double";
2749       }
2750       break;
2751     }
2752 
2753     xmlNewProp(current_buffer,
2754 	       BAD_CAST "format",
2755 	       BAD_CAST (str));
2756 
2757     //    g_message("copy - buffer->x = %lu", buffer->x);
2758 
2759     xmlNewProp(current_buffer,
2760 	       BAD_CAST "x",
2761 	       BAD_CAST (g_strdup_printf("%lu", buffer->x)));
2762 
2763     xmlNewProp(current_buffer,
2764 	       BAD_CAST "selection-x0",
2765 	       BAD_CAST (g_strdup_printf("%lu", buffer->selection_x0)));
2766 
2767     xmlNewProp(current_buffer,
2768 	       BAD_CAST "selection-x1",
2769 	       BAD_CAST (g_strdup_printf("%lu", buffer->selection_x1)));
2770 
2771     cbuffer = NULL;
2772     buffer_size = 0;
2773 
2774     switch(buffer->format){
2775     case AGS_SOUNDCARD_SIGNED_8_BIT:
2776       {
2777 	cbuffer = ags_buffer_util_s8_to_char_buffer((gint8 *) buffer->data,
2778 						    buffer->buffer_size);
2779 	buffer_size = buffer->buffer_size * sizeof(guchar);
2780       }
2781       break;
2782     case AGS_SOUNDCARD_SIGNED_16_BIT:
2783       {
2784 	cbuffer = ags_buffer_util_s16_to_char_buffer((gint16 *) buffer->data,
2785 						     buffer->buffer_size);
2786 	buffer_size = 2 * buffer->buffer_size * sizeof(guchar);
2787       }
2788       break;
2789     case AGS_SOUNDCARD_SIGNED_24_BIT:
2790       {
2791 	cbuffer = ags_buffer_util_s24_to_char_buffer((gint32 *) buffer->data,
2792 						     buffer->buffer_size);
2793 	buffer_size = 4 * buffer->buffer_size * sizeof(guchar);
2794       }
2795       break;
2796     case AGS_SOUNDCARD_SIGNED_32_BIT:
2797       {
2798 	cbuffer = ags_buffer_util_s32_to_char_buffer((gint32 *) buffer->data,
2799 						     buffer->buffer_size);
2800 	buffer_size = 4 * buffer->buffer_size * sizeof(guchar);
2801       }
2802       break;
2803     case AGS_SOUNDCARD_SIGNED_64_BIT:
2804       {
2805 	cbuffer = ags_buffer_util_s64_to_char_buffer((gint64 *) buffer->data,
2806 						     buffer->buffer_size);
2807 	buffer_size = 8 * buffer->buffer_size * sizeof(guchar);
2808       }
2809       break;
2810     }
2811 
2812     g_rec_mutex_unlock(buffer_mutex);
2813 
2814     //    current_buffer->content = g_base64_encode(cbuffer,
2815     //					      buffer_size);
2816     xmlNodeSetContent(current_buffer,
2817 		      g_base64_encode(cbuffer,
2818     				      buffer_size));
2819 
2820     g_free(cbuffer);
2821 
2822     selection = selection->next;
2823   }
2824 
2825   g_list_free(start_selection);
2826 
2827   xmlNewProp(wave_node,
2828 	     BAD_CAST "x-boundary",
2829 	     BAD_CAST (g_strdup_printf("%lu", x_boundary)));
2830 
2831   return(wave_node);
2832 }
2833 
2834 /**
2835  * ags_wave_cut_selection:
2836  * @wave: the #AgsWave
2837  *
2838  * Cut selection to clipboard.
2839  *
2840  * Returns: (transfer none): the selection as xmlNode
2841  *
2842  * Since: 3.0.0
2843  */
2844 xmlNode*
ags_wave_cut_selection(AgsWave * wave)2845 ags_wave_cut_selection(AgsWave *wave)
2846 {
2847   xmlNode *wave_node;
2848 
2849   GList *selection, *buffer;
2850 
2851   GRecMutex *wave_mutex;
2852 
2853   if(!AGS_IS_WAVE(wave)){
2854     return(NULL);
2855   }
2856 
2857   /* get wave mutex */
2858   wave_mutex = AGS_WAVE_GET_OBJ_MUTEX(wave);
2859 
2860   /* copy selection */
2861   wave_node = ags_wave_copy_selection(wave);
2862 
2863   /* cut */
2864   g_rec_mutex_lock(wave_mutex);
2865 
2866   selection = wave->selection;
2867 
2868   while(selection != NULL){
2869     wave->buffer = g_list_remove(wave->buffer,
2870 				 selection->data);
2871     g_object_unref(selection->data);
2872 
2873     selection = selection->next;
2874   }
2875 
2876   g_rec_mutex_unlock(wave_mutex);
2877 
2878   /* free selection */
2879   ags_wave_free_selection(wave);
2880 
2881   return(wave_node);
2882 }
2883 
2884 void
ags_wave_insert_native_level_from_clipboard_version_1_4_0(AgsWave * wave,xmlNode * root_node,char * version,char * x_boundary,gboolean reset_x_offset,guint64 x_offset,gdouble delay,guint attack,gboolean match_line,gboolean do_replace,guint current_line,guint64 relative_offset,guint wave_samplerate,guint wave_buffer_size,guint wave_format,gboolean match_timestamp)2885 ags_wave_insert_native_level_from_clipboard_version_1_4_0(AgsWave *wave,
2886 							  xmlNode *root_node, char *version,
2887 							  char *x_boundary,
2888 							  gboolean reset_x_offset, guint64 x_offset,
2889 							  gdouble delay, guint attack,
2890 							  gboolean match_line, gboolean do_replace,
2891 							  guint current_line,
2892 							  guint64 relative_offset,
2893 							  guint wave_samplerate,
2894 							  guint wave_buffer_size,
2895 							  guint wave_format,
2896 							  gboolean match_timestamp)
2897 {
2898   AgsBuffer *buffer;
2899 
2900   AgsTimestamp *timestamp;
2901 
2902   xmlNode *node;
2903 
2904   void *clipboard_data;
2905   unsigned char *clipboard_cdata;
2906 
2907   xmlChar *samplerate;
2908   xmlChar *buffer_size;
2909   xmlChar *format;
2910   xmlChar *x;
2911   xmlChar *selection_x0, *selection_x1;
2912   xmlChar *content;
2913   gchar *offset;
2914   char *endptr;
2915 
2916   guint64 timestamp_offset;
2917   guint samplerate_val;
2918   guint buffer_size_val;
2919   guint format_val;
2920   guint64 x_boundary_val;
2921   guint64 x_val;
2922   guint64 base_x_difference;
2923   guint64 selection_x0_val, selection_x1_val;
2924   guint target_frame_count, frame_count;
2925   guint word_size;
2926   gsize clipboard_length;
2927   gboolean subtract_x;
2928 
2929   node = root_node->children;
2930 
2931   /* retrieve x values for resetting */
2932   base_x_difference = 0;
2933   subtract_x = FALSE;
2934 
2935   x_boundary_val = 0;
2936 
2937   if(reset_x_offset){
2938     if(x_boundary != NULL){
2939       errno = 0;
2940 
2941       x_boundary_val = strtoul(x_boundary,
2942 			       &endptr,
2943 			       10);
2944 
2945       if(errno == ERANGE){
2946 	goto dont_reset_x_offset;
2947       }
2948 
2949       if(x_boundary == endptr){
2950 	goto dont_reset_x_offset;
2951       }
2952 
2953       if(x_boundary_val < x_offset){
2954 	base_x_difference = x_offset - x_boundary_val;
2955 	subtract_x = FALSE;
2956       }else{
2957 	base_x_difference = x_boundary_val - x_offset;
2958 	subtract_x = TRUE;
2959       }
2960     }else{
2961     dont_reset_x_offset:
2962       reset_x_offset = FALSE;
2963     }
2964   }
2965 
2966   /* parse */
2967   while(node != NULL){
2968     if(node->type == XML_ELEMENT_NODE){
2969       if(!xmlStrncmp("buffer",
2970 		     node->name,
2971 		     7)){
2972 	void *target_data;
2973 
2974 	samplerate_val = 0;
2975 	samplerate = xmlGetProp(node,
2976 				"samplerate");
2977 
2978 	if(samplerate != NULL){
2979 	  samplerate_val = g_ascii_strtoull(samplerate,
2980 					    NULL,
2981 					    10);
2982 	}
2983 
2984 	buffer_size_val = 0;
2985 	buffer_size = xmlGetProp(node,
2986 				 "buffer-size");
2987 
2988 	if(buffer_size != NULL){
2989 	  buffer_size_val = g_ascii_strtoull(buffer_size,
2990 					     NULL,
2991 					     10);
2992 	}
2993 
2994 	/* retrieve format */
2995 	format = xmlGetProp(node,
2996 			    "format");
2997 
2998 	if(!g_ascii_strncasecmp("s8",
2999 				format,
3000 				3)){
3001 	  format_val = AGS_SOUNDCARD_SIGNED_8_BIT;
3002 	}else if(!g_ascii_strncasecmp("s16",
3003 				      format,
3004 				      4)){
3005 	  format_val = AGS_SOUNDCARD_SIGNED_16_BIT;
3006 	}else if(!g_ascii_strncasecmp("s24",
3007 				      format,
3008 				      4)){
3009 	  format_val = AGS_SOUNDCARD_SIGNED_24_BIT;
3010 	}else if(!g_ascii_strncasecmp("s32",
3011 				      format,
3012 				      4)){
3013 	  format_val = AGS_SOUNDCARD_SIGNED_32_BIT;
3014 	}else if(!g_ascii_strncasecmp("s64",
3015 				      format,
3016 				      4)){
3017 	  format_val = AGS_SOUNDCARD_SIGNED_64_BIT;
3018 	}else if(!g_ascii_strncasecmp("float",
3019 				      format,
3020 				      4)){
3021 	  format_val = AGS_SOUNDCARD_FLOAT;
3022 	}else if(!g_ascii_strncasecmp("double",
3023 				      format,
3024 				      4)){
3025 	  format_val = AGS_SOUNDCARD_DOUBLE;
3026 	}else{
3027 	  node = node->next;
3028 
3029 	  continue;
3030 	}
3031 
3032 	/* retrieve x offset */
3033 	x = xmlGetProp(node,
3034 		       "x");
3035 
3036 	if(x == NULL){
3037 	  node = node->next;
3038 
3039 	  continue;
3040 	}
3041 
3042 	errno = 0;
3043 	x_val = g_ascii_strtoull(x,
3044 				 &endptr,
3045 				 10);
3046 
3047 	if(errno == ERANGE){
3048 	  node = node->next;
3049 
3050 	  continue;
3051 	}
3052 
3053 	if(x == endptr){
3054 	  node = node->next;
3055 
3056 	  continue;
3057 	}
3058 
3059 	/* calculate new offset */
3060 	if(reset_x_offset){
3061 	  errno = 0;
3062 
3063 	  if(subtract_x){
3064 	    x_val -= base_x_difference;
3065 
3066 	    if(errno != 0){
3067 	      node = node->next;
3068 
3069 	      continue;
3070 	    }
3071 	  }else{
3072 	    x_val += base_x_difference;
3073 
3074 	    if(errno != 0){
3075 	      node = node->next;
3076 
3077 	      continue;
3078 	    }
3079 	  }
3080 	}
3081 
3082 	/* selection x0 and x1 */
3083 	selection_x0_val = 0;
3084 	selection_x1_val = wave_buffer_size;
3085 
3086 	selection_x0 = xmlGetProp(node,
3087 				  "selection-x0");
3088 
3089 	if(selection_x0 != NULL){
3090 	  guint64 tmp;
3091 
3092 	  endptr = NULL;
3093 	  errno = 0;
3094 	  tmp = g_ascii_strtoull(selection_x0,
3095 				 &endptr,
3096 				 10);
3097 
3098 	  if(errno != ERANGE &&
3099 	     endptr != selection_x0 &&
3100 	     tmp < wave_buffer_size){
3101 	    selection_x0_val = tmp;
3102 	  }
3103 	}
3104 
3105 	selection_x1 = xmlGetProp(node,
3106 				  "selection-x1");
3107 
3108 	if(selection_x1 != NULL){
3109 	  guint64 tmp;
3110 
3111 	  endptr = NULL;
3112 	  errno = 0;
3113 	  tmp = g_ascii_strtoull(selection_x1,
3114 				 &endptr,
3115 				 10);
3116 
3117 	  if(errno != ERANGE &&
3118 	     endptr != selection_x1 &&
3119 	     selection_x0_val <= tmp &&
3120 	     tmp <= wave_buffer_size){
3121 	    selection_x1_val = tmp;
3122 	  }
3123 	}
3124 
3125 	frame_count = selection_x1_val - selection_x0_val;
3126 
3127 	if(frame_count == 0){
3128 	  node = node->next;
3129 
3130 	  continue;
3131 	}
3132 
3133 	content = xmlNodeGetContent(node);
3134 	//content = node->content;
3135 
3136 	if(content == NULL){
3137 	  node = node->next;
3138 
3139 	  continue;
3140 	}
3141 
3142 	clipboard_cdata = g_base64_decode(content,
3143 					  &clipboard_length);
3144 
3145 	switch(format_val){
3146 	case AGS_SOUNDCARD_SIGNED_8_BIT:
3147 	{
3148 	  word_size = 1;
3149 
3150 	  clipboard_data = ags_buffer_util_char_buffer_to_s8(clipboard_cdata,
3151 							     clipboard_length);
3152 	}
3153 	break;
3154 	case AGS_SOUNDCARD_SIGNED_16_BIT:
3155 	{
3156 	  word_size = 2;
3157 
3158 	  clipboard_data = ags_buffer_util_char_buffer_to_s16(clipboard_cdata,
3159 							      clipboard_length);
3160 	}
3161 	break;
3162 	case AGS_SOUNDCARD_SIGNED_24_BIT:
3163 	{
3164 	  word_size = 4;
3165 
3166 	  clipboard_data = ags_buffer_util_char_buffer_to_s32(clipboard_cdata,
3167 							      clipboard_length);
3168 	}
3169 	break;
3170 	case AGS_SOUNDCARD_SIGNED_32_BIT:
3171 	{
3172 	  word_size = 4;
3173 
3174 	  clipboard_data = ags_buffer_util_char_buffer_to_s32(clipboard_cdata,
3175 							      clipboard_length);
3176 	}
3177 	break;
3178 	case AGS_SOUNDCARD_SIGNED_64_BIT:
3179 	{
3180 	  word_size = 8;
3181 
3182 	  clipboard_data = ags_buffer_util_char_buffer_to_s64(clipboard_cdata,
3183 							      clipboard_length);
3184 	}
3185 	break;
3186 	case AGS_SOUNDCARD_FLOAT:
3187 	{
3188 	  word_size = sizeof(gfloat);
3189 
3190 	  clipboard_data = ags_buffer_util_char_buffer_to_float(clipboard_cdata,
3191 								clipboard_length);
3192 	}
3193 	break;
3194 	case AGS_SOUNDCARD_DOUBLE:
3195 	{
3196 	  word_size = sizeof(gdouble);
3197 
3198 	  clipboard_data = ags_buffer_util_char_buffer_to_double(clipboard_cdata,
3199 								 clipboard_length);
3200 	}
3201 	break;
3202 	default:
3203 	  node = node->next;
3204 
3205 	  continue;
3206 	}
3207 
3208 	if(clipboard_length % word_size != 0 ||
3209 	   clipboard_length / word_size != frame_count){
3210 	  g_warning("malformed clipboard");
3211 
3212 	  node = node->next;
3213 
3214 	  continue;
3215 	}
3216 
3217 	/* add buffer */
3218 	g_object_get(wave,
3219 		     "timestamp", &timestamp,
3220 		     NULL);
3221 
3222 	timestamp_offset = ags_timestamp_get_ags_offset(timestamp);
3223 	g_object_unref(timestamp);
3224 
3225 	if(!match_timestamp ||
3226 	   x_val < timestamp_offset + relative_offset){
3227 	  guint copy_mode;
3228 
3229 	  /* find first */
3230 	  buffer = ags_wave_find_point(wave,
3231 				       wave_buffer_size * floor(x_val / wave_buffer_size),
3232 				       FALSE);
3233 
3234 	  if(buffer != NULL &&
3235 	     do_replace){
3236 	    void *data;
3237 
3238 	    //	      g_message("found %d", x_val);
3239 
3240 	    data = buffer->data;
3241 
3242 	    if(attack != 0){
3243 	      switch(wave_format){
3244 	      case AGS_SOUNDCARD_SIGNED_8_BIT:
3245 	      {
3246 		data = ((gint8 *) data) + attack;
3247 	      }
3248 	      break;
3249 	      case AGS_SOUNDCARD_SIGNED_16_BIT:
3250 	      {
3251 		data = ((gint16 *) data) + attack;
3252 	      }
3253 	      break;
3254 	      case AGS_SOUNDCARD_SIGNED_24_BIT:
3255 	      {
3256 		data = ((gint32 *) data) + attack;
3257 	      }
3258 	      break;
3259 	      case AGS_SOUNDCARD_SIGNED_32_BIT:
3260 	      {
3261 		data = ((gint32 *) data) + attack;
3262 	      }
3263 	      break;
3264 	      case AGS_SOUNDCARD_SIGNED_64_BIT:
3265 	      {
3266 		data = ((gint64 *) data) + attack;
3267 	      }
3268 	      break;
3269 	      case AGS_SOUNDCARD_FLOAT:
3270 	      {
3271 		data = ((gfloat *) data) + attack;
3272 	      }
3273 	      break;
3274 	      case AGS_SOUNDCARD_DOUBLE:
3275 	      {
3276 		data = ((gdouble *) data) + attack;
3277 	      }
3278 	      break;
3279 	      default:
3280 		g_warning("unknown soundcard format");
3281 
3282 		node = node->next;
3283 
3284 		continue;
3285 	      }
3286 	    }
3287 
3288 	    if(attack + frame_count <= wave_buffer_size){
3289 	      if(wave_format == AGS_SOUNDCARD_DOUBLE){
3290 		ags_audio_buffer_util_clear_double(data, 1,
3291 						   frame_count);
3292 	      }else if(wave_format == AGS_SOUNDCARD_FLOAT){
3293 		ags_audio_buffer_util_clear_float(data, 1,
3294 						  frame_count);
3295 	      }else{
3296 		ags_audio_buffer_util_clear_buffer(data, 1,
3297 						   frame_count, ags_audio_buffer_util_format_from_soundcard(wave_format));
3298 	      }
3299 	    }else{
3300 	      if(wave_format == AGS_SOUNDCARD_DOUBLE){
3301 		ags_audio_buffer_util_clear_double(data, 1,
3302 						   wave_buffer_size);
3303 	      }else if(wave_format == AGS_SOUNDCARD_FLOAT){
3304 		ags_audio_buffer_util_clear_float(data, 1,
3305 						  wave_buffer_size);
3306 	      }else{
3307 		ags_audio_buffer_util_clear_buffer(data, 1,
3308 						   wave_buffer_size - attack, ags_audio_buffer_util_format_from_soundcard(wave_format));
3309 	      }
3310 	    }
3311 	  }
3312 
3313 	  if(buffer == NULL){
3314 	    buffer = ags_buffer_new();
3315 	    g_object_set(buffer,
3316 			 "samplerate", wave_samplerate,
3317 			 "buffer-size", wave_buffer_size,
3318 			 "format", wave_format,
3319 			 NULL);
3320 
3321 	    buffer->x = x_val;
3322 
3323 	    //	      g_message("created %d", x_val);
3324 
3325 	    ags_wave_add_buffer(wave,
3326 				buffer,
3327 				FALSE);
3328 	  }
3329 
3330 	  //	    g_message("insert - buffer->x = %lu", buffer->x);
3331 	  //	    g_message("%d %d", wave_format, format_val);
3332 	  copy_mode = ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(wave_format),
3333 							  ags_audio_buffer_util_format_from_soundcard(format_val));
3334 
3335 	  if(samplerate_val != wave_samplerate){
3336 	    target_frame_count = ceil((double) frame_count / (double) samplerate_val * (double) wave_samplerate);
3337 
3338 	    target_data = ags_stream_alloc(target_frame_count,
3339 					   format_val);
3340 
3341 	    ags_audio_buffer_util_resample_with_buffer(clipboard_data, 1,
3342 						       ags_audio_buffer_util_format_from_soundcard(format_val), samplerate_val,
3343 						       buffer_size_val,
3344 						       wave_samplerate,
3345 						       target_frame_count,
3346 						       target_data);
3347 
3348 	    if(attack + target_frame_count <= wave_buffer_size){
3349 	      ags_audio_buffer_util_copy_buffer_to_buffer(buffer->data, 1, attack,
3350 							  target_data, 1, 0,
3351 							  target_frame_count, copy_mode);
3352 	    }else{
3353 	      ags_audio_buffer_util_copy_buffer_to_buffer(buffer->data, 1, attack,
3354 							  target_data, 1, 0,
3355 							  wave_buffer_size - attack, copy_mode);
3356 	    }
3357 
3358 	    free(target_data);
3359 	  }else{
3360 	    if(attack + frame_count <= wave_buffer_size){
3361 	      ags_audio_buffer_util_copy_buffer_to_buffer(buffer->data, 1, attack,
3362 							  clipboard_data, 1, 0,
3363 							  frame_count, copy_mode);
3364 	    }else{
3365 	      ags_audio_buffer_util_copy_buffer_to_buffer(buffer->data, 1, attack,
3366 							  clipboard_data, 1, 0,
3367 							  wave_buffer_size - attack, copy_mode);
3368 	    }
3369 	  }
3370 
3371 	  /* find next */
3372 	  if(attack + frame_count > wave_buffer_size){
3373 	    buffer = ags_wave_find_point(wave,
3374 					 x_val + 1,
3375 					 FALSE);
3376 
3377 	    if(buffer != NULL &&
3378 	       do_replace){
3379 	      void *data;
3380 
3381 	      data = buffer->data;
3382 
3383 	      if(wave_format == AGS_SOUNDCARD_DOUBLE){
3384 		ags_audio_buffer_util_clear_double(data, 1,
3385 						   attack);
3386 	      }else if(wave_format == AGS_SOUNDCARD_FLOAT){
3387 		ags_audio_buffer_util_clear_float(data, 1,
3388 						  attack);
3389 	      }else{
3390 		ags_audio_buffer_util_clear_buffer(data, 1,
3391 						   attack, ags_audio_buffer_util_format_from_soundcard(wave_format));
3392 	      }
3393 	    }
3394 
3395 	    if(buffer == NULL){
3396 	      buffer = ags_buffer_new();
3397 	      g_object_set(buffer,
3398 			   "samplerate", wave_samplerate,
3399 			   "buffer-size", wave_buffer_size,
3400 			   "format", wave_format,
3401 			   NULL);
3402 	      buffer->x = x_val + 1;
3403 
3404 	      ags_wave_add_buffer(wave,
3405 				  buffer,
3406 				  FALSE);
3407 	    }
3408 
3409 	    //	      g_message("insert - buffer->x = %lu", buffer->x);
3410 
3411 	    copy_mode = ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(wave_format),
3412 							    ags_audio_buffer_util_format_from_soundcard(format_val));
3413 
3414 	    if(samplerate_val != wave_samplerate){
3415 	      target_data = ags_stream_alloc(wave_buffer_size,
3416 					     format_val);
3417 
3418 	      ags_audio_buffer_util_resample_with_buffer(clipboard_data, 1,
3419 							 ags_audio_buffer_util_format_from_soundcard(format_val), samplerate_val,
3420 							 buffer_size_val,
3421 							 wave_samplerate,
3422 							 wave_buffer_size,
3423 							 target_data);
3424 
3425 	      ags_audio_buffer_util_copy_buffer_to_buffer(buffer->data, 1, 0,
3426 							  target_data, 1, wave_buffer_size - attack,
3427 							  attack, copy_mode);
3428 
3429 	      free(target_data);
3430 	    }else{
3431 	      ags_audio_buffer_util_copy_buffer_to_buffer(buffer->data, 1, 0,
3432 							  clipboard_data, 1, wave_buffer_size - attack,
3433 							  attack, copy_mode);
3434 	    }
3435 	  }
3436 	}
3437       }
3438     }
3439 
3440     node = node->next;
3441   }
3442 }
3443 
3444 /**
3445  * ags_wave_insert_native_level_from_clipboard:
3446  * @wave: the #AgsWave
3447  * @wave_node: the clipboard XML data
3448  * @version: clipboard version
3449  * @x_boundary: region start offset
3450  * @reset_x_offset: if %TRUE @x_offset used as cursor
3451  * @x_offset: region start cursor offset
3452  * @delay: the delay to be used
3453  * @attack: the attack to be used
3454  * @match_line: only paste if channel matches
3455  * @do_replace: if %TRUE current data is replaced, otherwise additive mixing is performed
3456  *
3457  * Paste previously copied buffers.
3458  *
3459  * Since: 3.0.0
3460  */
3461 void
ags_wave_insert_native_level_from_clipboard(AgsWave * wave,xmlNode * root_node,char * version,char * x_boundary,gboolean reset_x_offset,guint64 x_offset,gdouble delay,guint attack,gboolean match_line,gboolean do_replace)3462 ags_wave_insert_native_level_from_clipboard(AgsWave *wave,
3463 					    xmlNode *root_node, char *version,
3464 					    char *x_boundary,
3465 					    gboolean reset_x_offset, guint64 x_offset,
3466 					    gdouble delay, guint attack,
3467 					    gboolean match_line, gboolean do_replace)
3468 {
3469   guint current_line;
3470   guint64 relative_offset;
3471   guint wave_samplerate;
3472   guint wave_buffer_size;
3473   guint wave_format;
3474 
3475   gboolean match_timestamp;
3476 
3477   if(!AGS_IS_WAVE(wave)){
3478     return;
3479   }
3480 
3481   match_timestamp = TRUE;
3482 
3483   if(!xmlStrncmp("1.4.0",
3484 		 version,
3485 		 6)){
3486     /* changes contain only optional informations */
3487     g_object_get(wave,
3488 		 "line", &current_line,
3489 		 "samplerate", &wave_samplerate,
3490 		 "buffer-size", &wave_buffer_size,
3491 		 "format", &wave_format,
3492 		 NULL);
3493 
3494     relative_offset = AGS_WAVE_DEFAULT_BUFFER_LENGTH * wave_samplerate;
3495 
3496     if(match_line &&
3497        current_line != g_ascii_strtoull(xmlGetProp(root_node,
3498 						   "line"),
3499 					NULL,
3500 					10)){
3501       //      g_message("line %d", current_line);
3502 
3503       return;
3504     }
3505 
3506     ags_wave_insert_native_level_from_clipboard_version_1_4_0(wave,
3507 							      root_node, version,
3508 							      x_boundary,
3509 							      reset_x_offset, x_offset,
3510 							      delay, attack,
3511 							      match_line, do_replace,
3512 							      current_line,
3513 							      relative_offset,
3514 							      wave_samplerate,
3515 							      wave_buffer_size,
3516 							      wave_format,
3517 							      match_timestamp);
3518   }
3519 }
3520 
3521 /**
3522  * ags_wave_insert_from_clipboard:
3523  * @wave: the #AgsWave
3524  * @wave_node: the clipboard XML data
3525  * @reset_x_offset: if %TRUE @x_offset used as cursor
3526  * @x_offset: region start cursor offset
3527  * @delay: the delay to be used
3528  * @attack: the attack to be used
3529  *
3530  * Paste previously copied buffers.
3531  *
3532  * Since: 3.0.0
3533  */
3534 void
ags_wave_insert_from_clipboard(AgsWave * wave,xmlNode * wave_node,gboolean reset_x_offset,guint64 x_offset,gdouble delay,guint attack)3535 ags_wave_insert_from_clipboard(AgsWave *wave,
3536 			       xmlNode *wave_node,
3537 			       gboolean reset_x_offset, guint64 x_offset,
3538 			       gdouble delay, guint attack)
3539 {
3540   ags_wave_insert_from_clipboard_extended(wave,
3541 					  wave_node,
3542 					  reset_x_offset, x_offset,
3543 					  delay, attack,
3544 					  FALSE, FALSE);
3545 }
3546 
3547 /**
3548  * ags_wave_insert_from_clipboard_extended:
3549  * @wave: the #AgsWave
3550  * @wave_node: the clipboard XML data
3551  * @reset_x_offset: if %TRUE @x_offset used as cursor
3552  * @x_offset: region start cursor offset
3553  * @delay: the delay to be used
3554  * @attack: the attack to be used
3555  * @match_line: only paste if channel matches
3556  * @do_replace: if %TRUE current data is replaced, otherwise additive mixing is performed
3557  *
3558  * Paste previously copied buffers.
3559  *
3560  * Since: 3.0.0
3561  */
3562 void
ags_wave_insert_from_clipboard_extended(AgsWave * wave,xmlNode * wave_node,gboolean reset_x_offset,guint64 x_offset,gdouble delay,guint attack,gboolean match_line,gboolean do_replace)3563 ags_wave_insert_from_clipboard_extended(AgsWave *wave,
3564 					xmlNode *wave_node,
3565 					gboolean reset_x_offset, guint64 x_offset,
3566 					gdouble delay, guint attack,
3567 					gboolean match_line, gboolean do_replace)
3568 {
3569   char *program, *version, *type, *format;
3570   char *x_boundary;
3571 
3572   if(!AGS_IS_WAVE(wave)){
3573     return;
3574   }
3575 
3576   while(wave_node != NULL){
3577     if(wave_node->type == XML_ELEMENT_NODE && !xmlStrncmp("wave", wave_node->name, 9)){
3578       break;
3579     }
3580 
3581     wave_node = wave_node->next;
3582   }
3583 
3584   if(wave_node != NULL){
3585     program = xmlGetProp(wave_node, "program");
3586 
3587     if(!xmlStrncmp("ags", program, 4)){
3588       version = xmlGetProp(wave_node, "version");
3589       type = xmlGetProp(wave_node, "type");
3590       format = xmlGetProp(wave_node, "format");
3591 
3592       if(!xmlStrcmp(AGS_WAVE_CLIPBOARD_FORMAT,
3593 		    format)){
3594 	x_boundary = xmlGetProp(wave_node, "x-boundary");
3595 
3596 	ags_wave_insert_native_level_from_clipboard(wave,
3597 						    wave_node, version,
3598 						    x_boundary,
3599 						    reset_x_offset, x_offset,
3600 						    delay, attack,
3601 						    match_line, do_replace);
3602       }
3603     }
3604   }
3605 }
3606 
3607 /**
3608  * ags_wave_new:
3609  * @audio: the assigned #AgsAudio
3610  * @line: the line to be used
3611  *
3612  * Creates a new instance of #AgsWave.
3613  *
3614  * Returns: a new #AgsWave
3615  *
3616  * Since: 3.0.0
3617  */
3618 AgsWave*
ags_wave_new(GObject * audio,guint line)3619 ags_wave_new(GObject *audio,
3620 	     guint line)
3621 {
3622   AgsWave *wave;
3623 
3624   wave = (AgsWave *) g_object_new(AGS_TYPE_WAVE,
3625 				  "audio", audio,
3626 				  "line", line,
3627 				  NULL);
3628 
3629   return(wave);
3630 }
3631