SegServerFileWriter.cpp

Go to the documentation of this file.
00001 /*
00002         This file is part of ALIZE which is an open-source tool for 
00003         speaker recognition.
00004 
00005     ALIZE is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU Lesser General Public License as 
00007     published by the Free Software Foundation, either version 3 of 
00008     the License, or any later version.
00009 
00010     ALIZE is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU Lesser General Public License for more details.
00014 
00015     You should have received a copy of the GNU Lesser General Public 
00016     License along with ALIZE.
00017     If not, see <http://www.gnu.org/licenses/>.
00018         
00019         ALIZE is a development project initiated by the ELISA consortium
00020         [alize.univ-avignon.fr/] and funded by the French Research 
00021         Ministry in the framework of the TECHNOLANGUE program 
00022         [www.technolangue.net]
00023 
00024         The ALIZE project team wants to highlight the limits of voice
00025         authentication in a forensic context.
00026         The "Person  Authentification by Voice: A Need of Caution" paper 
00027         proposes a good overview of this point (cf. "Person  
00028         Authentification by Voice: A Need of Caution", Bonastre J.F., 
00029         Bimbot F., Boe L.J., Campbell J.P., Douglas D.A., Magrin-
00030         chagnolleau I., Eurospeech 2003, Genova].
00031         The conclusion of the paper of the paper is proposed bellow:
00032         [Currently, it is not possible to completely determine whether the 
00033         similarity between two recordings is due to the speaker or to other 
00034         factors, especially when: (a) the speaker does not cooperate, (b) there 
00035         is no control over recording equipment, (c) recording conditions are not 
00036         known, (d) one does not know whether the voice was disguised and, to a 
00037         lesser extent, (e) the linguistic content of the message is not 
00038         controlled. Caution and judgment must be exercised when applying speaker 
00039         recognition techniques, whether human or automatic, to account for these 
00040         uncontrolled factors. Under more constrained or calibrated situations, 
00041         or as an aid for investigative purposes, judicious application of these 
00042         techniques may be suitable, provided they are not considered as infallible.
00043         At the present time, there is no scientific process that enables one to 
00044         uniquely characterize a person=92s voice or to identify with absolute 
00045         certainty an individual from his or her voice.]
00046         Contact Jean-Francois Bonastre for more information about the licence or
00047         the use of ALIZE
00048 
00049         Copyright (C) 2003-2010
00050         Laboratoire d'informatique d'Avignon [lia.univ-avignon.fr]
00051         ALIZE admin [alize@univ-avignon.fr]
00052         Jean-Francois Bonastre [jean-francois.bonastre@univ-avignon.fr]
00053 */
00054 
00055 #if !defined(ALIZE_SegServerFileWriter_cpp)
00056 #define ALIZE_SegServerFileWriter_cpp
00057 
00058 #include "SegServerFileWriter.h"
00059 #include "Exception.h"
00060 #include "SegServer.h"
00061 #include "Config.h"
00062 
00063 #include <cstdlib>
00064 
00065 using namespace alize;
00066 using namespace std;
00067 typedef SegServerFileWriter W;
00068 
00069 //-------------------------------------------------------------------------
00070 W::SegServerFileWriter(const FileName& f,const Config& c)
00071 :FileWriter(getFullFileName(c, f)), _config(c)
00072 {
00073   if (_fileName.endsWith(".xml"))
00074     _format = SegServerFileWriterFormat_XML;
00075   else 
00076     _format = c.getParam_saveSegServerFileFormat();
00077 }
00078 //-------------------------------------------------------------------------
00079 String W::getFullFileName(const Config& c, const String& n) const // protected
00080 {
00081   if (n.beginsWith("/") || n.beginsWith("./"))
00082     return n;
00083   return c.getParam_segServerFilesPath() + n
00084       + c.getParam_saveSegServerFileExtension();
00085 }
00086 //-------------------------------------------------------------------------
00087 void W::writeSegServer(const SegServer& ss)
00088 {
00089   if (_format == SegServerFileWriterFormat_XML)
00090     writeSegServerXml(ss);
00091   else if (_format == SegServerFileWriterFormat_RAW)
00092     writeSegServerRaw(ss);
00093   else if (_format == SegServerFileWriterFormat_TRS)
00094     writeSegServerTrs(ss);
00095   //else if (_format == SegServerFileWriterFormat_LIUM)
00096   //  writeSegServerLium(ss);
00097   else
00098    throw Exception("I don't know how to save the segment server",
00099            __FILE__, __LINE__);
00100 }
00101 //-------------------------------------------------------------------------
00102 void W::writeSegServerXml(const SegServer& ss)
00103 {
00104   open(); //can throw IOException
00105   unsigned long i;
00106   writeString("<SegServer");
00107   writeAttribute("name", ss.getServerName());
00108   writeString(">");
00109   for (i=0; i<ss.getSegCount(); i++)
00110   {
00111     const Seg& s = ss.getSeg(i);
00112     writeString("\n\t<Seg");
00113     writeAttribute("id", i);
00114     writeAttribute("begin", s.begin());
00115     writeAttribute("length", s.length());
00116     writeAttribute("codeLabel", s.labelCode());
00117     writeAttribute("string", s.string());
00118     writeAttribute("sourceName", s.sourceName());
00119     if (s.list().getLineCount() != 0)
00120     {
00121       writeString(">");
00122       writeListXml(s.list());
00123       writeString("\n\t</Seg>");
00124     }
00125     else
00126       writeString("/>");
00127   }
00128   for (i=0; i<ss.getClusterCount(); i++)
00129   {
00130     SegCluster& cl = ss.getCluster(i);
00131     writeString("\n\t<SegCluster");
00132     writeAttribute("id", cl.getId());
00133     writeAttribute("codeLabel", cl.labelCode());
00134     writeAttribute("string", cl.string());
00135     writeAttribute("sourceName", cl.sourceName());
00136     writeString(">");
00137     if (cl.list().getLineCount() != 0)
00138       writeListXml(cl.list());
00139     writeSubSegXml(ss.getCluster(i), ss);
00140     writeString("\n\t</SegCluster>");
00141   }
00142   writeString("\n</SegServer>");
00143   close();
00144 }
00145 //-------------------------------------------------------------------------
00146 void W::writeSubSegXml(const SegCluster& cl, const SegServer& ss) // private
00147 {
00148   for (unsigned long i=0; i<cl.getCount(); i++)
00149   {
00150     SegAbstract& s = cl.get(i);
00151     if (dynamic_cast<Seg*>(&s) != NULL)
00152       writeString("\n\t\t<Seg");
00153     else if (dynamic_cast<SegCluster*>(&s) != NULL)
00154       writeString("\n\t\t<SegCluster");
00155     else
00156       throw Exception("unexpected object", __FILE__, __LINE__);
00157     writeAttribute("idx", ss.getIndex(s));
00158     writeString("/>");
00159   }
00160 }
00161 //-------------------------------------------------------------------------
00162 void W::writeListXml(const XList& l)
00163 {
00164   for (unsigned long i=0; i<l.getLineCount(); i++)
00165   {
00166     writeString("\n\t\t<Line");
00167     writeAttribute("idx", i);
00168     writeString(">");
00169     const XLine& line = l.getLine(i);
00170     for (unsigned long j=0; j<line.getElementCount(); j++)
00171     {
00172       writeString("\n\t\t\t<element");
00173       writeAttribute("idx", j);
00174       writeString(">" + line.getElement(j) + "</element>");
00175     }
00176     writeString("\n\t\t</Line>");
00177   }
00178 }  
00179 //-------------------------------------------------------------------------
00180 void W::writeSegServerRaw(const SegServer& ss)
00181 {
00182   open(); //can throw IOException
00183   unsigned long i;
00184 
00185   writeUInt4(ss.getServerName().length());
00186   writeString(ss.getServerName());
00187   writeUInt4(ss.getSegCount());
00188   for (i=0; i<ss.getSegCount(); i++)
00189   {
00190     const Seg& s = ss.getSeg(i);
00191     writeUInt4(s.begin());
00192     writeUInt4(s.length());
00193     writeUInt4(s.labelCode());
00194     writeUInt4(s.string().length());
00195     writeString(s.string());
00196     writeUInt4(s.sourceName().length());
00197     writeString(s.sourceName());
00198     //writeUInt4(s.list().getLineCount());
00199     writeListRaw(s.list());
00200   }
00201   writeUInt4(ss.getClusterCount());
00202   for (i=0; i<ss.getClusterCount(); i++)
00203   {
00204     SegCluster& cl = ss.getCluster(i);
00205     writeUInt4(cl.getId());
00206     writeUInt4(cl.labelCode());
00207     writeUInt4(cl.string().length());
00208     writeString(cl.string());
00209     writeUInt4(cl.sourceName().length());
00210     writeString(cl.sourceName());
00211     //writeUInt4(cl.list().getLineCount());
00212     writeListRaw(cl.list());
00213     writeSubSegRaw(ss.getCluster(i), ss);
00214   }
00215   close();
00216 }
00217 //-------------------------------------------------------------------------
00218 void W::writeSubSegRaw(const SegCluster& cl, const SegServer& ss) // private
00219 {
00220   writeUInt4(cl.getCount());
00221   for (unsigned long i=0; i<cl.getCount(); i++)
00222   {
00223     SegAbstract& s = cl.get(i);
00224     if (dynamic_cast<Seg*>(&s) != NULL)
00225       writeString("s");
00226     else if (dynamic_cast<SegCluster*>(&s) != NULL)
00227       writeString("c");
00228     else
00229       throw Exception("unexpected object", __FILE__, __LINE__);
00230     writeUInt4(ss.getIndex(s));
00231   }
00232 }
00233 //-------------------------------------------------------------------------
00234 void W::writeListRaw(const XList& l)
00235 {
00236   writeUInt4(l.getLineCount());
00237   for (unsigned long i=0; i<l.getLineCount(); i++)
00238   {
00239     const XLine& line = l.getLine(i);
00240     unsigned long c = line.getElementCount();
00241     writeUInt4(c);
00242     for (unsigned long j=0; j<c; j++)
00243     {
00244       const String& e = line.getElement(j);
00245       writeUInt4(e.length());
00246       writeString(e);
00247     }
00248   }
00249 }  
00250 //-------------------------------------------------------------------------
00251 void W::writeSegServerTrs(const SegServer& ss)
00252 {
00253   open(); //can throw IOException
00254   unsigned long i, n, vSize, id = 0, begin = 0, end = 0, endTurn = 0;
00255   double sampleRate = _config.getParam_sampleRate();
00256   writeString("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
00257   writeString("\n<!DOCTYPE Trans SYSTEM \"trans-13.dtd\">");
00258   unsigned long nbCl = ss.getClusterCount();
00259   writeString("\n<Trans>");
00260   // create segVect[]
00261   n = 0;
00262   for (i=0; i<nbCl; i++)
00263   {
00264       const SegCluster& cl = ss.getCluster(i);
00265       cl.rewind();
00266       while (cl.getSeg() != NULL)
00267         n++;
00268   }
00269   _type* segVect = new (std::nothrow) _type[n!=0?n:1];
00270   assertMemoryIsAllocated(segVect, __FILE__, __LINE__);
00271   //
00272   try
00273   {
00274     writeString("\n\t<Speakers>");
00275     vSize = 0;
00276     for (i=0; i<nbCl; i++)
00277     {
00278       const SegCluster& cl = ss.getCluster(i);
00279       writeString("\n\t\t<Speaker");
00280       writeAttribute("id", "spk" + String::valueOf(cl.getId()));
00281       writeAttribute("name", cl.string());
00282       writeString("/>");
00283       Seg* p;
00284       cl.rewind();
00285       while ( (p = cl.getSeg()) != NULL)
00286       {
00287         segVect[vSize].begin = (unsigned long)((p->begin()*1000.0)/sampleRate);
00288         segVect[vSize].end = (unsigned long)(((p->begin()+p->length()-1+1)*1000.0)/sampleRate);
00289         segVect[vSize].id = cl.getId();
00290         if (segVect[vSize].begin != segVect[vSize].end)
00291           vSize++;
00292       }
00293     }
00294     writeString("\n\t</Speakers>");
00295     writeString("\n\t<Episode>");
00296 
00297     if (vSize != 0)
00298     {
00299       qsort(segVect, vSize, sizeof(_type), compare);
00300       writeString("\n\t\t<Section");
00301       writeAttribute("type","report");
00302       writeTime("startTime", segVect[0].begin);
00303 
00304       for (long ii=vSize-1; ii>=0; ii--)
00305       {
00306         _type& seg = segVect[ii];
00307         if ((unsigned long)ii == vSize-1 || seg.id != id || seg.end < begin)
00308           endTurn = seg.end;
00309         seg.endTurn = endTurn;
00310         id = seg.id;
00311         begin = seg.begin;
00312       }
00313       writeTime("endTime", segVect[vSize-1].end);
00314       writeString(">");
00315       bool turnStarted = false;
00316       for (i=0; i<vSize; i++)
00317       {
00318         _type& seg = segVect[i];
00319         if (i == 0 || seg.id != id || seg.begin > end)
00320         {
00321           if (i != 0)
00322             writeString("\n\t\t\t</Turn>");
00323           turnStarted = true;
00324           writeString("\n\t\t\t<Turn");
00325           writeAttribute("speaker", "spk" + String::valueOf(seg.id));
00326           writeTime("startTime", seg.begin);
00327           writeTime("endTime", seg.endTurn);
00328           writeString(">");
00329         }
00330         writeString("\n\t\t\t\t<Sync");
00331         writeTime("time", seg.begin);
00332         writeString("/>");
00333         id = seg.id;
00334         end = seg.end;
00335       }
00336       if (turnStarted)
00337         writeString("\n\t\t\t</Turn>");
00338       writeString("\n\t\t</Section>");
00339     }
00340     delete [] segVect;
00341     writeString("\n\t</Episode>");
00342     writeString("\n</Trans>");
00343     close();
00344   }
00345   catch (Exception&)
00346   {
00347     delete [] segVect;
00348     throw; // do not use 'throw e'
00349   }
00350 }
00351 //-------------------------------------------------------------------------
00352 void W::writeTime(const String& n, unsigned long t) // private
00353 { writeAttribute(n, String::valueOf(t/1000.0)); }
00354 //-------------------------------------------------------------------------
00355 String W::getClassName() const { return "SegServerFileWriter"; }
00356 //-------------------------------------------------------------------------
00357 W::~SegServerFileWriter() {}
00358 //-------------------------------------------------------------------------
00359 // static method
00360 //-------------------------------------------------------------------------
00361 int W::compare(const void *s1, const void *s2)
00362 
00363 {
00364     if (((_type*)s1)->begin > ((_type*)s2)->begin)
00365         return 1;
00366     if (((_type*)s1)->begin < ((_type*)s2)->begin)
00367         return -1;
00368     return 0;
00369 }
00370 
00371 #endif // !defined(ALIZE_SegServerFileWriter_cpp)
00372