1 /*
2  * sample_list_test.c - Tests sample edit lists and virtual sample store
3  *
4  * - Creates double stereo format test waveform with triangle wave in left
5  *   channel and sine wave in right channel
6  * - Re-constructs both channels using 2 sample lists using various list
7  *   operations
8  * - Creates virtual sample store using double stereo format with left
9  *   and right sample lists
10  * - Duplicates virtual sample store to a double stereo format store
11  * - Compares final duplicated store to original waveform and makes sure its
12  *   the same
13  *
14  * libInstPatch
15  * Copyright (C) 1999-2014 Element Green <element@elementsofsound.org>
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public License
19  * as published by the Free Software Foundation; version 2.1
20  * of the License only.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU Lesser General Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30  * 02110-1301, USA or on the web at http://www.gnu.org.
31  */
32 #include <libinstpatch/libinstpatch.h>
33 #include <math.h>
34 
35 #define DEFAULT_AUDIO_SIZE	(32 * 1024)	/* default test waveform size in samples */
36 #define WAVEFORM_PERIOD		1684		/* something to exercise LSB bytes too */
37 #define MAX_DIFF_ALLOWED	0.0		/* maximum difference allowed */
38 
39 #define WAVEFORM_QUARTER	(WAVEFORM_PERIOD / 4)
40 
41 
42 static int test_size = DEFAULT_AUDIO_SIZE;
43 static gboolean verbose = FALSE;
44 
45 static GOptionEntry entries[] =
46 {
47     { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL },
48     { NULL }
49 };
50 
main(int argc,char * argv[])51 int main(int argc, char *argv[])
52 {
53     IpatchSampleStore *store, *vstore, *finstore;
54     IpatchSampleList *rlist, *llist;
55     IpatchSampleData *data, *vdata;
56     double *dwave, *findata;
57     guint periodpos;
58     double d, maxdiff;
59     int i, maxindex;
60     GError *error = NULL;
61     GOptionContext *context;
62     int test_size_q;
63 
64     context = g_option_context_new("- test libInstPatch sample edit list functions");
65     g_option_context_add_main_entries(context, entries, "sample_list_test");
66 
67     if(!g_option_context_parse(context, &argc, &argv, &error))
68     {
69         printf("Failed to parse command line arguments: %s\n",
70                ipatch_gerror_message(error));
71         return 1;
72     }
73 
74     g_option_context_free(context);
75 
76     test_size_q = test_size / 4;	/* test size quarter */
77 
78     ipatch_init();
79 
80     /* allocate audio buffer (double format stereo) */
81     dwave = g_new(double, test_size * 2);	/* ++ alloc */
82 
83     /* generate triangle waveform for left channel and sine wave for right */
84     for(i = 0; i < test_size * 2; i += 2)
85     {
86         periodpos = i % WAVEFORM_PERIOD;
87 
88         if(periodpos <= WAVEFORM_QUARTER)
89         {
90             dwave[i] = periodpos / (double)WAVEFORM_QUARTER;
91         }
92         else if(periodpos <= WAVEFORM_QUARTER * 3)
93         {
94             dwave[i] = -((periodpos - WAVEFORM_QUARTER) / (double)WAVEFORM_QUARTER - 1.0);
95         }
96         else
97         {
98             dwave[i] = (periodpos - WAVEFORM_QUARTER * 3) / (double)WAVEFORM_QUARTER - 1.0;
99         }
100 
101         dwave[i + 1] = sin((periodpos / (double)WAVEFORM_PERIOD) * G_PI * 2.0);
102     }
103 
104     data = ipatch_sample_data_new(test_size);	/* ++ ref */
105 
106     /* ++ ref - create sample store object for original waveform */
107     store = ipatch_sample_store_new(IPATCH_TYPE_SAMPLE_STORE_RAM, data,
108                                     "format", IPATCH_SAMPLE_DOUBLE
109                                     | IPATCH_SAMPLE_STEREO
110                                     | IPATCH_SAMPLE_ENDIAN_HOST,
111                                     "location", dwave,
112                                     "active", TRUE,
113                                     NULL);
114 
115     rlist = ipatch_sample_list_new();
116 
117     /* re-construct right channel in a very inefficient way ;) */
118     ipatch_sample_list_prepend(rlist, store, test_size_q * 2, test_size_q,
119                                IPATCH_SAMPLE_LIST_CHAN_RIGHT);
120     ipatch_sample_list_prepend(rlist, store, 0, test_size_q,
121                                IPATCH_SAMPLE_LIST_CHAN_RIGHT);
122     ipatch_sample_list_insert_index(rlist, 1, store, test_size_q, test_size_q,
123                                     IPATCH_SAMPLE_LIST_CHAN_RIGHT);
124     ipatch_sample_list_append(rlist, store, test_size_q * 3, test_size_q,
125                               IPATCH_SAMPLE_LIST_CHAN_RIGHT);
126     /* cut a segment out which overlaps segments and then re-insert the cut seg */
127     ipatch_sample_list_cut(rlist, test_size_q + test_size_q / 2, test_size_q);
128     ipatch_sample_list_insert(rlist, test_size_q + test_size_q / 2,
129                               store, test_size_q + test_size_q / 2,
130                               test_size_q, IPATCH_SAMPLE_LIST_CHAN_RIGHT);
131 
132     llist = ipatch_sample_list_new();
133 
134     /* have fun with left channel too */
135     ipatch_sample_list_append(llist, store, 0, test_size,
136                               IPATCH_SAMPLE_LIST_CHAN_LEFT);
137     ipatch_sample_list_cut(llist, test_size_q, test_size_q);
138     ipatch_sample_list_insert(llist, test_size_q, store, test_size_q,
139                               test_size_q, IPATCH_SAMPLE_LIST_CHAN_LEFT);
140 
141     vdata = ipatch_sample_data_new(test_size);	/* ++ ref */
142 
143     /* ++ ref - create virtual store from left and right sample lists */
144     vstore = ipatch_sample_store_new(IPATCH_TYPE_SAMPLE_STORE_VIRTUAL, vdata,
145                                      "format", IPATCH_SAMPLE_DOUBLE
146                                      | IPATCH_SAMPLE_STEREO
147                                      | IPATCH_SAMPLE_ENDIAN_HOST,
148                                      NULL);
149     ipatch_sample_store_virtual_set_list(vstore, 0, llist);
150     ipatch_sample_store_virtual_set_list(vstore, 1, rlist);
151     ipatch_sample_store_activate(vstore);
152 
153     /* ++ ref - Duplicate store to render final waveform */
154     finstore = ipatch_sample_store_duplicate(vstore, IPATCH_TYPE_SAMPLE_STORE_RAM,
155                IPATCH_SAMPLE_DOUBLE
156                | IPATCH_SAMPLE_STEREO
157                | IPATCH_SAMPLE_ENDIAN_HOST, &error);
158 
159     if(!finstore)
160     {
161         printf("Failed to create new duplicate sample store: %s",
162                ipatch_gerror_message(error));
163         return 1;
164     }
165 
166     findata = ipatch_sample_store_RAM_get_location(finstore);
167 
168     /* compare final waveform against original */
169     for(i = 0, maxdiff = 0.0, maxindex = 0; i < test_size * 2; i++)
170     {
171         d = dwave[i] - findata[i];
172 
173         if(d < 0.0)
174         {
175             d = -d;
176         }
177 
178         if(d > maxdiff)
179         {
180             maxdiff = d;
181             maxindex = i;
182         }
183     }
184 
185     /* free up objects and data (for memcheck) */
186     g_object_unref(data);
187     g_object_unref(vdata);
188     g_object_unref(store);
189     g_object_unref(vstore);
190     g_object_unref(finstore);
191     g_free(dwave);
192 
193     if(maxdiff > MAX_DIFF_ALLOWED)
194     {
195         printf("Sample list test failed: maxdiff=%0.16f index=%d\n",
196                maxdiff, maxindex);
197         return 1;
198     }
199 
200     if(verbose)
201         printf("Sample list test passed: maxdiff=%0.16f index=%d\n",
202                maxdiff, maxindex);
203     else
204     {
205         printf("Sample list and virtual sample store test passed\n");
206     }
207 
208     return 0;
209 }
210