Marsyas
0.6.0-alpha
|
00001 /* 00002 ** Copyright (C) 1998-2006 George Tzanetakis <gtzan@cs.uvic.ca> 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 "../common_source.h" 00020 #include "../FileName.h" 00021 #include "AuFileSink.h" 00022 #include "AuFileSource.h" 00023 00024 #ifdef MARSYAS_WIN32 00025 #ifndef MARSYAS_CYGWIN 00026 typedef __int32 int32_t; 00027 #endif 00028 #else 00029 #include <stdint.h> 00030 #endif 00031 00032 #include <cstddef> 00033 00034 using std::ostringstream; 00035 using std::size_t; 00036 using namespace Marsyas; 00037 00038 /******** NeXT/Sun Soundfile Header Struct *******/ 00039 struct Marsyas::snd_header 00040 { 00041 char pref[4]; 00042 int32_t hdrLength; 00043 int32_t fileLength; 00044 int32_t mode; 00045 int32_t srate; 00046 int32_t channels; 00047 char comment[1024]; 00048 }; 00049 00050 00051 00052 00053 00054 00055 #define SND_MAGIC_NUM 0x2e736e64 00056 00057 00058 /* Array containing descriptions of 00059 the various formats for the samples 00060 of the Next .snd/ Sun .au format */ 00061 00062 /* types of .snd files */ 00063 #define SND_FORMAT_UNSPECIFIED 0 00064 #define SND_FORMAT_MULAW_8 1 00065 #define SND_FORMAT_LINEAR_8 2 00066 #define SND_FORMAT_LINEAR_16 3 00067 #define SND_FORMAT_LINEAR_24 4 00068 #define SND_FORMAT_LINEAR_32 5 00069 #define SND_FORMAT_FLOAT 6 00070 00071 AuFileSink::AuFileSink(mrs_string name):AbsSoundFileSink("AuFileSink",name) 00072 { 00073 //type_ = "AuFileSink"; 00074 //name_ = name; 00075 00076 sfp_ = NULL; 00077 cdata_ = NULL; 00078 sdata_ = NULL; 00079 hdr_ = new snd_header; 00080 00081 addControls(); 00082 } 00083 00084 AuFileSink::~AuFileSink() 00085 { 00086 delete [] sdata_; 00087 delete [] cdata_; 00088 delete hdr_; 00089 if (sfp_) fclose(sfp_); 00090 } 00091 00092 00093 AuFileSink::AuFileSink(const AuFileSink& a): AbsSoundFileSink(a) 00094 { 00095 hdr_ = new snd_header; 00096 } 00097 00098 00099 00100 MarSystem* 00101 AuFileSink::clone() const 00102 { 00103 return new AuFileSink(*this); 00104 } 00105 00106 void 00107 AuFileSink::addControls() 00108 { 00109 addctrl("mrs_string/filename", "daufile"); 00110 setctrlState("mrs_string/filename", true); 00111 00112 // lossy encoding specific controls 00113 addctrl("mrs_natural/bitrate", 128); 00114 setctrlState("mrs_natural/bitrate", true); 00115 addctrl("mrs_natural/encodingQuality", 2); 00116 setctrlState("mrs_natural/encodingQuality", true); 00117 addctrl("mrs_string/id3tags", "noTitle|noArtist|noAlbum|1978|noComment|1|0"); // 1: track one O Blues genreopen 00118 setctrlState("mrs_string/id3tags", true); 00119 00120 } 00121 00122 bool 00123 AuFileSink::checkExtension(mrs_string filename) 00124 { 00125 FileName fn(filename); 00126 mrs_string auext = "au"; 00127 mrs_string sndext = "snd"; 00128 00129 if ((fn.ext() == auext) || (fn.ext() == sndext)) 00130 return true; 00131 else 00132 return false; 00133 } 00134 00135 void 00136 AuFileSink::myUpdate(MarControlPtr sender) 00137 { 00138 (void) sender; //suppress warning of unused parameter(s) 00139 MRSDIAG("AudioFileSink::myUpdate"); 00140 setctrl("mrs_natural/onSamples", getctrl("mrs_natural/inSamples")); 00141 setctrl("mrs_natural/onObservations", getctrl("mrs_natural/inObservations")); 00142 setctrl("mrs_real/osrate", getctrl("mrs_real/israte")); 00143 00144 nChannels_ = getctrl("mrs_natural/inObservations")->to<mrs_natural>(); 00145 00146 delete [] sdata_; 00147 delete [] cdata_; 00148 00149 sdata_ = new short[getctrl("mrs_natural/inSamples")->to<mrs_natural>() * nChannels_]; 00150 cdata_ = new unsigned char[getctrl("mrs_natural/inSamples")->to<mrs_natural>() * nChannels_]; 00151 00152 filename_ = getctrl("mrs_string/filename")->to<mrs_string>(); 00153 } 00154 00155 void 00156 AuFileSink::putHeader(mrs_string filename) 00157 { 00158 mrs_natural nChannels = (mrs_natural)getctrl("mrs_natural/inObservations")->to<mrs_natural>(); 00159 00160 written_ = 0; 00161 const char *comment = "MARSYAS 2001, George Tzanetakis.\n"; 00162 size_t commentSize = strlen(comment); 00163 sfp_ = fopen(filename.c_str(), "wb"); 00164 hdr_->pref[0] = '.'; 00165 hdr_->pref[1] = 's'; 00166 hdr_->pref[2] = 'n'; 00167 hdr_->pref[3] = 'd'; 00168 00169 #if defined(MARSYAS_BIGENDIAN) 00170 hdr_->hdrLength = 24 + commentSize; 00171 hdr_->fileLength = 0; 00172 hdr_->mode = SND_FORMAT_LINEAR_16; 00173 hdr_->srate = (mrs_natural)getctrl("mrs_real/israte")->to<mrs_real>(); 00174 hdr_->channels = nChannels; 00175 #else 00176 hdr_->hdrLength = ByteSwapLong(24 + (unsigned long)commentSize); 00177 hdr_->fileLength = ByteSwapLong(0); 00178 hdr_->mode = ByteSwapLong(SND_FORMAT_LINEAR_16); 00179 hdr_->srate = ByteSwapLong((mrs_natural)getctrl("mrs_real/israte")->to<mrs_real>()); 00180 hdr_->channels = ByteSwapLong(nChannels); 00181 #endif 00182 00183 fwrite(hdr_, 24, 1, sfp_); 00184 // Write comment part of header 00185 fwrite(comment, commentSize, 1, sfp_); 00186 sfp_begin_ = ftell(sfp_); 00187 } 00188 00189 unsigned long 00190 AuFileSink::ByteSwapLong(unsigned long nLongNumber) 00191 { 00192 return (((nLongNumber&0x000000FF)<<24)+((nLongNumber&0x0000FF00)<<8)+ 00193 ((nLongNumber&0x00FF0000)>>8)+((nLongNumber&0xFF000000)>>24)); 00194 } 00195 00196 unsigned short 00197 AuFileSink::ByteSwapShort (unsigned short nValue) 00198 { 00199 return (static_cast<unsigned short>((nValue & 0xff00) >> 8) | 00200 static_cast<unsigned short>((nValue & 0xff) << 8)); 00201 } 00202 00203 void 00204 AuFileSink::putLinear16(realvec& slice) 00205 { 00206 mrs_natural c,t; 00207 for (c=0; c < nChannels_; ++c) 00208 for (t=0; t < inSamples_; t++) 00209 { 00210 #if defined(MARSYAS_BIGENDIAN) 00211 sdata_[t*nChannels_ + c] = (short)(slice(c,t) * PCM_MAXSHRT); 00212 #else 00213 sdata_[t*nChannels_ + c] = ByteSwapShort((short)(slice(c,t) * PCM_MAXSHRT)); 00214 #endif 00215 } 00216 00217 if ((mrs_natural)fwrite(sdata_, sizeof(short), nChannels_ * inSamples_, sfp_) != nChannels_ * inSamples_) 00218 { 00219 MRSWARN("Problem: could not write window to file" + filename_); 00220 } 00221 } 00222 00223 void 00224 AuFileSink::myProcess(realvec& in, realvec& out) 00225 { 00226 mrs_natural t,o; 00227 //checkFlow(in,out); 00228 00229 // copy input to output 00230 for (o=0; o < inObservations_; o++) 00231 for (t=0; t < inSamples_; t++) 00232 { 00233 if (in(o,t) > 1.0) 00234 { 00235 MRSWARN("AuFileSink::Value out of range > 1.0"); 00236 } 00237 if (in(o,t) < -1.0) 00238 { 00239 MRSWARN("AuFileSink::Value out of range < -1.0"); 00240 } 00241 out(o,t) = in(o,t); 00242 } 00243 00244 long fileSize; 00245 fpos_ = ftell(sfp_); 00246 fseek(sfp_, 8, SEEK_SET); 00247 written_ += inSamples_; 00248 #if defined(MARSYAS_BIGENDIAN) 00249 fileSize = (written_ * 2 * nChannels_); 00250 #else 00251 fileSize = ByteSwapLong(written_ * 2 * nChannels_); 00252 #endif 00253 00254 fwrite(&fileSize, 4, 1, sfp_); 00255 fseek(sfp_, fpos_, SEEK_SET); 00256 00257 putLinear16(in); 00258 } 00259 00260 00261 00262 00263 00264 00265 00266 00267 00268 00269 00270 00271 00272 00273 00274