00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
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>
00046 #include <esd.h>
00047 #include <unistd.h>
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
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
00137
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
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
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
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
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
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
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