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", ¤t_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", ¤t_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", ¤t_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", ¤t_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", ¤t_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", ¤t_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", ×tamp_a,
977 NULL);
978
979 g_object_get(b,
980 "timestamp", ×tamp_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", ×tamp,
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", ¤t_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", ¤t_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", ¤t_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", ¤t_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", ¤t_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", ¤t_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", ¤t_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", ¤t_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", ¤t_selection_x0,
2419 "selection-x1", ¤t_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", ¤t_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", ×tamp,
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", ×tamp,
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", ¤t_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