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", &current_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", &current_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