1
/* $Id: cmp_wav.c 3553 2011-05-05 06:14:19Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
21
#include <pjlib-util.h>
26
#define app_perror(a,b,c) printf("%s: %s (%d)", a, b, c)
29
/* For logging purpose. */
30
#define THIS_FILE "cmp_wav.c"
31
#define BYTES_PER_FRAME 512
33
static const char *desc =
40
" Compare two WAV files. \n"
44
" cmp_wav ORIGINAL_WAV DEGRADED_WAV [TIME] [DETAIL] \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"
53
" Both files must have same clock rate and must contain \n"
54
" uncompressed (i.e. 16bit) PCM. \n";
57
/* Sum of multiplication of corresponding samples in buf1 & buf2 */
58
double sum_mult_sig(pj_int16_t *buf1, pj_int16_t *buf2, unsigned nsamples)
63
mag += (double)*buf1++ * (double)*buf2++;
72
int main(int argc, char *argv[])
75
pjmedia_endpt *med_endpt;
77
pjmedia_port *file_ori_port;
78
pjmedia_port *file_deg_port;
80
unsigned first_nsamples = 0;
81
unsigned samples_compared = 0;
83
char buf1[BYTES_PER_FRAME];
84
char buf2[BYTES_PER_FRAME];
91
int res_deg, res_mix, res_overall;
94
puts("Error: original & degraded filename required");
102
/* Must init PJLIB first: */
104
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
106
/* Must create a pool factory before we can allocate any memory. */
107
pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
110
* Initialize media endpoint.
111
* This will implicitly initialize PJMEDIA too.
113
status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
114
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
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 */
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 */
128
PJMEDIA_FILE_NO_LOOP, /* flags */
129
0, /* default buffer */
130
&file_ori_port/* returned port */
132
if (status != PJ_SUCCESS) {
133
app_perror(THIS_FILE, "Unable to use WAV file", status);
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 */
141
PJMEDIA_FILE_NO_LOOP, /* flags */
142
0, /* default buffer */
143
&file_deg_port/* returned port */
145
if (status != PJ_SUCCESS) {
146
app_perror(THIS_FILE, "Unable to use WAV file", status);
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);
156
first_nsamples = atoi(argv[3]) * file_ori_port->info.clock_rate / 1000;
159
detail = atoi(argv[4]);
162
pjmedia_frame f1, f2;
165
f1.size = BYTES_PER_FRAME;
167
f2.size = BYTES_PER_FRAME;
169
status = pjmedia_port_get_frame(file_ori_port, &f1);
170
if (status == PJ_EEOF) {
172
} else if (status != PJ_SUCCESS) {
173
app_perror(THIS_FILE, "Error occured while reading file", status);
176
status = pjmedia_port_get_frame(file_deg_port, &f2);
177
if (status == PJ_EEOF) {
179
} else if (status != PJ_SUCCESS) {
180
app_perror(THIS_FILE, "Error occured while reading file", status);
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);
189
samples_compared += BYTES_PER_FRAME >> 1;
190
if (first_nsamples && samples_compared >= first_nsamples)
194
/* Degraded magnitude compared to reference magnitude
196
res_deg = (int) (deg_mag / ref_mag * 100.0);
199
else if (res_deg >= 81)
202
res_deg = pj_isqrt(res_deg);
204
/* Mixed magnitude (don't know what this is actually :D) compared to
205
* reference magnitude
207
res_mix = (int) (mix_mag / ref_mag * 100.0);
210
else if (res_mix >= 81)
213
res_mix = pj_isqrt(res_mix);
216
* If mixed score is -1, then overall score should be -1 as well.
217
* Apply no weighting (1:1) for now.
222
res_overall = (res_mix*1 + res_deg*1) / 2;
225
printf("Reference = %.0f\n", ref_mag);
226
printf("Degraded = %.0f\n", deg_mag);
227
printf("Mixed = %.0f\n", mix_mag);
231
printf("Score 1 = %d\n", res_deg);
232
printf("Score 2 = %d\n", res_mix);
237
printf("Overall = %d\n", res_overall);
239
/* Destroy file port */
240
status = pjmedia_port_destroy( file_ori_port );
241
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
243
status = pjmedia_port_destroy( file_deg_port );
244
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
246
/* Release application pool */
247
pj_pool_release( pool );
249
/* Destroy media endpoint. */
250
pjmedia_endpt_destroy( med_endpt );
252
/* Destroy pool factory */
253
pj_caching_pool_destroy( &cp );