00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 #include <stdarg.h>
00013 #include <string.h>
00014 #include <assert.h>
00015 #include <float.h>
00016 #include <errno.h>
00017 #include <math.h>
00018 #include <locale.h>
00019
00020 #include <vector>
00021 #include <algorithm>
00022
00023 #include "bsapi.h"
00024 #include "getopt.h"
00025
00026 #ifdef WIN32
00027 #define DIRSEP "\\"
00028 #else
00029 #define DIRSEP "/"
00030 #endif
00031
00032
00033 #define SID_LOCALE "C" // use "" for environment's default locale
00034 #define SID_MIN_LEN_TO_PROCESS 3.0f // in seconds
00035 #define SID_BELOW_MIN_LEN_TEXT "(too short)"
00036 #define SID_OUT_COLUMN_CHARS "snkl"
00037
00038
00039 #define SID_DEF_VPRINT_EXT "vp"
00040 #define SID_DEF_SCORE_SHARPNESS 1.0f
00041 #define SID_DEF_ADAPT_CONST 1.0f
00042
00043 inline float GetSpeechLengthSec(SVoicePrintI *pVoicePrint)
00044 {
00045 return pVoicePrint->GetNFrames() / 100.0f;
00046 }
00047
00048 inline bool IsTooShort(SVoicePrintI *pVoicePrint)
00049 {
00050 return (GetSpeechLengthSec(pVoicePrint) < SID_MIN_LEN_TO_PROCESS);
00051 }
00052
00053 inline float RescaleScore(float score, float scale = 1.0f)
00054 {
00055 return (100.0f / (1.0f + expf(-(scale * score))));
00056 }
00057
00058
00059
00060
00061 class ErrorHandler : public SErrorCallbackI
00062 {
00063 public:
00064 ErrorHandler() : mVerbose(false) {;}
00065 virtual void BSAPI_METHOD OnTextMessage(SUnknownI *pSender, message_type type, unsigned int messageId, const char *pMessage)
00066 {
00067 unsigned int iid = pSender ? pSender->GetIID() : SIID_UNDEFINED;
00068 switch(type)
00069 {
00070 case mtError:
00071 fprintf(stderr, "ERROR: %s - %s\n", BSAPIInterfaceId2Text(iid), pMessage);
00072 break;
00073 case mtWarning:
00074 fprintf(stderr, "WARNING: %s - %s\n", BSAPIInterfaceId2Text(iid), pMessage);
00075 break;
00076 case mtLog:
00077 LogMessage(pMessage);
00078 break;
00079 }
00080 }
00081
00082 void LogMessage(const char *pMessage, ...)
00083 {
00084 if (mVerbose)
00085 {
00086 va_list ap;
00087 va_start(ap, pMessage);
00088 vfprintf(stderr, pMessage, ap);
00089 fprintf(stderr, "\n");
00090 va_end(ap);
00091 }
00092 }
00093
00094 void SetVerbose(bool verbose) {mVerbose = verbose;}
00095
00096 protected:
00097 bool mVerbose;
00098 } gErrorHandler;
00099
00100 class ScoreSorter
00101 {
00102 public:
00103 ScoreSorter() : mpScores(0), mpSet(0), mSuppressTooShort(false) {}
00104
00105 void SetScores(float *pScores, size_t length)
00106 {
00107 mpScores = pScores;
00108
00109 mIndices.resize(length);
00110 for (size_t i = 0; i < mIndices.size(); i++)
00111 mIndices[i] = i;
00112 }
00113
00114 void SetVoicePrints(SVoicePrintSetI *pSet, bool suppressTooShort)
00115 {
00116 mpSet = pSet;
00117 mSuppressTooShort = suppressTooShort;
00118 }
00119
00120 void Sort()
00121 {
00122 sort(mIndices.begin(), mIndices.end(), *this);
00123 }
00124
00125 int GetIndex(int nthBest) const
00126 {
00127 return mIndices[nthBest];
00128 }
00129
00130 bool operator() (int i, int j)
00131 {
00132 assert(mpScores != 0 && mpSet != 0);
00133 float score1 = (IsTooShort(mpSet->GetByIndex(i)) && !mSuppressTooShort) ? -FLT_MAX : mpScores[i];
00134 float score2 = (IsTooShort(mpSet->GetByIndex(j)) && !mSuppressTooShort) ? -FLT_MAX : mpScores[j];
00135 return (score1 > score2);
00136 }
00137
00138 private:
00139 std::vector<int> mIndices;
00140 float *mpScores;
00141 SVoicePrintSetI *mpSet;
00142 bool mSuppressTooShort;
00143 };
00144
00145 void help()
00146 {
00147 puts("\n Voice-print comparator ");
00148 printf(" %s\n", BSAPIVersion());
00149 puts(" ===================================================================== ");
00150 puts(" ");
00151 puts(" USAGE: vpcompare [options] input1 [input2] ");
00152 puts(" ");
00153 puts(" system configuration: ");
00154 puts(" -c file configuration file ");
00155 puts(" -m dir model directory ");
00156 puts(" -v verbose mode ");
00157 puts(" ");
00158 puts(" comparison mode: ");
00159 puts(" input: ");
00160 puts(" -f compare two voice-print files ");
00161 puts(" -l compare two lists of voice-print files ");
00162 puts(" -d compare two directories of voice-print files ");
00163 puts(" -e str [vp] extension of voice-print file ");
00164 puts(" ");
00165 puts(" output: ");
00166 puts(" -o file output score file ");
00167 puts(" -n dump voice-print file names to the score file ");
00168 puts(" -u suppress the 'too short' output ");
00169 puts(" -k columns enable column output format (see columns) ");
00170 puts(" -b num for each voice-print from input1 dump only N ");
00171 puts(" best scores from input2 ");
00172 puts(" -t num for each voice-print from input1 dump only scores");
00173 puts(" from input2 which are greater than threshold ");
00174 puts(" -z num [1.0] score sharpness (positive number) ");
00175 puts(" ");
00176 puts(" columns: (columns to print are specified by string of ");
00177 puts(" the characters below, e.g. lsn) ");
00178 puts(" s raw score ");
00179 puts(" n score normalized to <0, 100> ");
00180 puts(" k speech length of input1 voice-print ");
00181 puts(" l speech length of input2 voice-print ");
00182 puts(" ");
00183 puts(" training mode (enabled by option -g): ");
00184 puts(" -x use counts (of voice-prints) for adaptation ");
00185 puts(" -a num [1.0] adaptation constant <0.0, 1.0> ");
00186 puts(" 0.0 ... old models are used only ");
00187 puts(" 1.0 ... new models are used only ");
00188 puts(" input: ");
00189 puts(" -l train from two-column list file; speaker name in ");
00190 puts(" first column, voice-print file in second column ");
00191 puts(" -d train from directory with subdirectories each ");
00192 puts(" corresponding to a single speaker ");
00193 puts(" -e str [vp] extension of voice-print file ");
00194 puts(" ");
00195 puts(" output: ");
00196 puts(" -g dir output model directory ");
00197 puts(" ");
00198 puts(" example: ");
00199 puts(" vpcompare -c settings/compare -f file1.vp file2.vp ");
00200 puts(" vpcompare -c settings/compare -l -o score.txt list1.txt list2.txt ");
00201 puts(" vpcompare -c settings/compare -d -e 'vp' -o score.txt dir1 dir2 ");
00202 puts(" vpcompare -c settings/compare -d -e 'vp' -g models dir1 ");
00203 puts(" ");
00204 }
00205
00206 void DumpColWiseLine(FILE *pFileHandle, float score, SVoicePrintI *pVoicePrint1, SVoicePrintI *pVoicePrint2,
00207 const char *pColumnFmt, float sharpness, bool suppressTooShort)
00208 {
00209 fprintf(pFileHandle, "%s\t%s", pVoicePrint1->GetSegmentId(), pVoicePrint2->GetSegmentId());
00210 for (const char *pc = pColumnFmt; *pc != '\0'; pc++)
00211 {
00212 switch (*pc)
00213 {
00214 case 's':
00215 if ((IsTooShort(pVoicePrint1) || IsTooShort(pVoicePrint2)) && !suppressTooShort)
00216 fprintf(pFileHandle, "\t-inf");
00217 else
00218 fprintf(pFileHandle, "\t%.3f", score);
00219 break;
00220
00221 case 'n':
00222 if ((IsTooShort(pVoicePrint1) || IsTooShort(pVoicePrint2)) && !suppressTooShort)
00223 fprintf(pFileHandle, "\t0.000");
00224 else
00225 fprintf(pFileHandle, "\t%.3f", RescaleScore(score, sharpness));
00226 break;
00227
00228 case 'k':
00229 fprintf(pFileHandle, "\t%.3f", GetSpeechLengthSec(pVoicePrint1));
00230 break;
00231
00232 case 'l':
00233 fprintf(pFileHandle, "\t%.3f", GetSpeechLengthSec(pVoicePrint2));
00234 break;
00235 }
00236 }
00237
00238 if ((IsTooShort(pVoicePrint1) || IsTooShort(pVoicePrint2)) && !suppressTooShort)
00239 fprintf(pFileHandle, "\t%s", SID_BELOW_MIN_LEN_TEXT);
00240
00241 fprintf(pFileHandle, "\n");
00242 }
00243
00244 void DumpColWiseNBest(FILE *pFileHandle, SFloatMatrixI *pScores, SVoicePrintSetI *pSet1, SVoicePrintSetI *pSet2,
00245 const char *pColumnFmt, float sharpness, bool suppressTooShort, int nBest)
00246 {
00247 ScoreSorter score_sorter;
00248
00249 for (int i = 0; i < pSet1->GetNVoicePrints(); i++)
00250 {
00251 int nscores = pScores->GetNColumns();
00252 float *pscores = pScores->GetRowMem(i);
00253 score_sorter.SetScores(pscores, nscores);
00254 score_sorter.SetVoicePrints(pSet2, suppressTooShort);
00255 score_sorter.Sort();
00256 SVoicePrintI *pvoice_print1 = pSet1->GetByIndex(i);
00257 for (int j = 0; j < std::min(nBest, nscores); j++)
00258 {
00259 int index = score_sorter.GetIndex(j);
00260 DumpColWiseLine(pFileHandle, pscores[index], pvoice_print1, pSet2->GetByIndex(index),
00261 pColumnFmt, sharpness, suppressTooShort);
00262 }
00263 }
00264 }
00265
00266 void DumpColWiseBest(FILE *pFileHandle, SFloatMatrixI *pScores, SVoicePrintSetI *pSet1, SVoicePrintSetI *pSet2,
00267 const char *pColumnFmt, float sharpness, bool suppressTooShort)
00268 {
00269 for (int i = 0; i < pSet1->GetNVoicePrints(); i++)
00270 {
00271 assert(pSet2->GetNVoicePrints() > 0);
00272
00273 float best_score = -FLT_MAX;
00274 SVoicePrintI *pbest_vprint = 0;
00275 float *pscores = pScores->GetRowMem(i);
00276 for (int j = 0; j < pSet2->GetNVoicePrints(); j++)
00277 {
00278 if ((pscores[j] > best_score) &&
00279 ((!IsTooShort(pSet1->GetByIndex(i)) && !IsTooShort(pSet2->GetByIndex(j))) || suppressTooShort))
00280 {
00281 best_score = pScores->Get(i, j);
00282 pbest_vprint = pSet2->GetByIndex(j);
00283 }
00284 }
00285
00286 DumpColWiseLine(pFileHandle, best_score, pSet1->GetByIndex(i), pbest_vprint ? pbest_vprint : pSet2->GetByIndex(0),
00287 pColumnFmt, sharpness, suppressTooShort);
00288 }
00289 }
00290
00291 void DumpColWiseThr(FILE *pFileHandle, SFloatMatrixI *pScores, SVoicePrintSetI *pSet1, SVoicePrintSetI *pSet2,
00292 const char *pColumnFmt, float sharpness, bool suppressTooShort, float scoreThreshold)
00293 {
00294 for (int i = 0; i < pSet1->GetNVoicePrints(); i++)
00295 {
00296 float *pscores = pScores->GetRowMem(i);
00297 SVoicePrintI *pvoice_print1 = pSet1->GetByIndex(i);
00298 for (int j = 0; j < pSet2->GetNVoicePrints(); j++)
00299 {
00300 if ((RescaleScore(pscores[j], sharpness) >= scoreThreshold) &&
00301 ((!IsTooShort(pvoice_print1) && !IsTooShort(pSet2->GetByIndex(j))) || suppressTooShort))
00302 {
00303 DumpColWiseLine(pFileHandle, pscores[j], pvoice_print1, pSet2->GetByIndex(j),
00304 pColumnFmt, sharpness, suppressTooShort);
00305 }
00306 }
00307 }
00308 }
00309
00310 void DumpColWise(FILE *pFileHandle, SFloatMatrixI *pScores, SVoicePrintSetI *pSet1, SVoicePrintSetI *pSet2,
00311 const char *pColumnFmt, float sharpness, bool suppressTooShort)
00312 {
00313 for (int i = 0; i < pSet1->GetNVoicePrints(); i++)
00314 {
00315 float *pscores = pScores->GetRowMem(i);
00316 SVoicePrintI *pvoice_print1 = pSet1->GetByIndex(i);
00317 for (int j = 0; j < pSet2->GetNVoicePrints(); j++)
00318 {
00319 DumpColWiseLine(pFileHandle, pscores[j], pvoice_print1, pSet2->GetByIndex(j),
00320 pColumnFmt, sharpness, suppressTooShort);
00321 }
00322 }
00323 }
00324
00325 void DumpRowWise(FILE *pFileHandle, SFloatMatrixI *pScores, SVoicePrintSetI *pSet1, SVoicePrintSetI *pSet2,
00326 bool dumpNames, bool suppressTooShort)
00327 {
00328 if(dumpNames)
00329 {
00330 for(int i = 0; i < pSet2->GetNVoicePrints(); i++)
00331 fprintf(pFileHandle, "\t%s", pSet2->GetByIndex(i)->GetSegmentId());
00332 fprintf(pFileHandle, "\n");
00333 }
00334
00335 bool too_short2 = false;
00336 float *prow = pScores->GetMem();
00337 for(int i = 0; i < pSet1->GetNVoicePrints(); i++)
00338 {
00339 if(dumpNames)
00340 fprintf(pFileHandle, "%s\t", pSet1->GetByIndex(i)->GetSegmentId());
00341 for(int j = 0; j < pSet2->GetNVoicePrints(); j++)
00342 {
00343 if(IsTooShort(pSet2->GetByIndex(j)))
00344 too_short2 = true;
00345 if(j != 0)
00346 fprintf(pFileHandle, "\t");
00347 if((IsTooShort(pSet1->GetByIndex(i)) || IsTooShort(pSet2->GetByIndex(j))) && !suppressTooShort)
00348 fprintf(pFileHandle, "-inf");
00349 else
00350 fprintf(pFileHandle, "%e", prow[j]);
00351 }
00352 if (IsTooShort(pSet1->GetByIndex(i)) && !suppressTooShort)
00353 fprintf(pFileHandle, "\t%s", SID_BELOW_MIN_LEN_TEXT);
00354 fprintf(pFileHandle, "\n");
00355 prow += pScores->GetStride();
00356 }
00357
00358 if(too_short2 && !suppressTooShort)
00359 {
00360 if(dumpNames)
00361 fprintf(pFileHandle, "\t");
00362 for(int i = 0; i < pSet2->GetNVoicePrints(); i++)
00363 {
00364 if(i != 0)
00365 fprintf(pFileHandle, "\t");
00366 if(IsTooShort(pSet2->GetByIndex(i)))
00367 fprintf(pFileHandle, "%s", SID_BELOW_MIN_LEN_TEXT);
00368 }
00369 fprintf(pFileHandle, "\n");
00370 }
00371 }
00372
00373 bool SaveScores(const char *pFile, SFloatMatrixI *pScores, SVoicePrintSetI *pSet1, SVoicePrintSetI *pSet2,
00374 const char *pColumnFmt, float sharpness, int nBestScores, float scoreThreshold, bool dumpNames, bool suppressTooShort)
00375 {
00376 assert(pScores->GetNRows() == pSet1->GetNVoicePrints() && pScores->GetNColumns() == pSet2->GetNVoicePrints());
00377
00378 setlocale(LC_ALL, SID_LOCALE);
00379
00380 FILE *pf = fopen(pFile, "w");
00381 if (!pf)
00382 {
00383 fprintf(stderr, "ERROR: Can not create '%s'.\n", pFile);
00384 return false;
00385 }
00386
00387 switch (nBestScores)
00388 {
00389 case 0:
00390 if (scoreThreshold > 0.0f)
00391 DumpColWiseThr(pf, pScores, pSet1, pSet2, (pColumnFmt ? pColumnFmt : "n"), sharpness, suppressTooShort, scoreThreshold);
00392 else if (pColumnFmt)
00393 DumpColWise(pf, pScores, pSet1, pSet2, pColumnFmt, sharpness, suppressTooShort);
00394 else
00395 DumpRowWise(pf, pScores, pSet1, pSet2, dumpNames, suppressTooShort);
00396 break;
00397
00398 case 1:
00399 DumpColWiseBest(pf, pScores, pSet1, pSet2, (pColumnFmt ? pColumnFmt : "n"), sharpness, suppressTooShort);
00400 break;
00401
00402 default:
00403 DumpColWiseNBest(pf, pScores, pSet1, pSet2, (pColumnFmt ? pColumnFmt : "n"), sharpness, suppressTooShort, nBestScores);
00404 break;
00405 }
00406
00407 fclose(pf);
00408 return true;
00409 }
00410
00411 int main(int argc, char *argv[])
00412 {
00413
00414 const char *pconfig_file = "settings/compare.bs";
00415 const char *pinput1 = 0;
00416 const char *pinput2 = 0;
00417 const char *pvprint_ext = SID_DEF_VPRINT_EXT;
00418 const char *poutput_file = 0;
00419 const char *pcolumn_fmt = 0;
00420 const char *pmodel_dir = 0;
00421 const char *pout_model_dir = 0;
00422 bool process_files = false;
00423 bool process_lists = false;
00424 bool process_dirs = false;
00425 int nbest_scores = 0;
00426 float score_thr = 0.0f;
00427 bool dump_names = false;
00428 bool supp_too_short = false;
00429 float sharpness = SID_DEF_SCORE_SHARPNESS;
00430 float adapt_const = SID_DEF_ADAPT_CONST;
00431 bool use_counts = false;
00432
00433
00434 if(argc == 1)
00435 {
00436 help();
00437 return 0;
00438 }
00439
00440 optind = 0;
00441 while (1)
00442 {
00443 int c = getopt(argc, argv, const_cast<char *>("c:uvflde:o:nk:t:z:b:m:g:a:x"));
00444 if(c == -1)
00445 break;
00446
00447 switch(c)
00448 {
00449 case 'c':
00450 pconfig_file = optarg;
00451 break;
00452 case 'm':
00453 pmodel_dir = optarg;
00454 break;
00455 case 'g':
00456 pout_model_dir = optarg;
00457 break;
00458 case 'o':
00459 poutput_file = optarg;
00460 break;
00461 case 'l':
00462 process_lists = true;
00463 break;
00464 case 'd':
00465 process_dirs = true;
00466 break;
00467 case 'f':
00468 process_files = true;
00469 break;
00470 case 'e':
00471 pvprint_ext = optarg;
00472 break;
00473 case 'n':
00474 dump_names = true;
00475 break;
00476 case 'u':
00477 supp_too_short = true;
00478 break;
00479 case 'x':
00480 use_counts = true;
00481 break;
00482 case 'b':
00483 if(sscanf(optarg, "%d", &nbest_scores) != 1 || nbest_scores < 0)
00484 {
00485 fprintf(stderr, "ERROR: Invalid number of best scores to print '%s'. "
00486 "Must be positive integer.\n", optarg);
00487 return 1;
00488 }
00489 break;
00490 case 't':
00491 if(sscanf(optarg, "%f", &score_thr) != 1 || score_thr < 0.0f || score_thr > 100.0f)
00492 {
00493 fprintf(stderr, "ERROR: Wrong value of score threshold '%s'. Must be number in <0,100>.\n", optarg);
00494 return 1;
00495 }
00496 break;
00497 case 'k':
00498 pcolumn_fmt = optarg;
00499 if (strspn(pcolumn_fmt, SID_OUT_COLUMN_CHARS) != strlen(pcolumn_fmt))
00500 {
00501 fprintf(stderr, "ERROR: Wrong format of output columns string. "
00502 "The set of allowed characters is '%s'.\n", SID_OUT_COLUMN_CHARS);
00503 return 1;
00504 }
00505 break;
00506 case 'z':
00507 if(sscanf(optarg, "%f", &sharpness) != 1 || sharpness < 0.0f)
00508 {
00509 fprintf(stderr, "ERROR: Wrong value of score sharpness '%s'. Must be positive number.\n", optarg);
00510 return 1;
00511 }
00512 break;
00513 case 'a':
00514 if(sscanf(optarg, "%f", &adapt_const) != 1 || adapt_const < 0.0f || adapt_const > 1.0f)
00515 {
00516 fprintf(stderr, "ERROR: Wrong value of adaptation constant '%s'. Must be number in <0.0, 1.0>.\n", optarg);
00517 return 1;
00518 }
00519 break;
00520 case 'v':
00521 gErrorHandler.SetVerbose(true);
00522 break;
00523 case 1:
00524 if(!pinput1)
00525 {
00526 pinput1 = optarg;
00527 }
00528 else if(!pinput2)
00529 {
00530 pinput2 = optarg;
00531 }
00532 else
00533 {
00534 fprintf(stderr, "ERROR: Only two files, lists or directories can be compared at the same time.\n");
00535 return 1;
00536 }
00537 break;
00538 case '?':
00539 fprintf(stderr, "ERROR: Command line parsing error.\n");
00540 return 1;
00541 default :
00542 fprintf(stderr, "ERROR: Command line parsing error. Unexpected argument '%s'.\n", optarg);
00543 return 1;
00544 }
00545 }
00546
00547
00548 if((process_files && process_dirs) || (process_files && process_lists) || (process_lists && process_dirs))
00549 {
00550 fprintf(stderr, "ERROR: Only one of -f, -l, -d options can be used at the same time.\n");
00551 return 1;
00552 }
00553
00554 if(!pinput1 || (!pout_model_dir && !pinput2))
00555 {
00556 fprintf(stderr, "ERROR: Missing input. Two inputs should be specified for comparison mode and one input for training mode.\n");
00557 return 1;
00558 }
00559
00560 if(!process_dirs && !process_lists && pout_model_dir)
00561 {
00562 fprintf(stderr, "ERROR: Training is enabled but not the input list file nor the input directory is set.\n");
00563 return 1;
00564 }
00565
00566 if(!process_files && !process_dirs && !process_lists)
00567 process_files = true;
00568
00569
00570 SLicenseManagerI *plicman = BSAPIGetLicenseManager();
00571 if (plicman)
00572 {
00573 plicman->SetErrorHandler(&gErrorHandler);
00574 plicman->RegisterLicenseFile("license.dat");
00575 }
00576
00577
00578 SVoicePrintComparatorI *pvp_compare = static_cast<SVoicePrintComparatorI *>(BSAPICreateInstance(SIID_VPRINTCOMPARATOR));
00579 if(!pvp_compare)
00580 {
00581 return 1;
00582 }
00583
00584
00585 pvp_compare->SetErrorHandler(&gErrorHandler);
00586
00587
00588 char pdefault_cfg[1024];
00589 sprintf(pdefault_cfg, "settings%sconfig", DIRSEP);
00590 if(!pvp_compare->Init((pconfig_file ? pconfig_file : pdefault_cfg)))
00591 {
00592 pvp_compare->Release();
00593 return 1;
00594 }
00595
00596 if(pmodel_dir)
00597 pvp_compare->SetModelDirectory(pmodel_dir);
00598
00599 if(pout_model_dir)
00600 {
00601
00602 pvp_compare->SetOutputModelDirectory(pout_model_dir);
00603
00604 STwoSetComparisonI *pcomparer = pvp_compare->GetTwoSetComparator();
00605 if(!pcomparer)
00606 {
00607 pvp_compare->Release();
00608 return 1;
00609 }
00610
00611 if(pcomparer->GetIID() == SIID_TWOCOVMODEL)
00612 {
00613 STwoCovarianceModelI *ptwo_cov_model = static_cast<STwoCovarianceModelI *>(pcomparer);
00614 ptwo_cov_model->SetAdaptConst(adapt_const);
00615 ptwo_cov_model->SetUseCounts(use_counts);
00616 }
00617
00618 if(process_lists)
00619 {
00620 assert(pinput1);
00621 if (!pvp_compare->TrainFromList(pinput1))
00622 {
00623 pvp_compare->Release();
00624 return 1;
00625 }
00626 }
00627 else
00628 {
00629 assert(process_dirs && pinput1);
00630 if (!pvp_compare->TrainFromDirectory(pinput1, pvprint_ext))
00631 {
00632 pvp_compare->Release();
00633 return 1;
00634 }
00635 }
00636 }
00637 else
00638 {
00639
00640 SFloatMatrixI *pscores = static_cast<SFloatMatrixI *>(BSAPICreateInstance(SIID_FLOATMATRIX));
00641 if(!pscores)
00642 {
00643 fprintf(stderr, "ERROR: Memory allocation error.\n");
00644 pvp_compare->Release();
00645 return 1;
00646 }
00647 pscores->SetErrorHandler(&gErrorHandler);
00648
00649 if(process_files)
00650 {
00651 float score = 0.0f;
00652 if(!pvp_compare->Compare2VoicePrintFiles(pinput1, pinput2, &score))
00653 {
00654 pscores->Release();
00655 pvp_compare->Release();
00656 return 1;
00657 }
00658 printf("Score: %e\n", score);
00659 }
00660 else if(process_lists || process_dirs)
00661 {
00662 if(!poutput_file)
00663 {
00664 fprintf(stderr, "ERROR: An output file must be specified (-o).\n");
00665 pscores->Release();
00666 pvp_compare->Release();
00667 return 1;
00668 }
00669
00670 SVoicePrintSetI *pset1 = static_cast<SVoicePrintSetI *>(BSAPICreateInstance(SIID_VPRINTSET));
00671 if(!pset1)
00672 {
00673 fprintf(stderr, "ERROR: Memory allocation error.\n");
00674 pscores->Release();
00675 pvp_compare->Release();
00676 return 1;
00677 }
00678
00679 pset1->SetErrorHandler(&gErrorHandler);
00680
00681 SVoicePrintSetI *pset2 = static_cast<SVoicePrintSetI *>(BSAPICreateInstance(SIID_VPRINTSET));
00682 if(!pset2)
00683 {
00684 fprintf(stderr, "ERROR: Memory allocation error.\n");
00685 pset1->Release();
00686 pscores->Release();
00687 pvp_compare->Release();
00688 return 1;
00689 }
00690
00691 pset2->SetErrorHandler(&gErrorHandler);
00692
00693 if(process_lists)
00694 {
00695 if(!pset1->LoadFromList(pinput1))
00696 {
00697 pset1->Release();
00698 pset2->Release();
00699 pscores->Release();
00700 pvp_compare->Release();
00701 return 1;
00702 }
00703
00704 if(!pset2->LoadFromList(pinput2))
00705 {
00706 pset1->Release();
00707 pset2->Release();
00708 pscores->Release();
00709 pvp_compare->Release();
00710 return 1;
00711 }
00712 }
00713 else
00714 {
00715 if(!pset1->LoadFromDirectory(pinput1, pvprint_ext))
00716 {
00717 pset1->Release();
00718 pset2->Release();
00719 pscores->Release();
00720 pvp_compare->Release();
00721 return 1;
00722 }
00723
00724 if(!pset2->LoadFromDirectory(pinput2, pvprint_ext))
00725 {
00726 pset1->Release();
00727 pset2->Release();
00728 pscores->Release();
00729 pvp_compare->Release();
00730 return 1;
00731 }
00732 }
00733
00734 if(!pvp_compare->Compare2VoicePrintSets(pset1, pset2, pscores))
00735 {
00736 pset1->Release();
00737 pset2->Release();
00738 pscores->Release();
00739 pvp_compare->Release();
00740 return 1;
00741 }
00742
00743 if(!SaveScores(poutput_file, pscores, pset1, pset2, pcolumn_fmt, sharpness, nbest_scores, score_thr, dump_names, supp_too_short))
00744 {
00745 pset1->Release();
00746 pset2->Release();
00747 pscores->Release();
00748 pvp_compare->Release();
00749 return 1;
00750 }
00751
00752 pset1->Release();
00753 pset2->Release();
00754 }
00755
00756 pscores->Release();
00757 }
00758
00759 pvp_compare->Release();
00760 return 0;
00761 }