Marsyas
0.6.0-alpha
|
00001 /* 00002 ** Copyright (C) 1998-2011 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 00020 #include "../common_source.h" 00021 00022 00023 00024 00025 00026 00027 00028 #include "AuFileSource.h" 00029 00030 00031 #ifdef MARSYAS_WIN32 00032 #ifndef MARSYAS_CYGWIN 00033 typedef __int32 int32_t; 00034 #endif 00035 #else 00036 #include <stdint.h> 00037 #endif 00038 00039 #include <cstddef> 00040 00041 using std::size_t; 00042 00043 /******** NeXT/Sun Soundfile Header Struct *******/ 00044 struct Marsyas::snd_header 00045 { 00046 char pref[4]; 00047 int32_t hdrLength; 00048 int32_t fileLength; 00049 int32_t mode; 00050 int32_t srate; 00051 int32_t channels; 00052 char comment[1024]; 00053 }; 00054 00055 00056 00057 /* Array containing descriptions of 00058 the various formats for the samples 00059 of the Next .snd/ Sun .au format */ 00060 00061 00062 using std::ostringstream; 00063 using namespace Marsyas; 00064 00065 #define SND_MAGIC_NUM 0x2e736e64 00066 00067 /* types of .snd files */ 00068 #define SND_FORMAT_UNSPECIFIED 0 00069 #define SND_FORMAT_MULAW_8 1 00070 #define SND_FORMAT_LINEAR_8 2 00071 #define SND_FORMAT_LINEAR_16 3 00072 #define SND_FORMAT_LINEAR_24 4 00073 #define SND_FORMAT_LINEAR_32 5 00074 #define SND_FORMAT_FLOAT 6 00075 00076 AuFileSource::AuFileSource(mrs_string name):AbsSoundFileSource("AuFileSource",name) 00077 { 00078 //type_ = "SoundFileSource";//"AuFileSource"?!? 00079 //name_ = name 00080 00081 sdata_ = 0; 00082 cdata_ = 0; 00083 sfp_ = 0; 00084 pos_ =0; 00085 hdr_ = new snd_header; 00086 sndFormats_.push_back("Unspecified format"); 00087 sndFormatSizes_.push_back(0); 00088 sndFormats_.push_back("Mulaw 8-bit"); 00089 sndFormatSizes_.push_back(1); 00090 sndFormats_.push_back("Linear 8-bit"); 00091 sndFormatSizes_.push_back(1); 00092 sndFormats_.push_back("Linear 16-bit"); 00093 sndFormatSizes_.push_back(2); 00094 sndFormats_.push_back("Linear 24-bit"); 00095 sndFormatSizes_.push_back(3); 00096 sndFormats_.push_back("Linear 32-bit"); 00097 sndFormatSizes_.push_back(4); 00098 sndFormats_.push_back("Float"); 00099 sndFormatSizes_.push_back(4); 00100 sndFormats_.push_back("Double"); 00101 sndFormatSizes_.push_back(8); 00102 00103 addControls(); 00104 } 00105 00106 AuFileSource::~AuFileSource() 00107 { 00108 00109 delete [] sdata_; 00110 delete [] cdata_; 00111 delete hdr_; 00112 00113 if (sfp_ != NULL) 00114 fclose(sfp_); 00115 } 00116 00117 MarSystem* 00118 AuFileSource::clone() const 00119 { 00120 return new AuFileSource(*this); 00121 } 00122 00123 00124 AuFileSource::AuFileSource(const AuFileSource& a): AbsSoundFileSource(a) 00125 { 00126 00127 ctrl_pos_ = getctrl("mrs_natural/pos"); 00128 ctrl_size_ = getctrl("mrs_natural/size"); 00129 ctrl_currentlyPlaying_ = getctrl("mrs_string/currentlyPlaying"); 00130 ctrl_previouslyPlaying_ = getctrl("mrs_string/previouslyPlaying"); 00131 ctrl_regression_ = getctrl("mrs_bool/regression"); 00132 ctrl_currentLabel_ = getctrl("mrs_real/currentLabel"); 00133 ctrl_previousLabel_ = getctrl("mrs_real/previousLabel"); 00134 ctrl_nLabels_ = getctrl("mrs_natural/nLabels"); 00135 ctrl_labelNames_ = getctrl("mrs_string/labelNames"); 00136 ctrl_currentHasData_ = getctrl("mrs_bool/currentHasData"); 00137 hdr_ = new snd_header; 00138 00139 } 00140 00141 00142 00143 00144 void 00145 AuFileSource::addControls() 00146 { 00147 addctrl("mrs_bool/hasData", true); 00148 addctrl("mrs_bool/lastTickWithData", false); 00149 00150 addctrl("mrs_natural/pos", (mrs_natural)0, ctrl_pos_); 00151 setctrlState("mrs_natural/pos", true); 00152 00153 addctrl("mrs_natural/loopPos", (mrs_natural)0); 00154 setctrlState("mrs_natural/loopPos", true); 00155 00156 addctrl("mrs_string/filename", "daufile"); 00157 setctrlState("mrs_string/filename", true); 00158 addctrl("mrs_natural/size", (mrs_natural)0, ctrl_size_); 00159 addctrl("mrs_string/filetype", "au"); 00160 00161 addctrl("mrs_real/repetitions", 1.0); 00162 setctrlState("mrs_real/repetitions", true); 00163 00164 addctrl("mrs_real/duration", -1.0); 00165 setctrlState("mrs_real/duration", true); 00166 00167 addctrl("mrs_natural/advance", 0); 00168 setctrlState("mrs_natural/advance", true); 00169 00170 addctrl("mrs_bool/shuffle", false); 00171 setctrlState("mrs_bool/shuffle", true); 00172 00173 addctrl("mrs_natural/cindex", 0); 00174 setctrlState("mrs_natural/cindex", true); 00175 00176 addctrl("mrs_string/allfilenames", ","); 00177 setctrlState("mrs_string/allfilenames", true); 00178 addctrl("mrs_natural/numFiles", 1); 00179 00180 addctrl("mrs_string/currentlyPlaying", "daufile", ctrl_currentlyPlaying_); 00181 addctrl("mrs_string/previouslyPlaying", "daufile", ctrl_previouslyPlaying_); 00182 addctrl("mrs_bool/regression", false, ctrl_regression_); 00183 addctrl("mrs_real/currentLabel", 0.0, ctrl_currentLabel_); 00184 addctrl("mrs_real/previousLabel", 0.0, ctrl_previousLabel_); 00185 addctrl("mrs_natural/nLabels", 0, ctrl_nLabels_); 00186 addctrl("mrs_string/labelNames", ",", ctrl_labelNames_); 00187 00188 addctrl("mrs_bool/currentHasData", true, ctrl_currentHasData_); 00189 addctrl("mrs_bool/currentLastTickWithData", false, ctrl_currentLastTickWithData_); 00190 } 00191 00192 unsigned long 00193 AuFileSource::ByteSwapLong(unsigned long nLongNumber) 00194 { 00195 return (((nLongNumber&0x000000FF)<<24)+((nLongNumber&0x0000FF00)<<8)+ 00196 ((nLongNumber&0x00FF0000)>>8)+((nLongNumber&0xFF000000)>>24)); 00197 } 00198 00199 unsigned short 00200 AuFileSource::ByteSwapShort (unsigned short nValue) 00201 { 00202 return (static_cast<unsigned short>((nValue & 0xff00) >> 8) | 00203 static_cast<unsigned short>((nValue & 0xff) << 8)); 00204 } 00205 00206 void 00207 AuFileSource::getHeader(mrs_string filename) 00208 { 00209 if (sfp_ != NULL) 00210 fclose(sfp_); 00211 sfp_ = fopen(filename.c_str(), "rb"); 00212 if (sfp_) 00213 { 00214 size_t n = fread(hdr_, sizeof(snd_header), 1, sfp_); 00215 if ((n != 1) ||((hdr_->pref[0] != '.') &&(hdr_->pref[1] != 's'))) 00216 { 00217 MRSWARN("Filename " + filename + " is not correct .au file \n or has settings that are not supported in Marsyas"); 00218 setctrl("mrs_natural/onObservations", (mrs_natural)1); 00219 setctrl("mrs_real/israte", (mrs_real)22050.0); 00220 setctrl("mrs_natural/size", (mrs_natural)0); 00221 hasData_ = false; 00222 lastTickWithData_ = true; 00223 setctrl("mrs_bool/hasData", false); 00224 setctrl("mrs_bool/lastTickWithData", true); 00225 } 00226 else 00227 { 00228 #if defined(MARSYAS_BIGENDIAN) 00229 hdr_->hdrLength = hdr_->hdrLength; 00230 hdr_->comment[hdr_->hdrLength-24] = '\0'; 00231 hdr_->srate = hdr_->srate; 00232 hdr_->channels = hdr_->channels; 00233 hdr_->mode = hdr_->mode; 00234 hdr_->fileLength = hdr_->fileLength; 00235 #else 00236 hdr_->hdrLength = ByteSwapLong(hdr_->hdrLength); 00237 hdr_->comment[hdr_->hdrLength-24] = '\0'; 00238 hdr_->srate = ByteSwapLong(hdr_->srate); 00239 hdr_->channels = ByteSwapLong(hdr_->channels); 00240 hdr_->mode = ByteSwapLong(hdr_->mode); 00241 hdr_->fileLength = ByteSwapLong(hdr_->fileLength); 00242 #endif 00243 00244 sampleSize_ = 2; 00245 size_ = (hdr_->fileLength) / sndFormatSizes_[hdr_->mode] / hdr_->channels; 00246 // csize_ = size_ * hdr_->channels; 00247 csize_ = size_; 00248 00249 fseek(sfp_, hdr_->hdrLength, 0); 00250 sfp_begin_ = ftell(sfp_); 00251 setctrl("mrs_natural/onObservations", (mrs_natural)hdr_->channels); 00252 00253 setctrl("mrs_real/israte", (mrs_real)hdr_->srate); 00254 setctrl("mrs_natural/size", size_); 00255 ctrl_currentlyPlaying_->setValue(filename, NOUPDATE); 00256 ctrl_previouslyPlaying_->setValue(filename, NOUPDATE); 00257 ctrl_currentLabel_->setValue(0.0, NOUPDATE); 00258 ctrl_previousLabel_->setValue(0.0, NOUPDATE); 00259 ctrl_labelNames_->setValue(",", NOUPDATE); 00260 ctrl_nLabels_->setValue(0, NOUPDATE); 00261 setctrl("mrs_bool/hasData", true); 00262 hasData_ = true; 00263 lastTickWithData_ = false; 00264 samplesOut_ = 0; 00265 pos_ = 0; 00266 setctrl("mrs_natural/pos", 0); 00267 } 00268 } 00269 else 00270 { 00271 setctrl("mrs_natural/onObservations", (mrs_natural)1); 00272 setctrl("mrs_real/israte", (mrs_real)22050.0); 00273 setctrl("mrs_natural/size", (mrs_natural)0); 00274 hasData_ = false; 00275 setctrl("mrs_bool/hasData", false); 00276 lastTickWithData_ = true; 00277 setctrl("mrs_bool/lastTickWithData", true); 00278 pos_ = 0; 00279 } 00280 nChannels_ = getctrl("mrs_natural/onObservations")->to<mrs_natural>(); 00281 samplesRead_ = 0; 00282 } 00283 00284 mrs_natural 00285 AuFileSource::getLinear16(realvec& slice) 00286 { 00287 mrs_natural c,t =0; 00288 00289 // read samples 00290 fseek(sfp_, 2 * pos_ * nChannels_ + sfp_begin_, SEEK_SET); 00291 samplesRead_ = (mrs_natural)fread(sdata_, sizeof(short), samplesToRead_, sfp_); 00292 00293 00294 // pad with zeros if necessary 00295 if ((samplesRead_ != samplesToRead_)&&(samplesRead_ != 0)) 00296 { 00297 for (c=0; c < nChannels_; ++c) 00298 for (t=0; t < inSamples_; t++) 00299 slice(c, t) = 0.0; 00300 samplesToWrite_ = samplesRead_ / nChannels_; 00301 } 00302 else // default case - read enough samples or no samples in which case zero output 00303 { 00304 samplesToWrite_ = inSamples_; 00305 00306 // if there are no more samples output zeros 00307 if (samplesRead_ == 0) 00308 for (t=0; t < inSamples_; t++) 00309 { 00310 nt_ = nChannels_ * t; 00311 for (c=0; c < nChannels_; ++c) 00312 { 00313 sdata_[nt_ + c] = 0; 00314 } 00315 } 00316 } 00317 00318 // write the read samples to output slice once for each channel 00319 for (t=0; t < samplesToWrite_; t++) 00320 { 00321 sval_ = 0; 00322 nt_ = nChannels_ * t; 00323 00324 #if defined(MARSYAS_BIGENDIAN) 00325 for (c=0; c < nChannels_; ++c) 00326 slice(c, t) = ((mrs_real) sdata_[nt_ + c] / (PCM_FMAXSHRT)); 00327 #else 00328 for (c=0; c < nChannels_; ++c) 00329 { 00330 usval_ = sdata_[nt_ + c]; 00331 usval_ = ByteSwapShort (usval_); 00332 sval_ = usval_; 00333 slice(c, t) = (mrs_real) sval_ / (PCM_FMAXSHRT); 00334 } 00335 #endif 00336 } 00337 pos_ += samplesToWrite_; 00338 return pos_; 00339 } 00340 00341 void 00342 AuFileSource::myUpdate(MarControlPtr sender) 00343 { 00344 (void) sender; //suppress warning of unused parameter(s) 00345 nChannels_ = getctrl("mrs_natural/onObservations")->to<mrs_natural>(); 00346 inSamples_ = getctrl("mrs_natural/inSamples")->to<mrs_natural>(); 00347 inObservations_ = getctrl("mrs_natural/inObservations")->to<mrs_natural>(); 00348 israte_ = getctrl("mrs_real/israte")->to<mrs_real>(); 00349 00350 setctrl("mrs_natural/onSamples", inSamples_); 00351 setctrl("mrs_natural/onObservations", nChannels_); 00352 00353 setctrl("mrs_real/osrate", israte_); 00354 00355 filename_ = getctrl("mrs_string/filename")->to<mrs_string>(); 00356 pos_ = getctrl("mrs_natural/pos")->to<mrs_natural>(); 00357 rewindpos_ = getctrl("mrs_natural/loopPos")->to<mrs_natural>(); 00358 00359 delete [] sdata_; 00360 delete [] cdata_; 00361 00362 sdata_ = new short[inSamples_ * nChannels_]; 00363 cdata_ = new unsigned char[inSamples_ * nChannels_]; 00364 00365 repetitions_ = getctrl("mrs_real/repetitions")->to<mrs_real>(); 00366 00367 duration_ = getctrl("mrs_real/duration")->to<mrs_real>(); 00368 advance_ = getctrl("mrs_natural/advance")->to<mrs_natural>(); 00369 cindex_ = getctrl("mrs_natural/cindex")->to<mrs_natural>(); 00370 00371 if (duration_ != -1.0) 00372 { 00373 csize_ = (mrs_natural)(duration_ * israte_ ); 00374 } 00375 00376 //defaultUpdate(); [!] 00377 00378 samplesToRead_ = inSamples_ * nChannels_; 00379 } 00380 00381 void 00382 AuFileSource::myProcess(realvec& in, realvec &out) 00383 { 00384 00385 00386 (void) in; 00387 if (ctrl_size_->to<mrs_natural>() != 0) 00388 { 00389 //checkFlow(in,out); 00390 00391 switch (hdr_->mode) 00392 { 00393 case SND_FORMAT_UNSPECIFIED: 00394 { 00395 MRSWARN("AuFileSource::Unspecified format"); 00396 updControl("mrs_natural/pos", pos_); 00397 updControl("mrs_bool/hasData", (pos_ < size_ * nChannels_)); 00398 break; 00399 } 00400 case SND_FORMAT_MULAW_8: 00401 { 00402 MRSWARN("MU_LAW for now not supported"); 00403 updControl("mrs_natural/pos", pos_); 00404 updControl("mrs_bool/hasData", (pos_ < size_ * nChannels_)); 00405 break; 00406 } 00407 case SND_FORMAT_LINEAR_8: 00408 { 00409 // pos_ = getLinear8(c, out); 00410 setctrl("mrs_natural/pos", pos_); 00411 setctrl("mrs_bool/hasData", pos_ < size_ * nChannels_); 00412 break; 00413 } 00414 case SND_FORMAT_LINEAR_16: 00415 { 00416 getLinear16(out); 00417 ctrl_pos_->setValue(pos_, NOUPDATE); 00418 00419 if (pos_ >= rewindpos_ + csize_) 00420 { 00421 if (repetitions_ != 1) 00422 { 00423 pos_ = rewindpos_; 00424 } 00425 00426 } 00427 00428 samplesOut_ += onSamples_; 00429 00430 if (repetitions_ != 1) 00431 { 00432 hasData_ = (samplesOut_ < repetitions_ * csize_); 00433 lastTickWithData_ = ((samplesOut_ + onSamples_>= repetitions_ * csize_) && hasData_); 00434 } 00435 else 00436 { 00437 hasData_ = pos_ < rewindpos_ + csize_; 00438 lastTickWithData_ = ((samplesOut_ + onSamples_>= repetitions_ * csize_) && hasData_); 00439 } 00440 00441 00442 if (repetitions_ == -1) 00443 { 00444 hasData_ = true; 00445 lastTickWithData_ = false; 00446 } 00447 00448 break; 00449 } 00450 case SND_FORMAT_FLOAT: 00451 { 00452 // getfloat(win); 00453 break; 00454 } 00455 default: 00456 { 00457 mrs_string warn = "File mode"; 00458 warn += sndFormats_[hdr_->mode]; 00459 warn += "("; 00460 warn += (char) hdr_->mode; 00461 warn += ") is not supported for now"; 00462 MRSWARN(warn); 00463 } 00464 } 00465 } 00466 ctrl_currentHasData_->setValue(hasData_); 00467 ctrl_currentLastTickWithData_->setValue(lastTickWithData_); 00468 }