1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2015 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 <glib.h>
21 #include <glib-object.h>
22 
23 #include <CUnit/CUnit.h>
24 #include <CUnit/Automated.h>
25 #include <CUnit/Basic.h>
26 
27 #include <ags/object/ags_soundcard.h>
28 
29 #include <ags/audio/ags_devout.h>
30 #include <ags/audio/ags_channel.h>
31 #include <ags/audio/ags_recycling.h>
32 #include <ags/audio/ags_audio_signal.h>
33 #include <ags/audio/ags_audio_buffer_util.h>
34 
35 #include <libintl.h>
36 #include <stdio.h>
37 #include <signal.h>
38 #include <unistd.h>
39 #include <sys/resource.h>
40 #include <sys/mman.h>
41 
42 int ags_recycling_test_init_suite();
43 int ags_recycling_test_clean_suite();
44 
45 void ags_recycling_test_add_audio_signal();
46 void ags_recycling_test_remove_audio_signal();
47 void ags_recycling_test_create_audio_signal_with_defaults();
48 void ags_recycling_test_create_audio_signal_with_frame_count();
49 void ags_recycling_test_position();
50 void ags_recycling_test_find_next_channel();
51 
52 gboolean ags_recycling_test_create_audio_signal_with_frame_count_compare_frames(signed short *destination,
53 										signed short *source,
54 										guint buffer_size);
55 
56 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_SAMPLERATE (44100)
57 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_BUFFER_SIZE (944)
58 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_FORMAT (AGS_SOUNDCARD_SIGNED_16_BIT)
59 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_FREQUENCY (440.0)
60 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_FRAMES (AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_SAMPLERATE / \
61 								     AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_BUFFER_SIZE * \
62 								     440.0)
63 
64 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_NOTE_DELAY (1.0 / 4.0)
65 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_NOTE_LENGTH (64.0)
66 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_SAMPLERATE (44100)
67 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_BUFFER_SIZE (944)
68 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FORMAT (AGS_SOUNDCARD_SIGNED_16_BIT)
69 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FREQUENCY (440.0)
70 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES (AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_SAMPLERATE * \
71 									(AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_NOTE_LENGTH * \
72 									 (1.0 / 16.0 * AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_NOTE_DELAY)))
73 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_LAST_FRAME (AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES % \
74 									    AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_BUFFER_SIZE)
75 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_LOOP_START (2.0 * AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES / 5.0 / 16.0)
76 #define AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_LOOP_END (3.5 * AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES / 5.0 / 16.0)
77 
78 #define AGS_RECYCLING_TEST_POSITION_N_RECYCLING (16)
79 #define AGS_RECYCLING_TEST_FIND_NEXT_CHANNEL_N_CHANNEL (8)
80 
81 AgsApplicationContext *application_context;
82 AgsDevout *devout;
83 
84 /* The suite initialization function.
85  * Opens the temporary file used by the tests.
86  * Returns zero on success, non-zero otherwise.
87  */
88 int
ags_recycling_test_init_suite()89 ags_recycling_test_init_suite()
90 {
91   ags_priority_load_defaults(ags_priority_get_instance());
92 
93   application_context = ags_application_context_new(NULL,
94 						    NULL);
95   g_object_ref(application_context);
96 
97   ags_application_context_prepare(application_context);
98   ags_application_context_setup(application_context);
99 
100   devout = ags_devout_new(NULL);
101 
102   return(0);
103 }
104 
105 /* The suite cleanup function.
106  * Closes the temporary file used by the tests.
107  * Returns zero on success, non-zero otherwise.
108  */
109 int
ags_recycling_test_clean_suite()110 ags_recycling_test_clean_suite()
111 {
112   g_object_unref(devout);
113   g_object_unref(application_context);
114 
115   return(0);
116 }
117 
118 void
ags_recycling_test_add_audio_signal()119 ags_recycling_test_add_audio_signal()
120 {
121   AgsRecycling *recycling;
122   AgsAudioSignal *audio_signal;
123 
124   /* instantiate recycling */
125   recycling = ags_recycling_new(G_OBJECT(devout));
126 
127   /* instantiate audio signal */
128   audio_signal = ags_audio_signal_new(G_OBJECT(devout),
129 				      recycling,
130 				      NULL);
131 
132   /* add audio signal */
133   ags_recycling_add_audio_signal(recycling,
134 				 audio_signal);
135 
136   /* assert if audio signal available in recycling */
137   CU_ASSERT(g_list_find(recycling->audio_signal,
138 			audio_signal) != NULL);
139 }
140 
141 void
ags_recycling_test_remove_audio_signal()142 ags_recycling_test_remove_audio_signal()
143 {
144   AgsRecycling *recycling;
145   AgsAudioSignal *audio_signal;
146 
147   /* instantiate recycling */
148   recycling = ags_recycling_new(G_OBJECT(devout));
149 
150   /* instantiate audio signal */
151   audio_signal = ags_audio_signal_new(G_OBJECT(devout),
152 				      recycling,
153 				      NULL);
154 
155   /* add audio signal */
156   ags_recycling_add_audio_signal(recycling,
157 				 audio_signal);
158 
159   /* assert if audio signal available in recycling */
160   CU_ASSERT(g_list_find(recycling->audio_signal,
161 			audio_signal) != NULL);
162 
163   /* add audio signal */
164   ags_recycling_remove_audio_signal(recycling,
165 				    audio_signal);
166 
167   /* assert if no audio signal in recycling */
168   CU_ASSERT(g_list_find(recycling->audio_signal,
169 			audio_signal) == NULL);
170 }
171 
172 void
ags_recycling_test_create_audio_signal_with_defaults()173 ags_recycling_test_create_audio_signal_with_defaults()
174 {
175   AgsRecycling *recycling;
176   AgsAudioSignal *template, *audio_signal;
177   GList *stream, *template_stream;
178   signed short *buffer;
179   guint i, j;
180 
181   /* instantiate recycling */
182   recycling = ags_recycling_new(G_OBJECT(devout));
183 
184   /* instantiate template audio signal */
185   template = ags_audio_signal_new(G_OBJECT(devout),
186 				  recycling,
187 				  NULL);
188   template->flags |= AGS_AUDIO_SIGNAL_TEMPLATE;
189   g_object_set(G_OBJECT(template),
190 	       "samplerate", AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_SAMPLERATE,
191 	       "buffer-size", AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_BUFFER_SIZE,
192 	       "format", AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_FORMAT,
193 	       NULL);
194 
195   /* fill stream */
196   stream = NULL;
197 
198   for(i = 0; i < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_FRAMES;){
199     buffer = (signed short *) malloc(template->buffer_size * sizeof(signed short));
200     memset(buffer, 0, template->buffer_size * sizeof(signed short));
201 
202     for(j = 0;
203 	j < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_BUFFER_SIZE &&
204 	  i + j < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_FRAMES;
205 	j++){
206       /* generate sin tone */
207       buffer[j] = (signed short) (0xffff & (int) (32000.0 * (double) (sin ((double)(j) * 2.0 * M_PI * AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_FREQUENCY / (double) AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_SAMPLERATE))));
208     }
209 
210     /* prepend buffer */
211     stream = g_list_prepend(stream,
212 			    buffer);
213 
214     /* iterate */
215     i += AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_BUFFER_SIZE;
216   }
217 
218   template->stream_end = stream;
219   template->stream = g_list_reverse(stream);
220 
221   template->length = g_list_length(template->stream);
222 
223   /* add audio signal to recycling */
224   ags_recycling_add_audio_signal(recycling,
225 				 template);
226 
227   /* instantiate audio signal */
228   audio_signal = ags_audio_signal_new(G_OBJECT(devout),
229 				      recycling,
230 				      NULL);
231   audio_signal->format = AGS_SOUNDCARD_SIGNED_16_BIT;
232 
233   /* create defaults */
234   ags_recycling_create_audio_signal_with_defaults(recycling,
235 						  audio_signal,
236 						  0.0, 0);
237 
238   /* assert audio signal */
239   CU_ASSERT(audio_signal->samplerate == template->samplerate);
240   CU_ASSERT(audio_signal->buffer_size == template->buffer_size);
241   CU_ASSERT(audio_signal->format == template->format);
242 
243   CU_ASSERT(audio_signal->length == template->length);
244   CU_ASSERT(audio_signal->first_frame == template->first_frame);
245   CU_ASSERT(audio_signal->last_frame == template->last_frame);
246   CU_ASSERT(audio_signal->loop_start == template->loop_start);
247   CU_ASSERT(audio_signal->loop_end == template->loop_end);
248 
249   stream = audio_signal->stream;
250   template_stream = template->stream;
251 
252   for(i = 0; i < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_FRAMES;){
253     for(j = 0;
254 	j < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_BUFFER_SIZE &&
255 	  i + j < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_FRAMES;
256 	j++){
257       CU_ASSERT(AGS_AUDIO_BUFFER_S16(stream->data)[j] == AGS_AUDIO_BUFFER_S16(template_stream->data)[j]);
258     }
259 
260     /* iterate */
261     stream = stream->next;
262     template_stream = template_stream->next;
263 
264     i += AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_DEFAULTS_BUFFER_SIZE;
265   }
266 }
267 
268 gboolean
ags_recycling_test_create_audio_signal_with_frame_count_compare_frames(signed short * destination,signed short * source,guint buffer_size)269 ags_recycling_test_create_audio_signal_with_frame_count_compare_frames(signed short *destination,
270 								       signed short *source,
271 								       guint buffer_size)
272 {
273   guint i;
274 
275   for(i = 0; i < buffer_size; i++){
276     if(destination[i] != source[i]){
277       return(FALSE);
278     }
279   }
280 
281   return(TRUE);
282 }
283 
284 void
ags_recycling_test_create_audio_signal_with_frame_count()285 ags_recycling_test_create_audio_signal_with_frame_count()
286 {
287   AgsRecycling *recycling;
288   AgsAudioSignal *template, *audio_signal;
289 
290   GList *stream, *template_stream;
291 
292   signed short *entire_buffer;
293   signed short *buffer;
294 
295   guint frame_count;
296   guint first_frame;
297   guint loop_frame_count;
298   guint shifted_frame_count;
299   guint stream_index, template_stream_index;
300   guint copy_n_frames;
301   guint i, j, k;
302   guint nth;
303   guint copy_mode;
304   gboolean success;
305 
306   struct rlimit rl;
307 
308   int result;
309 
310   const rlim_t kStackSize = 64L * 1024L * 1024L;   // min stack size = 64 Mb
311 
312   /* instantiate recycling */
313   recycling = ags_recycling_new(G_OBJECT(devout));
314 
315   /* instantiate template audio signal */
316   template = ags_audio_signal_new(G_OBJECT(devout),
317 				  recycling,
318 				  NULL);
319   template->flags |= AGS_AUDIO_SIGNAL_TEMPLATE;
320   g_object_set(G_OBJECT(template),
321 	       "samplerate", AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_SAMPLERATE,
322 	       "buffer-size", AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_BUFFER_SIZE,
323 	       "format", AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FORMAT,
324 	       NULL);
325 
326   /* fill stream */
327   ags_audio_signal_stream_resize(template,
328 				 (guint) ceil(AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES / template->buffer_size) + 1);
329 
330   for(i = 0, nth = 0; i < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES / 16.0; nth++){
331     buffer = (signed short *) g_list_nth_data(template->stream,
332 					      nth);
333 
334     for(j = 0;
335 	j < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_BUFFER_SIZE &&
336 	  i < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES / 16.0;
337 	j++, i++){
338       /* generate sin tone */
339       buffer[j] = (signed short) (0xffff & (int) (32000.0 * (double) (sin ((double)(j) * 2.0 * M_PI * AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FREQUENCY / (double) AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_SAMPLERATE))));
340     }
341   }
342 
343   template->loop_start = AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_LOOP_START;
344   template->loop_end = AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_LOOP_END;
345 
346   /* add audio signal to recycling */
347   ags_recycling_add_audio_signal(recycling,
348 				 template);
349 
350   /* instantiate audio signal */
351   audio_signal = ags_audio_signal_new(G_OBJECT(devout),
352 				      recycling,
353 				      NULL);
354   g_object_set(G_OBJECT(audio_signal),
355 	       "samplerate", AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_SAMPLERATE,
356 	       "buffer-size", AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_BUFFER_SIZE,
357 	       "format", AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FORMAT,
358 	       NULL);
359 
360   /* create frame count */
361   frame_count = AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES;
362   ags_recycling_create_audio_signal_with_frame_count(recycling,
363 						     audio_signal,
364 						     frame_count,
365 						     0.0, 0);
366 
367   /* assert audio signal */
368   CU_ASSERT(audio_signal->samplerate == template->samplerate);
369   CU_ASSERT(audio_signal->buffer_size == template->buffer_size);
370   CU_ASSERT(audio_signal->format == template->format);
371 
372   CU_ASSERT(audio_signal->first_frame == template->first_frame);
373   CU_ASSERT(audio_signal->last_frame == frame_count % AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_BUFFER_SIZE);
374 
375   /* create compare buffer */
376   template_stream = template->stream;
377 
378   loop_frame_count = ((frame_count - template->loop_start) / (template->loop_end - template->loop_start)) * template->buffer_size;
379 
380   entire_buffer = (signed short *) malloc(AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES * sizeof(signed short));
381   memset(entire_buffer, 0, AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES * sizeof(signed short));
382 
383   copy_mode = ags_audio_buffer_util_get_copy_mode(AGS_AUDIO_BUFFER_UTIL_S16,
384 						  ags_audio_buffer_util_format_from_soundcard(template->format));
385 
386   for(i = 0, j = 0; i < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES;){
387     copy_n_frames = template->buffer_size;
388 
389     /* limit nth loop */
390     if(i > template->loop_start &&
391        i + copy_n_frames > template->loop_start + (template->loop_end - template->loop_start) &&
392        i + copy_n_frames < template->loop_start + loop_frame_count &&
393        template->loop_start + ((i - template->loop_start) % (template->loop_end - template->loop_start)) + copy_n_frames >= template->loop_end - template->loop_start){
394       copy_n_frames = template->loop_end - (template->loop_start + ((i - template->loop_start) % (template->loop_end - template->loop_start)));
395     }
396 
397     /* check boundaries */
398     if(i + copy_n_frames > AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES){
399       copy_n_frames = AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES - i;
400     }
401 
402     if(j + copy_n_frames > template->buffer_size){
403       copy_n_frames = template->buffer_size - j;
404     }
405 
406     /* copy */
407     ags_audio_buffer_util_copy_buffer_to_buffer(entire_buffer, 1, i,
408 						template_stream->data, 1, j,
409 						copy_n_frames, copy_mode);
410 
411     /* increment and iterate */
412     if(j + copy_n_frames == template->buffer_size){
413       template_stream = template_stream->next;
414     }
415 
416     if(i > template->loop_start &&
417        i + copy_n_frames > template->loop_start + (template->loop_end - template->loop_start) &&
418        i + copy_n_frames < template->loop_start + loop_frame_count &&
419        template->loop_start + ((i - template->loop_start) % (template->loop_end - template->loop_start)) + copy_n_frames >= template->loop_end - template->loop_start){
420       j = template->loop_start % template->buffer_size;
421       template_stream = g_list_nth(template->stream,
422 				   floor(template->loop_start / template->buffer_size));
423     }else{
424       j += copy_n_frames;
425     }
426 
427     i += copy_n_frames;
428 
429     if(j == template->buffer_size){
430       j = 0;
431     }
432   }
433 
434   /* check loop */
435   stream = audio_signal->stream;
436 
437   i = 0;
438   j = 0;
439   k = 0;
440 
441   success = TRUE;
442 
443   for(i = 0, j = 0; i < AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES;){
444     copy_n_frames = template->buffer_size;
445 
446     /* limit nth loop */
447     if(i > template->loop_start &&
448        i + copy_n_frames > template->loop_start + (template->loop_end - template->loop_start) &&
449        i + copy_n_frames < template->loop_start + loop_frame_count &&
450        template->loop_start + ((i - template->loop_start) % (template->loop_end - template->loop_start)) + copy_n_frames >= template->loop_end - template->loop_start){
451       copy_n_frames = template->loop_end - (template->loop_start + ((i - template->loop_start) % (template->loop_end - template->loop_start)));
452     }
453 
454     /* check boundaries */
455     if(i + copy_n_frames > AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES){
456       copy_n_frames = AGS_RECYCLING_TEST_CREATE_AUDIO_SIGNAL_WITH_FRAME_COUNT_FRAMES - i;
457     }
458 
459     if(j + copy_n_frames > template->buffer_size){
460       copy_n_frames = template->buffer_size - j;
461     }
462 
463     /* copy */
464     if(!ags_recycling_test_create_audio_signal_with_frame_count_compare_frames(&(((signed short *) stream->data)[i % audio_signal->buffer_size]),
465 									       entire_buffer + i,
466 									       copy_n_frames)){
467       success = FALSE;
468     }
469 
470     /* increment and iterate */
471     if(j + copy_n_frames == template->buffer_size){
472       template_stream = template_stream->next;
473     }
474 
475     if(i > template->loop_start &&
476        i + copy_n_frames > template->loop_start + (template->loop_end - template->loop_start) &&
477        i + copy_n_frames < template->loop_start + loop_frame_count &&
478        template->loop_start + ((i - template->loop_start) % (template->loop_end - template->loop_start)) + copy_n_frames >= template->loop_end - template->loop_start){
479       j = template->loop_start % template->buffer_size;
480       template_stream = g_list_nth(template->stream,
481 				   floor(template->loop_start / template->buffer_size));
482     }else{
483       j += copy_n_frames;
484     }
485 
486     i += copy_n_frames;
487 
488     if(j == template->buffer_size){
489       j = 0;
490     }
491   }
492 
493   CU_ASSERT(success == TRUE);
494 }
495 
496 void
ags_recycling_test_position()497 ags_recycling_test_position()
498 {
499   AgsRecycling *first_recycling, *last_recycling;
500   AgsRecycling *current;
501   guint i;
502 
503   /* instantiate n recycling */
504   first_recycling = NULL;
505   last_recycling = NULL;
506 
507   for(i = 0; i < AGS_RECYCLING_TEST_POSITION_N_RECYCLING; i++){
508     if(first_recycling == NULL){
509       current = ags_recycling_new(G_OBJECT(devout));
510       first_recycling = current;
511     }else{
512       current->next = ags_recycling_new(G_OBJECT(devout));
513       current->next->prev = current;
514 
515       current = current->next;
516     }
517   }
518 
519   last_recycling = current;
520 
521   /* assert every position */
522   current = first_recycling;
523 
524   for(i = 0; i < AGS_RECYCLING_TEST_POSITION_N_RECYCLING; i++){
525     CU_ASSERT(ags_recycling_position(first_recycling, last_recycling->next,
526 				     current) == i);
527 
528     current = current->next;
529   }
530 }
531 
532 void
ags_recycling_test_find_next_channel()533 ags_recycling_test_find_next_channel()
534 {
535   AgsChannel *start, *end;
536   AgsChannel *channel;
537   AgsRecycling *recycling, *prev_recycling;
538   guint i;
539 
540   /* instantiate n channel and recycling */
541   start = NULL;
542   end = NULL;
543 
544   for(i = 0; i < AGS_RECYCLING_TEST_FIND_NEXT_CHANNEL_N_CHANNEL; i++){
545     if(start == NULL){
546       recycling = ags_recycling_new(G_OBJECT(devout));
547 
548       start =
549 	channel = g_object_new(AGS_TYPE_CHANNEL,
550 			       NULL);
551       channel->last_recycling =
552 	channel->first_recycling = recycling;
553 
554       g_object_set(G_OBJECT(recycling),
555 		   "channel", channel,
556 		   NULL);
557 
558       prev_recycling = recycling;
559     }else{
560       recycling = ags_recycling_new(G_OBJECT(devout));
561 
562       channel->next =
563 	channel->next_pad = g_object_new(AGS_TYPE_CHANNEL,
564 					 NULL);
565       channel->next->last_recycling =
566 	channel->next->first_recycling = recycling;
567 
568       g_object_set(G_OBJECT(recycling),
569 		   "channel", channel->next,
570 		   NULL);
571 
572       channel->next->prev =
573 	channel->next_pad->prev_pad = channel;
574 
575       recycling->prev = prev_recycling;
576       prev_recycling->next = recycling;
577 
578       channel = channel->next;
579       prev_recycling = recycling;
580     }
581   }
582 
583   end = channel;
584 
585   /* assert to find next channel */
586   channel = start;
587   recycling = start->first_recycling;
588 
589   for(i = 0; i + 1 < AGS_RECYCLING_TEST_FIND_NEXT_CHANNEL_N_CHANNEL; i++){
590     CU_ASSERT(ags_recycling_find_next_channel(recycling, NULL,
591 					      channel->prev) == recycling);
592 
593     channel = channel->next;
594     recycling = recycling->next;
595   }
596 }
597 
598 int
main(int argc,char ** argv)599 main(int argc, char **argv)
600 {
601   CU_pSuite pSuite = NULL;
602 
603   putenv("LC_ALL=C");
604   putenv("LANG=C");
605 
606   putenv("LADSPA_PATH=\"\"");
607   putenv("DSSI_PATH=\"\"");
608   putenv("LV2_PATH=\"\"");
609 
610   /* initialize the CUnit test registry */
611   if(CUE_SUCCESS != CU_initialize_registry()){
612     return CU_get_error();
613   }
614 
615   /* add a suite to the registry */
616   pSuite = CU_add_suite("AgsRecyclingTest", ags_recycling_test_init_suite, ags_recycling_test_clean_suite);
617 
618   if(pSuite == NULL){
619     CU_cleanup_registry();
620 
621     return CU_get_error();
622   }
623 
624 #if 0
625   g_log_set_fatal_mask("GLib-GObject",
626   		       G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
627 
628   g_log_set_fatal_mask("Gtk",
629   		       G_LOG_LEVEL_CRITICAL);
630 
631   g_log_set_fatal_mask(NULL,
632   		       G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
633 #endif
634 
635   /* add the tests to the suite */
636   if((CU_add_test(pSuite, "test of AgsRecycling add audio signal", ags_recycling_test_add_audio_signal) == NULL) ||
637      (CU_add_test(pSuite, "test of AgsRecycling remove audio signal", ags_recycling_test_remove_audio_signal) == NULL) ||
638      (CU_add_test(pSuite, "test of AgsRecycling create audio signal with defaults", ags_recycling_test_create_audio_signal_with_defaults) == NULL) ||
639      //FIXME:JK: uncomment
640      /* (CU_add_test(pSuite, "test of AgsRecycling create audio signal with frame count", ags_recycling_test_create_audio_signal_with_frame_count) == NULL) || */
641      (CU_add_test(pSuite, "test of AgsRecycling position", ags_recycling_test_position) == NULL) ||
642      (CU_add_test(pSuite, "test of AgsRecycling find next channel", ags_recycling_test_find_next_channel) == NULL)){
643       CU_cleanup_registry();
644 
645       return CU_get_error();
646     }
647 
648   /* Run all tests using the CUnit Basic interface */
649   CU_basic_set_mode(CU_BRM_VERBOSE);
650   CU_basic_run_tests();
651 
652   CU_cleanup_registry();
653 
654   return(CU_get_error());
655 }
656 
657