esdsound.h

Go to the documentation of this file.
00001 
00004 
00005 //
00006 // Copyright (c) 2001-2004 California Institute of Technology
00007 // Copyright (c) 2004-2007 University of Southern California
00008 // Rob Peters <rjpeters at usc dot edu>
00009 //
00010 // created: Thu May 24 18:13:53 2001
00011 // commit: $Id: esdsound.h 10065 2007-04-12 05:54:56Z rjpeters $
00012 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/media/esdsound.h $
00013 //
00014 // --------------------------------------------------------------------
00015 //
00016 // This file is part of GroovX.
00017 //   [http://ilab.usc.edu/rjpeters/groovx/]
00018 //
00019 // GroovX is free software; you can redistribute it and/or modify it
00020 // under the terms of the GNU General Public License as published by
00021 // the Free Software Foundation; either version 2 of the License, or
00022 // (at your option) any later version.
00023 //
00024 // GroovX is distributed in the hope that it will be useful, but
00025 // WITHOUT ANY WARRANTY; without even the implied warranty of
00026 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00027 // General Public License for more details.
00028 //
00029 // You should have received a copy of the GNU General Public License
00030 // along with GroovX; if not, write to the Free Software Foundation,
00031 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00032 //
00034 
00035 #ifndef GROOVX_MEDIA_ESDSOUND_H_UTC20050626084018_DEFINED
00036 #define GROOVX_MEDIA_ESDSOUND_H_UTC20050626084018_DEFINED
00037 
00038 #include "media/soundrep.h"
00039 
00040 #include "rutz/error.h"
00041 #include "rutz/fstring.h"
00042 #include "rutz/sfmt.h"
00043 #include "rutz/shared_ptr.h"
00044 
00045 #include <cstring> // for strncpy()
00046 #include <esd.h>
00047 #include <unistd.h> // for write(), close()
00048 
00049 #include "rutz/trace.h"
00050 #include "rutz/debug.h"
00051 GVX_DBG_REGISTER
00052 
00053 namespace media
00054 {
00056   class esd_sound_rep : public sound_rep
00057   {
00058   public:
00060     esd_sound_rep(const char* filename = 0);
00061 
00063     virtual ~esd_sound_rep() throw();
00064 
00066     virtual void play();
00067 
00068   private:
00069     rutz::fstring m_filename;
00070   };
00071 
00072 }
00073 
00074 namespace
00075 {
00076   struct af_error_info
00077   {
00078   private:
00079     af_error_info(const af_error_info&);
00080     af_error_info& operator=(const af_error_info&);
00081 
00082   public:
00083     af_error_info() throw() : error(false), code(0) {}
00084 
00085     void set(long v, const char* c) throw()
00086     {
00087       error = true;
00088       code = v;
00089       strncpy(&message[0], c, MSG_SIZE - 1);
00090       message[MSG_SIZE - 1] = '\0';
00091     }
00092 
00093     void reset() throw() { error = false; }
00094 
00095     rutz::fstring what() const
00096     {
00097       return rutz::sfmt("audiofile error: %s [error code = %ld]",
00098                         message, code);
00099     }
00100 
00101     static const int MSG_SIZE = 512;
00102 
00103     bool  error;
00104     long  code;
00105     char  message[MSG_SIZE];
00106   };
00107 
00108   af_error_info last_error;
00109 
00110   void af_error_handler(long v, const char* c) throw()
00111   {
00112     dbg_eval_nl(3, v);
00113     dbg_eval_nl(3, c);
00114 
00115     last_error.set(v, c);
00116   }
00117 }
00118 
00120 //
00121 // esd_sound_rep member definitions
00122 //
00124 
00125 media::esd_sound_rep::esd_sound_rep(const char* filename) :
00126   m_filename("")
00127 {
00128 GVX_TRACE("media::esd_sound_rep::esd_sound_rep");
00129 
00130   sound_rep::check_filename(filename);
00131 
00132   afSetErrorHandler(&af_error_handler);
00133 
00134   last_error.reset();
00135 
00136   // We just use afOpenFile to ensure that the filename refers to
00137   // a readable+valid file
00138   AFfilehandle audiofile = afOpenFile(filename, "r",
00139                                       static_cast<AFfilesetup>(0));
00140 
00141   if (audiofile == 0)
00142     {
00143       if (last_error.error == true)
00144         throw rutz::error(last_error.what(), SRC_POS);
00145       else
00146         throw rutz::error(rutz::sfmt("couldn't open sound file '%s'",
00147                                      filename), SRC_POS);
00148     }
00149 
00150   int close_result = afCloseFile(audiofile);
00151 
00152   if (close_result == -1)
00153     {
00154       if (last_error.error == true)
00155         throw rutz::error(last_error.what(), SRC_POS);
00156       else
00157         throw rutz::error(rutz::sfmt("error closing sound file '%s'",
00158                                      filename), SRC_POS);
00159     }
00160 
00161   m_filename = filename;
00162 }
00163 
00164 media::esd_sound_rep::~esd_sound_rep() throw() {}
00165 
00166 void media::esd_sound_rep::play()
00167 {
00168   GVX_TRACE("media::esd_sound_rep::play");
00169 
00170   if (m_filename.is_empty())
00171     return;
00172 
00173   const char* const fname = m_filename.c_str();
00174 
00175   dbg_eval_nl(3, fname);
00176 
00177   last_error.reset();
00178 
00179   // open the audio file
00180   const AFfilehandle in_file = afOpenFile(fname, "rb", NULL);
00181 
00182   if (in_file == 0)
00183     {
00184       if (last_error.error == true)
00185         throw rutz::error(last_error.what(), SRC_POS);
00186       else
00187         throw rutz::error(rutz::sfmt("couldn't open sound file '%s'",
00188                                      fname), SRC_POS);
00189     }
00190 
00191   // get audio file parameters
00192   const int frame_count = afGetFrameCount(in_file, AF_DEFAULT_TRACK);
00193   const int in_channels = afGetChannels(in_file, AF_DEFAULT_TRACK);
00194   const double in_rate = afGetRate(in_file, AF_DEFAULT_TRACK);
00195   int in_format = -1;
00196   int in_width = -1;
00197   afGetSampleFormat(in_file, AF_DEFAULT_TRACK, &in_format, &in_width);
00198 
00199   dbg_eval_nl(3, frame_count);
00200   dbg_eval_nl(3, in_channels);
00201   dbg_eval_nl(3, in_rate);
00202   dbg_eval_nl(3, in_format);
00203   dbg_eval_nl(3, in_width);
00204 
00205   // convert audiofile parameters to EsounD parameters
00206   int out_bits;
00207   if (in_width == 8)
00208     out_bits = ESD_BITS8;
00209   else if (in_width == 16)
00210     out_bits = ESD_BITS16;
00211   else
00212     {
00213       throw rutz::error
00214         (rutz::sfmt("while attempting to play sound file '%s': "
00215                     "only sample widths of 8 and 16 are supported",
00216                     fname), SRC_POS);
00217     }
00218 
00219   const int bytes_per_frame = (in_width * in_channels) / 8;
00220 
00221   dbg_eval_nl(3, bytes_per_frame);
00222 
00223   int out_channels;
00224   if (in_channels == 1)
00225     out_channels = ESD_MONO;
00226   else if (in_channels == 2)
00227     out_channels = ESD_STEREO;
00228   else
00229     {
00230       throw rutz::error
00231         (rutz::sfmt("while attempting to play sound file '%s': "
00232                     "only 1 or 2 channel samples are supported",
00233                     fname), SRC_POS);
00234     }
00235 
00236   const int out_mode = ESD_STREAM;
00237   const int out_func = ESD_PLAY;
00238 
00239   const esd_format_t out_format =
00240     out_bits | out_channels | out_mode | out_func;
00241 
00242   const int out_rate = int(in_rate);
00243 
00244   // connect to server
00245   const int out_sock = esd_play_stream(out_format, out_rate, NULL, fname);
00246 
00247   if (out_sock <= 0)
00248     {
00249       throw rutz::error
00250         (rutz::sfmt("while attempting to play sound file '%s': "
00251                     "couldn't open esd sound socket", fname),
00252          SRC_POS);
00253     }
00254 
00255   // play
00256   const int BUF_SIZE = 4096;
00257   char buf[BUF_SIZE];
00258   const int buf_frames = BUF_SIZE / bytes_per_frame;
00259 
00260   int frames_read = 0;
00261 
00262   int total_frames_read = 0;
00263 
00264 #ifdef DEBUG_SAMPLES
00265   FILE* fout = fopen("samples.txt", "w");
00266 #endif
00267 
00268   while ((frames_read = afReadFrames(in_file, AF_DEFAULT_TRACK,
00269                                      buf, buf_frames)) != 0)
00270     {
00271       if (last_error.error == true)
00272         throw rutz::error(last_error.what(), SRC_POS);
00273 
00274 #ifdef DEBUG_SAMPLES
00275       if (fout != 0)
00276         for (int i = 0; i < frames_read; ++i)
00277           {
00278             int val = 0;
00279 
00280             for (int j = 0; j < bytes_per_frame; ++j)
00281               val += (buf[i * bytes_per_frame + j] << (j*8));
00282 
00283             fprintf(fout, "%d\n", val);
00284           }
00285 #endif
00286 
00287       total_frames_read += frames_read;
00288 
00289       if (write(out_sock, buf, frames_read * bytes_per_frame) <= 0)
00290         break;
00291     }
00292 
00293 #ifdef DEBUG_SAMPLES
00294   if (fout != 0)
00295     fclose(fout);
00296 #endif
00297 
00298   // close up and go home
00299   close(out_sock);
00300   if (afCloseFile(in_file) != 0)
00301     {
00302       if (last_error.error == true)
00303         throw rutz::error(last_error.what(), SRC_POS);
00304       else
00305         throw rutz::error(rutz::sfmt("error closing sound file '%s'",
00306                                      fname), SRC_POS);
00307     }
00308 
00309   if (total_frames_read < frame_count)
00310     {
00311       dbg_print_nl(0, "low frame count; sound file is truncated?");
00312     }
00313 }
00314 
00315 static const char __attribute__((used)) vcid_groovx_media_esdsound_h_utc20050626084018[] = "$Id: esdsound.h 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00316 #endif // !GROOVX_MEDIA_ESDSOUND_H_UTC20050626084018_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:39 2008 by Doxygen version 1.5.5.