Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/ArffFileSink.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 2009 Stefaan Lippens <soxofaan@gmail.com>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "ArffFileSink.h"
00020 
00021 #include <fstream>
00022 #include <iomanip>
00023 
00024 
00025 using std::ostringstream;
00026 using std::ofstream;
00027 using std::ios_base;
00028 using std::endl;
00029 using std::vector;
00030 using std::fixed;
00031 using std::setprecision;
00032 
00033 
00034 using namespace Marsyas;
00035 
00036 ArffFileSink::ArffFileSink(mrs_string name) : MarSystem("ArffFileSink", name)
00037 {
00038   os_ = NULL;
00039   filename_ = "";
00040   decimationCounter = 0;
00041   addControls();
00042 }
00043 
00044 ArffFileSink::ArffFileSink(const ArffFileSink& a) : MarSystem(a)
00045 {
00046   os_ = NULL;
00047   filename_ = "";
00048   decimationCounter = 0;
00049 
00052   ctrl_floatPrecision_ = getControl("mrs_natural/floatPrecision");
00053   ctrl_decimationFactor_ = getControl("mrs_natural/decimationFactor");
00054   ctrl_filename_ = getControl("mrs_string/filename");
00055 }
00056 
00057 
00058 ArffFileSink::~ArffFileSink()
00059 {
00060   closeOutput();
00061 }
00062 
00063 MarSystem*
00064 ArffFileSink::clone() const
00065 {
00066   return new ArffFileSink(*this);
00067 }
00068 
00069 void
00070 ArffFileSink::addControls()
00071 {
00073   addControl("mrs_natural/floatPrecision", 6, ctrl_floatPrecision_);
00074   addControl("mrs_natural/decimationFactor", 1, ctrl_decimationFactor_);
00075   addControl("mrs_string/filename", "data.arff", ctrl_filename_);
00076 }
00077 
00078 void
00079 ArffFileSink::myUpdate(MarControlPtr sender)
00080 {
00082   MarSystem::myUpdate(sender);
00083 
00084   // Cache float precision and decimation for usage in myProcess().
00085   floatPrecision_ = ctrl_floatPrecision_->to<mrs_natural>();
00086   decimationFactor_ = ctrl_decimationFactor_->to<mrs_natural>();
00087   // Sanitize decimation factor.
00088   decimationFactor_ = decimationFactor_ == 0 ? 1 : decimationFactor_;
00089   // Reset decimation counter variable.
00090   decimationCounter = 0;
00091 
00092 }
00093 
00095 void
00096 ArffFileSink::closeOutput()
00097 {
00098   if (os_ != NULL)
00099   {
00100     os_->flush();
00101     os_->close();
00102     delete os_;
00103   }
00104   filename_ = "";
00105 }
00106 
00108 void
00109 ArffFileSink::prepareOutput()
00110 {
00111   // If internal file name differs from the file name we should be writing to:
00112   // close previous file, open a new file and write header.
00113   if (filename_ != ctrl_filename_->to<mrs_string>())
00114   {
00115     // Close current file.
00116     closeOutput();
00117     // Open a new output stream for the new file.
00118     filename_ = ctrl_filename_->to<mrs_string>();
00119     os_ = new ofstream;
00120     os_->open(filename_.c_str());
00121     if (os_->fail()) {
00122       // \todo make this cleaner, e.g. by creating and using a dedicated
00123       // exception for IO/file errors.
00124       ostringstream oss;
00125       oss << "[Error in " << __FILE__ << ":" << __LINE__ << "] "
00126           << "could not open file '" << filename_ << "' for writing.";
00127       throw ios_base::failure(oss.str());
00128     }
00129     // Write ARFF header.
00130     writeArffHeader();
00131   }
00132 }
00133 
00134 
00135 void
00136 ArffFileSink::writeArffHeader()
00137 {
00138   // General header stuff.
00139   (*os_) << "% ARFF file Created by Marsyas (ArffFileSink)" << endl;
00140   (*os_) << "@relation " << filename_ << endl;
00141 
00142   // Print the attributes.
00143   // Get and output the observation names.
00144   mrs_string onObsNames = ctrl_onObsNames_->to<mrs_string>();
00145   vector<mrs_string> attributeNames = stringSplit(onObsNames, ",");
00146   const mrs_natural onObservations = ctrl_onObservations_->to<mrs_natural>();
00147   // Print the observation names, if available.
00148   for (mrs_natural i = 0; i < onObservations; ++i)
00149   {
00150     if (i < (mrs_natural)attributeNames.size() && !attributeNames[i].empty())
00151     {
00152       (*os_ ) << "@attribute " << attributeNames[i] << " real" << endl;
00153     }
00154     else
00155     {
00156       (*os_ ) << "@attribute " << "untitled" << i << " real" << endl;
00157     }
00158   }
00159 
00160   // End of header, we are ready now for outputting the data.
00161   (*os_) << "\n@data" << endl;
00162 }
00163 
00164 void
00165 ArffFileSink::myProcess(realvec& in, realvec& out)
00166 {
00167   mrs_natural o,t;
00168   // Make sure we can write to the output stream.
00169   prepareOutput();
00170 
00171   // Copy input to output.
00172   for (t = 0; t < inSamples_; t++)
00173   {
00174     for (o = 0; o < inObservations_; o++)
00175     {
00176       out(o, t) = in(o, t);
00177     }
00178   }
00179 
00180   if (!ctrl_mute_->isTrue()) {
00181     // Write data to file.
00182     for (t = 0; t < inSamples_; t++)
00183     {
00184       if (decimationCounter % decimationFactor_ == 0)
00185       {
00186         for (o = 0; o < inObservations_; o++)
00187         {
00188           (*os_) << fixed << setprecision(floatPrecision_) << out(o, t);
00189           if (o < inObservations_ - 1)
00190           {
00191             (*os_) << ",";
00192           }
00193         }
00194         (*os_) << endl;
00195       }
00196       decimationCounter ++;
00197     }
00198   }
00199 }