Marsyas
0.6.0-alpha
|
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 }