Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/AuFileSink.cpp
Go to the documentation of this file.
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