Switch iteration over channels to the do{}while(); construct in order to inform the...
[opus.git] / tests / tandem-test.c
1 /* (C) 2009 Gregory Maxwell
2
3    This test runs pink noise through the encoder and decoder many times 
4    while feeding the output back into the input. It checks that after
5    a number of cycles the energy has not increased or decreased by too
6    large an amount.
7
8    Redistribution and use in source and binary forms, with or without
9    modification, are permitted provided that the following conditions
10    are met:
11    
12    - Redistributions of source code must retain the above copyright
13    notice, this list of conditions and the following disclaimer.
14    
15    - Redistributions in binary form must reproduce the above copyright
16    notice, this list of conditions and the following disclaimer in the
17    documentation and/or other materials provided with the distribution.
18    
19    - Neither the name of the Xiph.org Foundation nor the names of its
20    contributors may be used to endorse or promote products derived from
21    this software without specific prior written permission.
22    
23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
27    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "celt.h"
41 #include "arch.h"
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <sys/types.h>
45 #include <time.h>
46 #include <unistd.h>
47 #include <math.h>
48 #include <string.h>
49
50
51 int async_tandem(int rate, int frame_size, int channels, int bitrate_min,
52                  int bitrate_max)
53 {
54     int error;
55     unsigned char data[648];
56     CELTMode *mode = NULL;
57     CELTEncoder *enc;
58     short carry[2];
59     short pcm[960 * 2];
60     CELTDecoder *dec;
61     int bmin, bmax;
62     float ms;
63     int ret, i, j, bytes_per_frame;
64     int increment = 1;
65
66     bmin = floor((bitrate_min / (rate / (float) frame_size)) / 8.0);
67     bmax = ceil((bitrate_max / (rate / (float) frame_size)) / 8.0);
68     if (bmin < 8)
69         bmin = 8;
70     if (bmax > 640)
71         bmax = 640;
72     if (bmin >= bmax)
73         bmax = bmin + 8;
74
75     increment += (bmax - bmin) / 128; 
76
77     printf ("Testing asynchronous tandeming (%dHz, %dch, %d samples, %d - %d bytes).\n",
78          rate, channels, frame_size, bmin, bmax);
79
80     mode = celt_mode_create(rate, frame_size, &error);
81     if (mode == NULL || error) {
82         fprintf(stderr, "Error: failed to create a mode: %s\n", celt_strerror(error));
83         exit(1);
84     }
85
86     dec = celt_decoder_create(mode, channels, &error);
87     if (error){
88       fprintf(stderr, "Error: celt_decoder_create returned %s\n", celt_strerror(error));
89       exit(1);
90     }
91     enc = celt_encoder_create(mode, channels, &error);
92     if (error){
93       fprintf(stderr, "Error: celt_encoder_create returned %s\n", celt_strerror(error));
94       exit(1);
95     }
96
97     for (j = 0; j < frame_size * channels; j++)
98         pcm[j] = 0;
99
100     for (bytes_per_frame = bmin; bytes_per_frame <= bmax;
101          bytes_per_frame += increment) {
102         /*Prime the encoder and decoder */
103         for (i = 0; i < (1024 + (frame_size >> 1)) / frame_size + 2; i++) {
104
105             for (j = 0; j < channels; j++)
106                 pcm[j] = pcm[frame_size * channels - (channels - j + 1)];
107             for (j = channels; j < frame_size * channels - 1; j++)
108                 pcm[j] = ((rand() % 4096) - 2048) + .9 * pcm[j - channels];
109
110             ret = celt_encode(enc, pcm, frame_size, data, bytes_per_frame);
111             if (ret != bytes_per_frame) {
112                 fprintf(stderr, "Error: celt_encode returned %s\n", celt_strerror(ret));
113                 exit(1);
114             }
115
116             ret = celt_decode(dec, data, ret, pcm, frame_size);
117             if (ret != CELT_OK) {
118                 fprintf(stderr, "Error: celt_decode returned %s\n", celt_strerror(ret));
119             }
120         }
121
122         for (j = 0; j < channels; j++)
123             pcm[j] = pcm[frame_size * channels - (channels - j)];
124         for (j = channels; j < frame_size * channels - 1; j++)
125             pcm[j] = ((rand() % 4096) - 2048) + .9 * pcm[j - channels];
126
127         for (i = 0; i < 8; i++) {
128             for (j = 0; j < channels; j++)
129                 carry[j] = pcm[frame_size * channels - (channels - j)];
130             memmove(pcm + channels, pcm, sizeof(short) * frame_size * channels);
131             for (j = 0; j < channels; j++)
132                 pcm[j] = carry[j];
133
134             ret = celt_encode(enc, pcm, frame_size, data, bytes_per_frame);
135             if (ret != bytes_per_frame) {
136                 fprintf(stderr, "Error: at %d bytes_per_frame celt_encode returned %s\n",
137                         bytes_per_frame, celt_strerror(ret));
138                 exit(1);
139             }
140
141             ret = celt_decode(dec, data, ret, pcm, frame_size);
142             if (ret != CELT_OK) {
143                 fprintf(stderr, "Error: at %d bytes_per_frame celt_decode returned %s\n",
144                         bytes_per_frame, celt_strerror(ret));
145                 exit(1);
146             }
147         }
148         ms = 0;
149         for (j = 0; j < frame_size * channels; j++)
150             ms += pcm[j] * pcm[j];
151         ms = sqrt(ms / (frame_size * channels));
152         if (ms > 7000 || ms < 1000) {
153             fprintf(stderr, "Error: Signal out of expected range. %d %d %d %d %f\n",
154                     rate, channels, frame_size, bytes_per_frame, ms);
155             exit(1);
156         }
157     }
158
159     celt_encoder_destroy(enc);
160     celt_decoder_destroy(dec);
161     celt_mode_destroy(mode);
162
163     return 0;
164 }
165
166 int main(int argc, char *argv[])
167 {
168     int sizes[8]={960,480,240,120,512,256,128,64};
169     unsigned int seed;
170     int ch, n;
171
172     if (argc > 2) {
173         fprintf(stderr, "Usage: %s [<seed>]\n", argv[0]);
174         return 1;
175     }
176
177     if (argc > 1)
178         seed = atoi(argv[1]);
179     else
180         seed = (time(NULL) ^ ((getpid() % 65536) << 16));
181
182     srand(seed);
183     printf("CELT codec tests. Random seed: %u (%.4X)\n", seed, rand() % 65536);
184
185     for (n = 0; n < 8; n++) {
186         for (ch = 1; ch <= 2; ch++) {
187             async_tandem(48000, sizes[n], ch, 12000 * ch, 128000 * ch);
188             async_tandem(44100, sizes[n], ch, 12000 * ch, 128000 * ch);
189             async_tandem(32000, sizes[n], ch, 12000 * ch, 128000 * ch);
190             async_tandem(16000, sizes[n], ch, 12000 * ch, 64000 * ch);
191         }
192     }
193
194     return 0;
195 }