00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "wavplugin.h"
00024
00025
00026 #include <opie2/odebug.h>
00027
00028
00029 #include <qfile.h>
00030
00031
00032 #include <stdio.h>
00033 #include <stdarg.h>
00034 #include <stdlib.h>
00035 #include <errno.h>
00036 #include <unistd.h>
00037
00038
00039 #define debugMsg(a)
00040
00041
00042 struct RiffChunk {
00043 char id[4];
00044 Q_UINT32 size;
00045 char data[4];
00046 };
00047
00048
00049 struct ChunkData {
00050 Q_INT16 formatTag;
00051 Q_INT16 channels;
00052 Q_INT32 samplesPerSec;
00053 Q_INT32 avgBytesPerSec;
00054 Q_INT16 blockAlign;
00055 Q_INT16 wBitsPerSample;
00056 };
00057
00058
00059 const int sound_buffer_size = 512;
00060
00061
00062 class WavPluginData {
00063 public:
00064 QFile *input;
00065
00066 int wavedata_remaining;
00067 ChunkData chunkdata;
00068 RiffChunk chunk;
00069 uchar data[sound_buffer_size+32];
00070 int out,max;
00071 int samples_due;
00072 int samples;
00073
00074 WavPluginData() {
00075 max = out = sound_buffer_size;
00076 wavedata_remaining = 0;
00077 samples_due = 0;
00078 samples = -1;
00079 }
00080
00081
00082 bool add( short *output, long count, long& done, bool stereo )
00083 {
00084 done = 0;
00085
00086 if ( input == 0 ) {
00087 odebug << "no input" << oendl;
00088 return FALSE;
00089 }
00090
00091 while ( count ) {
00092 int l,r;
00093 if ( getSample(l, r) == FALSE ) {
00094 odebug << "didn't get sample" << oendl;
00095 return FALSE;
00096 }
00097 samples_due += chunkdata.samplesPerSec;
00098 printf("samples due %d\r", samples_due);
00099 fflush(stdout);
00100 while ( count && (samples_due > chunkdata.samplesPerSec) ) {
00101 *output++ = l;
00102 if ( stereo )
00103 *output++ = r;
00104 samples_due -= chunkdata.samplesPerSec;
00105 count--;
00106 done++;
00107 }
00108 }
00109 return TRUE;
00110 }
00111
00112 bool initialise() {
00113 if ( input == 0 )
00114 return FALSE;
00115
00116 wavedata_remaining = -1;
00117
00118 while ( wavedata_remaining == -1 ) {
00119
00120 const int n = sizeof(chunk) - sizeof(chunk.data);
00121 int t = input->readBlock( (char*)&chunk, n );
00122 if ( t != n ) {
00123 if ( t == -1 )
00124 return FALSE;
00125 return TRUE;
00126 }
00127 if ( qstrncmp(chunk.id,"data",4) == 0 ) {
00128 samples = wavedata_remaining = chunk.size;
00129 } else if ( qstrncmp(chunk.id,"RIFF",4) == 0 ) {
00130 char d[4];
00131 if ( input->readBlock(d,4) != 4 ) {
00132 return FALSE;
00133 }
00134 if ( qstrncmp(d,"WAVE",4) != 0 ) {
00135
00136 if ( chunk.size > 1000000000 || !input->at(input->at()+chunk.size-4) ) {
00137 return FALSE;
00138 }
00139 }
00140 } else if ( qstrncmp(chunk.id,"fmt ",4) == 0 ) {
00141 if ( input->readBlock((char*)&chunkdata,sizeof(chunkdata)) != sizeof(chunkdata) ) {
00142 return FALSE;
00143 }
00144 #define WAVE_FORMAT_PCM 1
00145 if ( chunkdata.formatTag != WAVE_FORMAT_PCM ) {
00146 odebug << "WAV file: UNSUPPORTED FORMAT " << chunkdata.formatTag << "" << oendl;
00147 return FALSE;
00148 }
00149 } else {
00150
00151 if ( chunk.size > 1000000000 || !input->at(input->at()+chunk.size) ) {
00152 return FALSE;
00153 }
00154 }
00155 }
00156 odebug << "bits " << chunkdata.wBitsPerSample << "" << oendl;
00157 return TRUE;
00158 }
00159
00160
00161
00162 bool getSample(int& l, int& r)
00163 {
00164 l = r = 0;
00165
00166 if ( input == 0 )
00167 return FALSE;
00168
00169 if ( (wavedata_remaining < 0) || !max )
00170 return FALSE;
00171
00172 if ( out >= max ) {
00173 max = input->readBlock( (char*)data, (uint)QMIN(sound_buffer_size,wavedata_remaining) );
00174
00175 wavedata_remaining -= max;
00176
00177 out = 0;
00178 if ( max <= 0 ) {
00179 max = 0;
00180 return TRUE;
00181 }
00182 }
00183 if ( chunkdata.wBitsPerSample == 8 ) {
00184 l = (data[out++] - 128) * 128;
00185 } else {
00186 l = ((short*)data)[out/2];
00187 out += 2;
00188 }
00189 if ( chunkdata.channels == 1 ) {
00190 r = l;
00191 } else {
00192 if ( chunkdata.wBitsPerSample == 8 ) {
00193 r = (data[out++] - 128) * 128;
00194 } else {
00195 r = ((short*)data)[out/2];
00196 out += 2;
00197 }
00198 }
00199 return TRUE;
00200 }
00201
00202 };
00203
00204
00205 WavPlugin::WavPlugin() {
00206 d = new WavPluginData;
00207 d->input = 0;
00208 }
00209
00210
00211 WavPlugin::~WavPlugin() {
00212 close();
00213 delete d;
00214 }
00215
00216
00217 bool WavPlugin::isFileSupported( const QString& path ) {
00218
00219
00220 char *ext = strrchr( path.latin1(), '.' );
00221
00222
00223 if ( ext ) {
00224 if ( strncasecmp(ext, ".raw", 4) == 0 )
00225 return TRUE;
00226 if ( strncasecmp(ext, ".wav", 4) == 0 )
00227 return TRUE;
00228 if ( strncasecmp(ext, ".wave", 4) == 0 )
00229 return TRUE;
00230 }
00231
00232 return FALSE;
00233 }
00234
00235
00236 bool WavPlugin::open( const QString& path ) {
00237
00238
00239 d->max = d->out = sound_buffer_size;
00240 d->wavedata_remaining = 0;
00241 d->samples_due = 0;
00242
00243 d->input = new QFile( path );
00244 if ( d->input->open(IO_ReadOnly) == FALSE ) {
00245 odebug << "couldn't open file" << oendl;
00246 delete d->input;
00247 d->input = 0;
00248 return FALSE;
00249 }
00250
00251 d->initialise();
00252 qApp->processEvents();
00253
00254 return TRUE;
00255 }
00256
00257
00258 bool WavPlugin::close() {
00259
00260
00261 d->input->close();
00262 delete d->input;
00263 d->input = 0;
00264 return TRUE;
00265 }
00266
00267
00268 bool WavPlugin::isOpen() {
00269
00270 return ( d->input != 0 );
00271 }
00272
00273
00274 int WavPlugin::audioStreams() {
00275
00276 return 1;
00277 }
00278
00279
00280 int WavPlugin::audioChannels( int ) {
00281
00282 return d->chunkdata.channels;
00283 }
00284
00285
00286 int WavPlugin::audioFrequency( int ) {
00287
00288 return d->chunkdata.samplesPerSec;
00289 }
00290
00291
00292 int WavPlugin::audioSamples( int ) {
00293
00294 return d->samples / d->chunkdata.channels/2;
00295
00296 }
00297
00298
00299 bool WavPlugin::audioSetSample( long, int ) {
00300
00301 return FALSE;
00302 }
00303
00304
00305 long WavPlugin::audioGetSample( int ) {
00306
00307 return 0;
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 bool WavPlugin::audioReadSamples( short *output, int channels, long samples, long& samplesMade, int ) {
00336
00337 return d->add( output, samples, samplesMade, channels != 1 );
00338 }
00339
00340 double WavPlugin::getTime() {
00341
00342 return d->chunkdata.wBitsPerSample; ;
00343 }
00344
00345
00346
00347
00348
00349
00350