blob: e3c864c35765cb24d296ba4c4109be058b09448b [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $Id: cmp_wav.c 3553 2011-05-05 06:14:19Z nanang $ */
Tristan Matthews0a329cc2013-07-17 13:20:14 -04002/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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 this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjmedia.h>
21#include <pjlib-util.h>
22#include <pjlib.h>
23#include <stdio.h>
24#include <stdlib.h>
25
26#define app_perror(a,b,c) printf("%s: %s (%d)", a, b, c)
27
28
29/* For logging purpose. */
30#define THIS_FILE "cmp_wav.c"
31#define BYTES_PER_FRAME 512
32
33static const char *desc =
34" FILE \n"
35" \n"
36" cmp_wav.c \n"
37" \n"
38" PURPOSE \n"
39" \n"
40" Compare two WAV files. \n"
41" \n"
42" USAGE \n"
43" \n"
44" cmp_wav ORIGINAL_WAV DEGRADED_WAV [TIME] [DETAIL] \n"
45" \n"
46" ORIGINAL_WAV The original WAV file as reference. \n"
47" DEGRADED_WAV The degraded WAV file. \n"
48" TIME Compare only some part of the files \n"
49" (in ms, since the beginning). \n"
50" Specify 0 (default) to compare the whole time. \n"
51" DETAIL Show detail result, 1 or 0 (default=0, means no)\n"
52" \n"
53" Both files must have same clock rate and must contain \n"
54" uncompressed (i.e. 16bit) PCM. \n";
55
56
57/* Sum of multiplication of corresponding samples in buf1 & buf2 */
58double sum_mult_sig(pj_int16_t *buf1, pj_int16_t *buf2, unsigned nsamples)
59{
60 double mag = 0;
61
62 while (nsamples--)
63 mag += (double)*buf1++ * (double)*buf2++;
64
65 return mag;
66}
67
68
69/*
70 * main()
71 */
72int main(int argc, char *argv[])
73{
74 pj_caching_pool cp;
75 pjmedia_endpt *med_endpt;
76 pj_pool_t *pool;
77 pjmedia_port *file_ori_port;
78 pjmedia_port *file_deg_port;
79 pj_status_t status;
80 unsigned first_nsamples = 0;
81 unsigned samples_compared = 0;
82
83 char buf1[BYTES_PER_FRAME];
84 char buf2[BYTES_PER_FRAME];
85
86 double ref_mag = 0;
87 double deg_mag = 0;
88 double mix_mag = 0;
89
90 int detail = 0;
91 int res_deg, res_mix, res_overall;
92
93 if (argc < 3) {
94 puts("Error: original & degraded filename required");
95 puts(desc);
96 return 1;
97 }
98
99 /* Set log level. */
100 pj_log_set_level(3);
101
102 /* Must init PJLIB first: */
103 status = pj_init();
104 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
105
106 /* Must create a pool factory before we can allocate any memory. */
107 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
108
109 /*
110 * Initialize media endpoint.
111 * This will implicitly initialize PJMEDIA too.
112 */
113 status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
114 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
115
116 /* Create memory pool for our file player */
117 pool = pj_pool_create( &cp.factory, /* pool factory */
118 "wav", /* pool name. */
119 4000, /* init size */
120 4000, /* increment size */
121 NULL /* callback on error */
122 );
123
124 /* Create file media port from the original WAV file */
125 status = pjmedia_wav_player_port_create( pool, /* memory pool */
126 argv[1], /* file to play */
127 40, /* ptime. */
128 PJMEDIA_FILE_NO_LOOP, /* flags */
129 0, /* default buffer */
130 &file_ori_port/* returned port */
131 );
132 if (status != PJ_SUCCESS) {
133 app_perror(THIS_FILE, "Unable to use WAV file", status);
134 return 1;
135 }
136
137 /* Create file media port from the degraded WAV file */
138 status = pjmedia_wav_player_port_create( pool, /* memory pool */
139 argv[2], /* file to play */
140 40, /* ptime. */
141 PJMEDIA_FILE_NO_LOOP, /* flags */
142 0, /* default buffer */
143 &file_deg_port/* returned port */
144 );
145 if (status != PJ_SUCCESS) {
146 app_perror(THIS_FILE, "Unable to use WAV file", status);
147 return 1;
148 }
149
150 if (file_ori_port->info.clock_rate != file_deg_port->info.clock_rate) {
151 app_perror(THIS_FILE, "Clock rates must be same.", PJ_EINVAL);
152 return 1;
153 }
154
155 if (argc > 3)
156 first_nsamples = atoi(argv[3]) * file_ori_port->info.clock_rate / 1000;
157
158 if (argc > 4)
159 detail = atoi(argv[4]);
160
161 while (1) {
162 pjmedia_frame f1, f2;
163
164 f1.buf = buf1;
165 f1.size = BYTES_PER_FRAME;
166 f2.buf = buf2;
167 f2.size = BYTES_PER_FRAME;
168
169 status = pjmedia_port_get_frame(file_ori_port, &f1);
170 if (status == PJ_EEOF) {
171 break;
172 } else if (status != PJ_SUCCESS) {
173 app_perror(THIS_FILE, "Error occured while reading file", status);
174 break;
175 }
176 status = pjmedia_port_get_frame(file_deg_port, &f2);
177 if (status == PJ_EEOF) {
178 break;
179 } else if (status != PJ_SUCCESS) {
180 app_perror(THIS_FILE, "Error occured while reading file", status);
181 break;
182 }
183
184 /* Calculate magnitudes */
185 ref_mag += sum_mult_sig(f1.buf, f1.buf, BYTES_PER_FRAME >> 1);
186 deg_mag += sum_mult_sig(f2.buf, f2.buf, BYTES_PER_FRAME >> 1);
187 mix_mag += sum_mult_sig(f1.buf, f2.buf, BYTES_PER_FRAME >> 1);
188
189 samples_compared += BYTES_PER_FRAME >> 1;
190 if (first_nsamples && samples_compared >= first_nsamples)
191 break;
192 }
193
194 /* Degraded magnitude compared to reference magnitude
195 */
196 res_deg = (int) (deg_mag / ref_mag * 100.0);
197 if (res_deg < 0)
198 res_deg = -1;
199 else if (res_deg >= 81)
200 res_deg = 9;
201 else
202 res_deg = pj_isqrt(res_deg);
203
204 /* Mixed magnitude (don't know what this is actually :D) compared to
205 * reference magnitude
206 */
207 res_mix = (int) (mix_mag / ref_mag * 100.0);
208 if (res_mix < 0)
209 res_mix = -1;
210 else if (res_mix >= 81)
211 res_mix = 9;
212 else
213 res_mix = pj_isqrt(res_mix);
214
215 /* Overall score.
216 * If mixed score is -1, then overall score should be -1 as well.
217 * Apply no weighting (1:1) for now.
218 */
219 if (res_mix == -1)
220 res_overall = -1;
221 else
222 res_overall = (res_mix*1 + res_deg*1) / 2;
223
224 if (detail) {
225 printf("Reference = %.0f\n", ref_mag);
226 printf("Degraded = %.0f\n", deg_mag);
227 printf("Mixed = %.0f\n", mix_mag);
228
229 printf("\n");
230
231 printf("Score 1 = %d\n", res_deg);
232 printf("Score 2 = %d\n", res_mix);
233
234 printf("\n");
235 }
236
237 printf("Overall = %d\n", res_overall);
238
239 /* Destroy file port */
240 status = pjmedia_port_destroy( file_ori_port );
241 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
242
243 status = pjmedia_port_destroy( file_deg_port );
244 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
245
246 /* Release application pool */
247 pj_pool_release( pool );
248
249 /* Destroy media endpoint. */
250 pjmedia_endpt_destroy( med_endpt );
251
252 /* Destroy pool factory */
253 pj_caching_pool_destroy( &cp );
254
255 /* Shutdown PJLIB */
256 pj_shutdown();
257
258
259 /* Done. */
260 return 0;
261}
262