Marsyas
0.6.0-alpha
|
00001 /* 00002 ** Copyright (C) 1998-2010 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 "WavFileSource2.h" 00020 00021 using namespace std; 00022 using namespace Marsyas; 00023 00024 WavFileSource2::WavFileSource2(mrs_string name):AbsSoundFileSource2("WavFileSource2",name) 00025 { 00026 sdata_ = NULL; 00027 cdata_ = NULL; 00028 sfp_ = NULL; 00029 00030 addControls(); 00031 } 00032 00033 WavFileSource2::~WavFileSource2() 00034 { 00035 delete [] sdata_; 00036 delete [] cdata_; 00037 if (sfp_ != NULL) 00038 fclose(sfp_); 00039 } 00040 00041 WavFileSource2::WavFileSource2(const WavFileSource2& a):AbsSoundFileSource2(a) //[!][?] 00042 { 00043 sdata_ = NULL; 00044 cdata_ = NULL; 00045 sfp_ = NULL; 00046 } 00047 00048 MarSystem* 00049 WavFileSource2::clone() const 00050 { 00051 return new WavFileSource2(*this); //shouldn't this class have a copy constructor?!? [?][!] 00052 } 00053 00054 void 00055 WavFileSource2::addControls() 00056 { 00057 setctrl("mrs_string/filetype", "wav"); 00058 } 00059 00060 void 00061 WavFileSource2::hdrError() 00062 { 00063 setctrl("mrs_natural/nChannels", (mrs_natural)1); 00064 setctrl("mrs_real/israte", MRS_DEFAULT_SLICE_SRATE);//(mrs_real)22050.0); 00065 setctrl("mrs_natural/size", (mrs_natural)0); 00066 setctrl("mrs_bool/hasData", false); 00067 setctrl("mrs_string/filename", string()); 00068 } 00069 00070 bool 00071 WavFileSource2::getHeader() 00072 { 00073 unsigned short channels, srate; 00074 mrs_natural size; 00075 00076 mrs_string filename = getctrl("mrs_string/filename")->to<mrs_string>(); 00077 //if an empty filename, return error and default configuration 00078 if(filename.empty()) 00079 { 00080 MRSERR("WavFileSource2::getHeader: empty FileName"); 00081 hdrError(); 00082 return false; 00083 } 00084 00085 sfp_ = fopen(filename.c_str(), "rb"); 00086 if (sfp_) 00087 { 00088 char magic[5]; 00089 00090 fseek(sfp_, 8, SEEK_SET); // Locate wave id 00091 if (fread(magic, 4, 1, sfp_) == 0) 00092 { 00093 MRSERR("WavFileSource2::getHeader: File " + filename + " is empty "); 00094 hdrError(); 00095 return false; 00096 } 00097 magic[4] = '\0'; 00098 00099 if (strcmp(magic, "WAVE")) 00100 { 00101 MRSWARN("WavFileSource2::getHeader: Filename " + filename + " is not correct .wav file \n or has settings that are not supported in Marsyas"); 00102 hdrError(); 00103 return false; 00104 } 00105 else 00106 { 00107 char id[5]; 00108 int chunkSize; 00109 if (fread(id, 4, 1, sfp_) != 1) { 00110 MRSERR("Error reading wav file"); 00111 } 00112 id[4] = '\0'; 00113 00114 while (strcmp(id, "fmt ")) 00115 { 00116 if (fread(&chunkSize, 4, 1, sfp_) != 1) { 00117 MRSERR("Error reading wav file"); 00118 } 00119 #if defined(MARSYAS_BIGENDIAN) 00120 chunkSize = ByteSwapLong(chunkSize); 00121 #endif 00122 fseek(sfp_, chunkSize, SEEK_CUR); 00123 if (fread(id, 4, 1, sfp_) != 1) { 00124 MRSERR("Error reading wav file"); 00125 } 00126 } 00127 00128 if (fread(&chunkSize, 4, 1, sfp_) != 1) { 00129 MRSERR("Error reading wav file"); 00130 } 00131 #if defined(MARSYAS_BIGENDIAN) 00132 chunkSize = ByteSwapLong(chunkSize); 00133 #endif 00134 00135 unsigned short format_tag; 00136 if (fread(&format_tag, 2, 1, sfp_) != 1) { 00137 MRSERR("Error reading wav file"); 00138 } 00139 #if defined(MARSYAS_BIGENDIAN) 00140 format_tag = ByteSwapShort(format_tag); 00141 #endif 00142 if (format_tag != 1) 00143 { 00144 fclose(sfp_); 00145 MRSWARN("WavFileSource2::getHeader: Non pcm(compressed) wave files are not supported"); 00146 hdrError(); 00147 return false; 00148 } 00149 00150 // Get number of channels 00151 if (fread(&channels, 2, 1, sfp_) != 1) { 00152 MRSERR("Error reading wav file"); 00153 } 00154 #if defined(MARSYAS_BIGENDIAN) 00155 channels = ByteSwapShort(channels); 00156 #endif 00157 // access directly controls to avoid update() recursion 00158 setctrl("mrs_natural/nChannels", (mrs_natural)channels); 00159 //nChannels_ = channels; //getctrl("mrs_natural/nChannels")->to<mrs_natural>();//[!] 00160 00161 if (fread(&srate, 2, 1, sfp_) != 1) { 00162 MRSERR("Error reading wav file"); 00163 } 00164 #if defined(MARSYAS_BIGENDIAN) 00165 srate = ByteSwapShort(srate); 00166 #endif 00167 setctrl("mrs_real/israte", (mrs_real)srate); 00168 //israte_ = (mrs_real)srate; 00169 00170 fseek(sfp_,8,SEEK_CUR); 00171 if (fread(&bits_, 2, 1, sfp_) != 1) { 00172 MRSERR("Error reading wav file"); 00173 } 00174 #if defined(MARSYAS_BIGENDIAN) 00175 bits_ = ByteSwapShort(bits_); 00176 #endif 00177 if ((bits_ != 16))//&&(bits_ != 8)) 00178 { 00179 fclose(sfp_); 00180 //MRSWARN("WavFileSource2::getHeader: WavFileSource2::Only linear 8-bit and 16-bit samples are supported "); 00181 MRSWARN("WavFileSource2::getHeader: WavFileSource2::Only linear 16-bit samples are supported for now..."); 00182 hdrError(); 00183 return false; 00184 } 00185 00186 fseek(sfp_, chunkSize - 16, SEEK_CUR); 00187 if (fread(id, 4, 1, sfp_) != 1) { 00188 MRSERR("Error reading wav file"); 00189 } 00190 id[4] = '\0'; 00191 while (strcmp(id, "data")) 00192 { 00193 if (fread(&chunkSize, 4, 1, sfp_) != 1) { 00194 MRSERR("Error reading wav file"); 00195 } 00196 #if defined(MARSYAS_BIGENDIAN) 00197 chunkSize = ByteSwapLong(chunkSize); 00198 #endif 00199 fseek(sfp_,chunkSize,SEEK_CUR); 00200 if (fread(&id,4,1,sfp_) != 1) { 00201 MRSERR("Error reading wav file"); 00202 } 00203 } 00204 00205 int bytes; 00206 if (fread(&bytes, 4, 1, sfp_) != 1) { 00207 MRSERR("Error reading wav file"); 00208 } 00209 #if defined(MARSYAS_BIGENDIAN) 00210 bytes = ByteSwapLong(bytes); 00211 #endif 00212 //size in number of samples per channel 00213 size = bytes / (bits_ / 8)/ channels; 00214 setctrl("mrs_natural/size", size); 00215 00216 sfp_begin_ = ftell(sfp_); 00217 00218 //check if there is in fact any audio data in the soundfile 00219 if(size > 0) 00220 setctrl("mrs_bool/hasData", true); 00221 else 00222 setctrl("mrs_bool/hasData", false); 00223 } 00224 } 00225 else 00226 { 00227 hdrError(); 00228 return false; 00229 } 00230 00231 return true; 00232 } 00233 00234 void 00235 WavFileSource2::myUpdate(MarControlPtr sender) 00236 { 00237 (void) sender; //suppress warning of unused parameter(s) 00238 //if not a new audiofile, no need to read header again 00239 mrs_string filename = getctrl("mrs_string/filename")->to<mrs_string>(); 00240 if(filename_ != filename) 00241 { 00242 getHeader();//sets controls filename, nChannels, israte and size 00243 filename_ = getctrl("mrs_string/filename")->to<mrs_string>(); 00244 nChannels_ = getctrl("mrs_natural/nChannels")->to<mrs_natural>(); 00245 israte_ = getctrl("mrs_real/israte")->to<mrs_real>(); 00246 size_ = getctrl("mrs_natural/size")->to<mrs_natural>(); 00247 } 00248 00249 //update internal vars 00250 inSamples_ = getctrl("mrs_natural/inSamples")->to<mrs_natural>(); 00251 osrate_ = israte_; 00252 00253 //update output pin config 00254 setctrl("mrs_natural/onSamples", inSamples_); 00255 setctrl("mrs_natural/onObservations", nChannels_); 00256 setctrl("mrs_real/osrate", osrate_); 00257 00258 //update internal buffers 00259 delete [] sdata_; 00260 delete [] cdata_; 00261 sdata_ = new short[inSamples_ * nChannels_]; 00262 cdata_ = new unsigned char[inSamples_ * nChannels_]; 00263 00264 samplesToRead_ = inSamples_ * nChannels_; 00265 00266 //observation's names 00267 ostringstream oss; 00268 for (mrs_natural i = 0; i < nChannels_; ++i) 00269 oss << "audio_ch_" << i+1 << ","; 00270 setctrl("mrs_string/onObsNames", oss.str()); 00271 } 00272 00273 // mrs_natural 00274 // WavFileSource2::getLinear8(mrs_natural c, realvec& slice)//this does not seem to be working!!! [!][?] 00275 // { 00276 // mrs_natural nChannels = getctrl("nChannels")->to<mrs_natural>(); 00277 // mrs_natural inSamples = getctrl("mrs_natural/inSamples")->to<mrs_natural>(); 00278 // 00279 // samplesToRead_ = inSamples * nChannels; 00280 // 00281 // // only read data when called for first channel 00282 // if (c == 0) 00283 // { 00284 // samplesRead_ = (mrs_natural)fread(cdata_, sizeof(unsigned char), samplesToRead_, sfp_); 00285 // } 00286 // if (samplesRead_ != samplesToRead_) 00287 // { 00288 // for (t=0; t < inSamples; t++) 00289 // { 00290 // slice(0,t) = 0.0; 00291 // } 00292 // } 00293 // for (t=0; t < inSamples; t++) 00294 // { 00295 // slice(0, t) = (mrs_real)-1.0 + (mrs_real) cdata_[nChannels * t + c] / 128; 00296 // } 00297 // 00298 // pos_ += samplesToRead_; 00299 // return pos_; 00300 // } 00301 00302 unsigned long 00303 WavFileSource2::ByteSwapLong(unsigned long nLongNumber) 00304 { 00305 return (((nLongNumber&0x000000FF)<<24)+((nLongNumber&0x0000FF00)<<8)+ 00306 ((nLongNumber&0x00FF0000)>>8)+((nLongNumber&0xFF000000)>>24)); 00307 } 00308 00309 unsigned short 00310 WavFileSource2::ByteSwapShort (unsigned short nValue) 00311 { 00312 return (static_cast<unsigned short>((nValue & 0xff00) >> 8) | 00313 static_cast<unsigned short>((nValue & 0xff) << 8)); 00314 } 00315 00316 mrs_natural 00317 WavFileSource2::getLinear16(realvec& slice) 00318 { 00319 mrs_natural c,t; 00320 mrs_natural pos = getctrl("mrs_natural/pos")->to<mrs_natural>(); 00321 00322 fseek(sfp_, 2 * pos * nChannels_ + sfp_begin_, SEEK_SET); 00323 00324 samplesToRead_ = inSamples_ * nChannels_; 00325 00326 samplesRead_ = (mrs_natural)fread(sdata_, sizeof(short), samplesToRead_, sfp_); 00327 00328 if (samplesRead_ != samplesToRead_) 00329 { 00330 samplesToWrite_ = samplesRead_ / nChannels_; 00331 for (c=0; c < nChannels_; ++c) 00332 //only fill remaining space with zeros => faster 00333 for(t = samplesToWrite_; t < inSamples_; t++) 00334 { 00335 slice(c, t) = 0.0; 00336 } 00337 } 00338 else 00339 samplesToWrite_ = inSamples_; 00340 00341 for (t=0; t < samplesToWrite_; t++) 00342 { 00343 sval_ = 0; 00344 #if defined(MARSYAS_BIGENDIAN) 00345 for (c=0; c < nChannels_; ++c) 00346 { 00347 sval_ = ByteSwapShort(sdata_[nChannels_*t + c]); 00348 slice(c, t) = (mrs_real) sval_ / (PCM_FMAXSHRT); 00349 } 00350 #else 00351 for (c=0; c < nChannels_; ++c) 00352 { 00353 sval_ = sdata_[nChannels_ *t + c]; 00354 slice(c, t) = ((mrs_real) sval_ / (PCM_FMAXSHRT)); 00355 } 00356 #endif 00357 } 00358 00359 //update play position 00360 pos += samplesToWrite_; 00361 setctrl("mrs_natural/pos", pos); 00362 return pos; 00363 } 00364 00365 realvec& 00366 WavFileSource2::getAudioRegion(mrs_natural startSample, mrs_natural endSample) 00367 { 00368 (void) startSample; // FIXME Unused parameters 00369 (void) endSample; 00370 00371 //fill audioRegion_ with corresponding audio data! 00372 // ... 00373 // ... 00374 00375 return audioRegion_; 00376 } 00377 00378 void 00379 WavFileSource2::myProcess(realvec& in, realvec& out) 00380 { 00381 (void) in; 00382 //in case of problems opening the .wav file, 00383 //or no audiodata available to read, just send silence 00384 if(!getctrl("mrs_bool/hasData")->to<mrs_bool>()) 00385 { 00386 out.setval(0.0); 00387 return; 00388 } 00389 00390 switch(bits_) 00391 { 00392 case 16: 00393 { 00394 //read audio samples from .wav file 00395 getLinear16(out); 00396 break; 00397 } 00398 case 8: 00399 { 00400 //getLinear8(out); [!] 00401 break; 00402 } 00403 } 00404 00405 //if reached end of file, signal it! 00406 if(getctrl("mrs_natural/pos")->to<mrs_natural>() >= size_) 00407 setctrl("mrs_bool/hasData", false); 00408 } 00409 00410 00411 00412 00413 00414 00415 00416 00417 00418 00419 00420 00421 00422 00423 00424 00425