1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2019 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/recall/ags_play_wave_channel_run.h>
21
22 #include <ags/audio/ags_recycling.h>
23 #include <ags/audio/ags_recall_id.h>
24 #include <ags/audio/ags_recall_container.h>
25 #include <ags/audio/ags_wave.h>
26 #include <ags/audio/ags_buffer.h>
27 #include <ags/audio/ags_audio_buffer_util.h>
28
29 #include <ags/audio/recall/ags_play_wave_audio.h>
30 #include <ags/audio/recall/ags_play_wave_audio_run.h>
31 #include <ags/audio/recall/ags_play_wave_channel.h>
32
33 #include <math.h>
34
35 #include <ags/i18n.h>
36
37 void ags_play_wave_channel_run_class_init(AgsPlayWaveChannelRunClass *play_wave_channel_run);
38 void ags_play_wave_channel_run_seekable_interface_init(AgsSeekableInterface *seekable);
39 void ags_play_wave_channel_run_init(AgsPlayWaveChannelRun *play_wave_channel_run);
40 void ags_play_wave_channel_run_set_property(GObject *gobject,
41 guint prop_id,
42 const GValue *value,
43 GParamSpec *param_spec);
44 void ags_play_wave_channel_run_get_property(GObject *gobject,
45 guint prop_id,
46 GValue *value,
47 GParamSpec *param_spec);
48 void ags_play_wave_channel_run_dispose(GObject *gobject);
49 void ags_play_wave_channel_run_finalize(GObject *gobject);
50
51 void ags_play_wave_channel_run_seek(AgsSeekable *seekable,
52 gint64 offset,
53 guint whence);
54
55 void ags_play_wave_channel_run_run_inter_add_audio_signal(AgsPlayWaveChannelRun *play_wave_channel_run,
56 AgsChannel *channel,
57 GObject *output_soundcard,
58 AgsRecallID *recall_id,
59 guint samplerate,
60 guint buffer_size,
61 guint format);
62
63 void ags_play_wave_channel_run_run_inter(AgsRecall *recall);
64
65 /**
66 * SECTION:ags_play_wave_channel_run
67 * @short_description: play wave
68 * @title: AgsPlayWaveChannelRun
69 * @section_id:
70 * @include: ags/channel/recall/ags_play_wave_channel_run.h
71 *
72 * The #AgsPlayWaveChannelRun class play wave.
73 */
74
75 enum{
76 PROP_0,
77 PROP_X_OFFSET,
78 };
79
80 static gpointer ags_play_wave_channel_run_parent_class = NULL;
81
82 GType
ags_play_wave_channel_run_get_type()83 ags_play_wave_channel_run_get_type()
84 {
85 static volatile gsize g_define_type_id__volatile = 0;
86
87 if(g_once_init_enter (&g_define_type_id__volatile)){
88 GType ags_type_play_wave_channel_run = 0;
89
90 static const GTypeInfo ags_play_wave_channel_run_info = {
91 sizeof (AgsPlayWaveChannelRunClass),
92 NULL, /* base_init */
93 NULL, /* base_finalize */
94 (GClassInitFunc) ags_play_wave_channel_run_class_init,
95 NULL, /* class_finalize */
96 NULL, /* class_data */
97 sizeof (AgsPlayWaveChannelRun),
98 0, /* n_preallocs */
99 (GInstanceInitFunc) ags_play_wave_channel_run_init,
100 };
101
102 static const GInterfaceInfo ags_seekable_interface_info = {
103 (GInterfaceInitFunc) ags_play_wave_channel_run_seekable_interface_init,
104 NULL, /* interface_finalize */
105 NULL, /* interface_data */
106 };
107
108 ags_type_play_wave_channel_run = g_type_register_static(AGS_TYPE_RECALL_CHANNEL_RUN,
109 "AgsPlayWaveChannelRun",
110 &ags_play_wave_channel_run_info,
111 0);
112
113 g_type_add_interface_static(ags_type_play_wave_channel_run,
114 AGS_TYPE_SEEKABLE,
115 &ags_seekable_interface_info);
116
117 g_once_init_leave(&g_define_type_id__volatile, ags_type_play_wave_channel_run);
118 }
119
120 return g_define_type_id__volatile;
121 }
122
123 void
ags_play_wave_channel_run_class_init(AgsPlayWaveChannelRunClass * play_wave_channel_run)124 ags_play_wave_channel_run_class_init(AgsPlayWaveChannelRunClass *play_wave_channel_run)
125 {
126 GObjectClass *gobject;
127 AgsRecallClass *recall;
128
129 GParamSpec *param_spec;
130
131 ags_play_wave_channel_run_parent_class = g_type_class_peek_parent(play_wave_channel_run);
132
133 /* GObjectClass */
134 gobject = (GObjectClass *) play_wave_channel_run;
135
136 gobject->set_property = ags_play_wave_channel_run_set_property;
137 gobject->get_property = ags_play_wave_channel_run_get_property;
138
139 gobject->dispose = ags_play_wave_channel_run_dispose;
140 gobject->finalize = ags_play_wave_channel_run_finalize;
141
142 /* properties */
143 /**
144 * AgsPlayWaveChannelRun:x-offset:
145 *
146 * The x offset.
147 *
148 * Since: 3.0.0
149 */
150 param_spec = g_param_spec_uint64("x-offset",
151 i18n_pspec("x offset"),
152 i18n_pspec("The x offset in the wave"),
153 0,
154 G_MAXUINT64,
155 0,
156 G_PARAM_READABLE | G_PARAM_WRITABLE);
157 g_object_class_install_property(gobject,
158 PROP_X_OFFSET,
159 param_spec);
160
161 /* AgsRecallClass */
162 recall = (AgsRecallClass *) play_wave_channel_run;
163
164 recall->run_inter = ags_play_wave_channel_run_run_inter;
165 }
166
167 void
ags_play_wave_channel_run_seekable_interface_init(AgsSeekableInterface * seekable)168 ags_play_wave_channel_run_seekable_interface_init(AgsSeekableInterface *seekable)
169 {
170 seekable->seek = ags_play_wave_channel_run_seek;
171 }
172
173 void
ags_play_wave_channel_run_init(AgsPlayWaveChannelRun * play_wave_channel_run)174 ags_play_wave_channel_run_init(AgsPlayWaveChannelRun *play_wave_channel_run)
175 {
176 ags_recall_set_ability_flags((AgsRecall *) play_wave_channel_run, (AGS_SOUND_ABILITY_WAVE));
177
178 AGS_RECALL(play_wave_channel_run)->name = "ags-play-wave";
179 AGS_RECALL(play_wave_channel_run)->version = AGS_RECALL_DEFAULT_VERSION;
180 AGS_RECALL(play_wave_channel_run)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
181 AGS_RECALL(play_wave_channel_run)->xml_type = "ags-play-wave-channel-run";
182 AGS_RECALL(play_wave_channel_run)->port = NULL;
183
184 play_wave_channel_run->timestamp = ags_timestamp_new();
185 g_object_ref(play_wave_channel_run->timestamp);
186
187 play_wave_channel_run->timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
188 play_wave_channel_run->timestamp->flags |= AGS_TIMESTAMP_OFFSET;
189
190 play_wave_channel_run->timestamp->timer.ags_offset.offset = 0;
191
192 play_wave_channel_run->audio_signal = NULL;
193
194 play_wave_channel_run->x_offset = 0;
195 }
196
197 void
ags_play_wave_channel_run_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)198 ags_play_wave_channel_run_set_property(GObject *gobject,
199 guint prop_id,
200 const GValue *value,
201 GParamSpec *param_spec)
202 {
203 AgsPlayWaveChannelRun *play_wave_channel_run;
204
205 GRecMutex *recall_mutex;
206
207 play_wave_channel_run = AGS_PLAY_WAVE_CHANNEL_RUN(gobject);
208
209 /* get recall mutex */
210 recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_wave_channel_run);
211
212 switch(prop_id){
213 case PROP_X_OFFSET:
214 {
215 guint64 x_offset;
216
217 x_offset = g_value_get_uint64(value);
218
219 g_rec_mutex_lock(recall_mutex);
220
221 play_wave_channel_run->x_offset = x_offset;
222
223 g_rec_mutex_unlock(recall_mutex);
224 }
225 break;
226 default:
227 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
228 break;
229 };
230 }
231
232 void
ags_play_wave_channel_run_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)233 ags_play_wave_channel_run_get_property(GObject *gobject,
234 guint prop_id,
235 GValue *value,
236 GParamSpec *param_spec)
237 {
238 AgsPlayWaveChannelRun *play_wave_channel_run;
239
240 GRecMutex *recall_mutex;
241
242 play_wave_channel_run = AGS_PLAY_WAVE_CHANNEL_RUN(gobject);
243
244 /* get recall mutex */
245 recall_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_wave_channel_run);
246
247 switch(prop_id){
248 case PROP_X_OFFSET:
249 {
250 g_rec_mutex_lock(recall_mutex);
251
252 g_value_set_uint64(value, play_wave_channel_run->x_offset);
253
254 g_rec_mutex_unlock(recall_mutex);
255 }
256 break;
257 default:
258 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
259 break;
260 };
261 }
262
263 void
ags_play_wave_channel_run_dispose(GObject * gobject)264 ags_play_wave_channel_run_dispose(GObject *gobject)
265 {
266 AgsPlayWaveChannelRun *play_wave_channel_run;
267
268 play_wave_channel_run = AGS_PLAY_WAVE_CHANNEL_RUN(gobject);
269
270 /* call parent */
271 G_OBJECT_CLASS(ags_play_wave_channel_run_parent_class)->dispose(gobject);
272 }
273
274 void
ags_play_wave_channel_run_finalize(GObject * gobject)275 ags_play_wave_channel_run_finalize(GObject *gobject)
276 {
277 AgsPlayWaveChannelRun *play_wave_channel_run;
278
279 play_wave_channel_run = AGS_PLAY_WAVE_CHANNEL_RUN(gobject);
280
281 /* timestamp */
282 if(play_wave_channel_run->timestamp != NULL){
283 g_object_unref(G_OBJECT(play_wave_channel_run->timestamp));
284 }
285
286 /* call parent */
287 G_OBJECT_CLASS(ags_play_wave_channel_run_parent_class)->finalize(gobject);
288 }
289
290 void
ags_play_wave_channel_run_seek(AgsSeekable * seekable,gint64 offset,guint whence)291 ags_play_wave_channel_run_seek(AgsSeekable *seekable,
292 gint64 offset,
293 guint whence)
294 {
295 AgsPlayWaveChannelRun *play_wave_channel_run;
296
297 GObject *soundcard;
298
299 gdouble absolute_delay;
300 guint buffer_size;
301 guint64 x_offset;
302
303 play_wave_channel_run = AGS_PLAY_WAVE_CHANNEL_RUN(seekable);
304
305 g_object_get(play_wave_channel_run,
306 "output-soundcard", &soundcard,
307 "buffer-size", &buffer_size,
308 NULL);
309
310 absolute_delay = ags_soundcard_get_absolute_delay(AGS_SOUNDCARD(soundcard));
311
312 switch(whence){
313 case AGS_SEEK_CUR:
314 {
315 g_object_get(play_wave_channel_run,
316 "x-offset", &x_offset,
317 NULL);
318
319 if(x_offset + (offset * absolute_delay * buffer_size) < 0){
320 x_offset = 0;
321 }else{
322 x_offset = x_offset + (offset * absolute_delay * buffer_size);
323 }
324
325 g_object_set(play_wave_channel_run,
326 "x-offset", x_offset,
327 NULL);
328 }
329 break;
330 case AGS_SEEK_END:
331 {
332 g_warning("seek from end not implemented");
333 }
334 break;
335 case AGS_SEEK_SET:
336 {
337 x_offset = offset * absolute_delay * buffer_size;
338
339 g_object_set(play_wave_channel_run,
340 "x-offset", x_offset,
341 NULL);
342 }
343 break;
344 }
345
346 g_object_unref(soundcard);
347 }
348
349 void
ags_play_wave_channel_run_run_inter_add_audio_signal(AgsPlayWaveChannelRun * play_wave_channel_run,AgsChannel * channel,GObject * output_soundcard,AgsRecallID * recall_id,guint samplerate,guint buffer_size,guint format)350 ags_play_wave_channel_run_run_inter_add_audio_signal(AgsPlayWaveChannelRun *play_wave_channel_run,
351 AgsChannel *channel,
352 GObject *output_soundcard,
353 AgsRecallID *recall_id,
354 guint samplerate,
355 guint buffer_size,
356 guint format)
357 {
358 AgsChannel *output;
359 AgsRecycling *first_recycling;
360
361 g_object_get(channel,
362 "first-recycling", &first_recycling,
363 NULL);
364 g_object_unref(first_recycling);
365
366 play_wave_channel_run->audio_signal = ags_audio_signal_new(output_soundcard,
367 (GObject *) first_recycling,
368 (GObject *) recall_id);
369 g_object_set(play_wave_channel_run->audio_signal,
370 "samplerate", samplerate,
371 "buffer-size", buffer_size,
372 "format", format,
373 NULL);
374 ags_audio_signal_stream_resize(play_wave_channel_run->audio_signal,
375 3);
376
377 play_wave_channel_run->audio_signal->stream_current = play_wave_channel_run->audio_signal->stream;
378
379 ags_recycling_add_audio_signal(first_recycling,
380 play_wave_channel_run->audio_signal);
381
382 ags_connectable_connect(AGS_CONNECTABLE(play_wave_channel_run->audio_signal));
383 }
384
385 void
ags_play_wave_channel_run_run_inter(AgsRecall * recall)386 ags_play_wave_channel_run_run_inter(AgsRecall *recall)
387 {
388 AgsAudio *audio;
389 AgsChannel *channel;
390 AgsWave *wave;
391 AgsPort *port;
392 AgsRecallID *recall_id;
393
394 AgsPlayWaveAudio *play_wave_audio;
395 AgsPlayWaveAudioRun *play_wave_audio_run;
396 AgsPlayWaveChannel *play_wave_channel;
397 AgsPlayWaveChannelRun *play_wave_channel_run;
398
399 GObject *output_soundcard;
400
401 GList *start_list, *list;
402
403 guint line;
404 guint samplerate;
405 guint buffer_size;
406 guint format;
407 guint64 x_offset;
408 guint64 x_point_offset;
409 guint64 relative_offset;
410 gdouble delay;
411 guint frame_count;
412 guint attack;
413 gboolean do_playback;
414 gboolean do_loop;
415
416 GValue do_playback_value = {0,};
417 GValue do_loop_value = {0,};
418 GValue x_offset_value = {0,};
419
420 GRecMutex *audio_mutex;
421 GRecMutex *channel_mutex;
422
423 play_wave_channel_run = (AgsPlayWaveChannelRun *) recall;
424
425 g_object_get(play_wave_channel_run,
426 "output-soundcard", &output_soundcard,
427 "recall-id", &recall_id,
428 "recall-audio", &play_wave_audio,
429 "recall-channel", &play_wave_channel,
430 "recall-audio-run", &play_wave_audio_run,
431 NULL);
432
433 delay = ags_soundcard_get_delay(AGS_SOUNDCARD(output_soundcard));
434
435 /* get do playback */
436 g_object_get(play_wave_channel,
437 "do-playback", &port,
438 NULL);
439
440 g_value_init(&do_playback_value,
441 G_TYPE_BOOLEAN);
442
443 ags_port_safe_read(port,
444 &do_playback_value);
445
446 do_playback = g_value_get_boolean(&do_playback_value);
447
448 g_value_unset(&do_playback_value);
449
450 g_object_unref(port);
451
452 if(!do_playback){
453 g_object_unref(output_soundcard);
454
455 g_object_unref(recall_id);
456
457 g_object_unref(play_wave_audio);
458
459 g_object_unref(play_wave_channel);
460
461 g_object_unref(play_wave_audio_run);
462
463 return;
464 }
465
466 g_object_get(play_wave_channel_run,
467 "x-offset", &x_offset,
468 NULL);
469
470 /* get some fields */
471 g_object_get(play_wave_audio_run,
472 "audio", &audio,
473 NULL);
474
475 g_object_get(play_wave_channel_run,
476 "source", &channel,
477 NULL);
478
479 g_object_get(audio,
480 "samplerate", &samplerate,
481 "buffer-size", &buffer_size,
482 "format", &format,
483 "wave", &start_list,
484 NULL);
485
486 g_object_get(channel,
487 "line", &line,
488 NULL);
489
490 relative_offset = AGS_WAVE_DEFAULT_BUFFER_LENGTH * samplerate;
491
492 attack = (x_offset % relative_offset) % buffer_size;
493
494 frame_count = buffer_size - attack;
495
496 if(x_offset + frame_count > relative_offset * floor(x_offset / relative_offset) + relative_offset){
497 frame_count = relative_offset * floor((x_offset + frame_count) / relative_offset) - x_offset;
498 }
499
500 /* clear */
501 if(play_wave_channel_run->audio_signal != NULL){
502 ags_audio_buffer_util_clear_buffer(play_wave_channel_run->audio_signal->stream_current->data, 1,
503 buffer_size, ags_audio_buffer_util_format_from_soundcard(format));
504 }
505
506 /* time stamp offset */
507 ags_timestamp_set_ags_offset(play_wave_channel_run->timestamp,
508 (guint64) (relative_offset * floor((double) x_offset / (double) relative_offset)));
509
510 /* find wave */
511 wave = NULL;
512
513 list = ags_wave_find_near_timestamp(start_list, line,
514 play_wave_channel_run->timestamp);
515
516 if(list != NULL){
517 AgsBuffer *buffer;
518
519 wave = list->data;
520
521 x_point_offset = x_offset - attack;
522 buffer = ags_wave_find_point(wave,
523 x_point_offset,
524 FALSE);
525
526 if(buffer != NULL){
527 guint copy_mode;
528 guint current_format;
529
530 g_object_get(buffer,
531 "format", ¤t_format,
532 NULL);
533
534 if(play_wave_channel_run->audio_signal == NULL){
535 ags_play_wave_channel_run_run_inter_add_audio_signal(play_wave_channel_run,
536 channel,
537 output_soundcard,
538 recall_id,
539 samplerate,
540 buffer_size,
541 format);
542 }
543
544 copy_mode = ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(format),
545 ags_audio_buffer_util_format_from_soundcard(current_format));
546
547 ags_audio_buffer_util_copy_buffer_to_buffer(play_wave_channel_run->audio_signal->stream_current->data, 1, 0,
548 buffer->data, 1, attack,
549 frame_count, copy_mode);
550 }
551 }
552
553 /* 2nd attempt */
554 ags_timestamp_set_ags_offset(play_wave_channel_run->timestamp,
555 (guint64) relative_offset * floor((double) (x_offset + frame_count) / (double) relative_offset));
556
557 /* play */
558 if(attack != 0 ||
559 frame_count != buffer_size){
560 list = ags_wave_find_near_timestamp(start_list, line,
561 play_wave_channel_run->timestamp);
562
563 if(list != NULL){
564 AgsBuffer *buffer;
565
566 wave = list->data;
567
568 x_point_offset = x_offset + frame_count;
569 buffer = ags_wave_find_point(wave,
570 x_point_offset,
571 FALSE);
572
573 if(buffer != NULL){
574 guint copy_mode;
575 guint current_format;
576
577 g_object_get(buffer,
578 "format", ¤t_format,
579 NULL);
580
581 if(play_wave_channel_run->audio_signal == NULL){
582 ags_play_wave_channel_run_run_inter_add_audio_signal(play_wave_channel_run,
583 channel,
584 output_soundcard,
585 recall_id,
586 samplerate,
587 buffer_size,
588 format);
589 }
590
591 copy_mode = ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(format),
592 ags_audio_buffer_util_format_from_soundcard(current_format));
593
594 ags_audio_buffer_util_copy_buffer_to_buffer(play_wave_channel_run->audio_signal->stream_current->data, 1, frame_count,
595 buffer->data, 1, 0,
596 buffer_size - frame_count, copy_mode);
597 }
598 }
599 }
600
601 /* check loop */
602 x_offset += buffer_size;
603
604 g_object_get(play_wave_audio,
605 "wave-loop", &port,
606 NULL);
607
608 g_value_init(&do_loop_value,
609 G_TYPE_BOOLEAN);
610
611 ags_port_safe_read(port,
612 &do_loop_value);
613
614 do_loop = g_value_get_boolean(&do_loop_value);
615 g_value_unset(&do_loop_value);
616
617 if(do_loop){
618 guint64 loop_start, loop_end;
619
620 GValue loop_start_value = {0,};
621 GValue loop_end_value = {0,};
622
623 g_object_get(play_wave_audio,
624 "wave-loop-end", &port,
625 NULL);
626
627 g_value_init(&loop_end_value,
628 G_TYPE_UINT64);
629
630 ags_port_safe_read(port,
631 &loop_end_value);
632
633 loop_end = g_value_get_uint64(&loop_end_value);
634 g_value_unset(&loop_end_value);
635
636 if(x_offset / buffer_size / delay >= loop_end){
637 g_object_get(play_wave_audio,
638 "wave-loop-start", &port,
639 NULL);
640
641 g_value_init(&loop_start_value,
642 G_TYPE_UINT64);
643
644 ags_port_safe_read(port,
645 &loop_start_value);
646
647 loop_start = g_value_get_uint64(&loop_start_value);
648 g_value_unset(&loop_start_value);
649
650 x_offset = (relative_offset * floor((delay * buffer_size * loop_start) / relative_offset)) + ((guint64) (delay * buffer_size * loop_start) % relative_offset);
651 }
652 }
653
654 /* new x offset */
655 g_object_set(play_wave_channel_run,
656 "x-offset", x_offset,
657 NULL);
658
659 g_object_get(play_wave_channel,
660 "x-offset", &port,
661 NULL);
662
663 g_value_init(&x_offset_value,
664 G_TYPE_UINT64);
665
666 g_value_set_uint64(&x_offset_value,
667 x_offset);
668
669 ags_port_safe_write(port,
670 &x_offset_value);
671
672 g_value_unset(&x_offset_value);
673 g_object_unref(port);
674
675 /* unref */
676 g_object_unref(output_soundcard);
677
678 g_object_unref(recall_id);
679
680 g_object_unref(play_wave_audio);
681
682 g_object_unref(play_wave_channel);
683
684 g_object_unref(play_wave_audio_run);
685
686 g_object_unref(audio);
687
688 g_object_unref(channel);
689
690 g_list_free_full(start_list,
691 g_object_unref);
692 }
693
694 /**
695 * ags_play_wave_channel_run_new:
696 * @source: the #AgsChannel
697 *
698 * Create a new instance of #AgsPlayWaveChannelRun
699 *
700 * Returns: the new #AgsPlayWaveChannelRun
701 *
702 * Since: 3.0.0
703 */
704 AgsPlayWaveChannelRun*
ags_play_wave_channel_run_new(AgsChannel * source)705 ags_play_wave_channel_run_new(AgsChannel *source)
706 {
707 AgsPlayWaveChannelRun *play_wave_channel_run;
708
709 play_wave_channel_run = (AgsPlayWaveChannelRun *) g_object_new(AGS_TYPE_PLAY_WAVE_CHANNEL_RUN,
710 "source", source,
711 NULL);
712
713 return(play_wave_channel_run);
714 }
715