00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "soundreader.h"
00021 #include "buffer.h"
00022
00023 #include <QtCore/QDebug>
00024
00025 #include <QtCore/QFile>
00026 #include <QtCore/QFileInfo>
00027 #include <QtGui/QMessageBox>
00028 #include <QtCore/QVector>
00029
00030 #include <ogg/ogg.h>
00031 #include <vorbis/codec.h>
00032 #include <vorbis/vorbisenc.h>
00033 #include <vorbis/vorbisfile.h>
00034 #include <sys/stat.h>
00035 #include <vector>
00036 #include <sndfile.h>
00037
00038 using namespace GluonAudio;
00039
00040 class SoundReader::SoundReaderPrivate
00041 {
00042 public:
00043 QString fileName;
00044 bool error;
00045 };
00046
00047 #define BUFFER_SIZE 32768 // 32 KB buffers
00048
00049 SoundReader::SoundReader( const QString& fileName )
00050 : d( new SoundReaderPrivate )
00051
00052 {
00053 d->fileName = fileName;
00054 d->error = false;
00055 if( !QFile::exists( fileName ) )
00056 {
00057 qDebug() << "Could not find file" << fileName;
00058 d->error = true;
00059 }
00060 }
00061
00062 SoundReader::~SoundReader()
00063 {
00064 delete d;
00065 }
00066
00067 bool SoundReader::canRead() const
00068 {
00069 return supportedSoundFormats().contains( format() );
00070 }
00071
00072 ALuint SoundReader::alBuffer()
00073 {
00074
00075 if( format() == "ogg" )
00076 {
00077 return fromOgg();
00078 }
00079
00080 if( format() == "wav" )
00081 {
00082 return fromWav();
00083 }
00084
00085 return 0;
00086 }
00087
00088 Buffer* SoundReader::buffer()
00089 {
00090 if( format() == "ogg" )
00091 {
00092 return new Buffer( fromOgg() );
00093 }
00094
00095 if( format() == "wav" )
00096 {
00097 return new Buffer( fromWav() );
00098 }
00099 d->error = true;
00100 return new Buffer();
00101 }
00102
00103 QStringList SoundReader::supportedSoundFormats()
00104 {
00105 return ( QStringList() << "wav" << "ogg" );
00106 }
00107
00108 ALuint SoundReader::fromWav()
00109 {
00110 SF_INFO fileInfos;
00111 SNDFILE* file = sf_open( d->fileName.toUtf8(), SFM_READ, &fileInfos );
00112
00113 if( !file )
00114 {
00115 qDebug() << "Could not load file:" << sf_strerror( file );
00116 return 0;
00117 }
00118
00119 ALsizei samplesNumber = static_cast<ALsizei>( fileInfos.channels * fileInfos.frames );
00120 ALsizei samplesRate = static_cast<ALsizei>( fileInfos.samplerate );
00121
00122
00123 std::vector<ALshort> samples( samplesNumber );
00124 if( sf_read_short( file, &samples[0], samplesNumber ) < samplesNumber )
00125 {
00126 qDebug() << "Could not read the sound data";
00127 return 0;
00128 }
00129
00130 sf_close( file );
00131
00132
00133 ALenum format;
00134 switch( fileInfos.channels )
00135 {
00136 case 1:
00137 format = AL_FORMAT_MONO16;
00138 break;
00139 case 2:
00140 format = AL_FORMAT_STEREO16;
00141 break;
00142 default :
00143 qDebug() << "Unsupported format: more than two channels";
00144 return 0;
00145 }
00146
00147 alGetError();
00148
00149 ALuint buffer;
00150 alGenBuffers( 1, &buffer );
00151 if( alGetError() != AL_NO_ERROR )
00152 {
00153 qDebug() << "Error generating buffer.";
00154 return 0;
00155 }
00156
00157 alBufferData( buffer, format, &samples[0], samplesNumber * sizeof( ALushort ), samplesRate );
00158
00159 int error = alGetError();
00160 if( error != AL_NO_ERROR )
00161 {
00162 qDebug() << "Could not read the samples: " << error;
00163 return 0;
00164 }
00165
00166 return buffer;
00167 }
00168 ALuint SoundReader::fromOgg()
00169 {
00170
00171 std::vector<char> buffer;
00172 ALenum format;
00173 ALsizei freq;
00174 int endian = 0;
00175 int bitStream;
00176 long bytes;
00177 char array[BUFFER_SIZE];
00178 FILE* f;
00179
00180
00181 f = fopen( d->fileName.toUtf8(), "rb" );
00182
00183 if( f == 0 )
00184 {
00185 qDebug() << "Cannot open " << d->fileName << " for reading...";
00186 return 0;
00187 }
00188
00189 vorbis_info* pInfo;
00190 OggVorbis_File oggFile;
00191
00192
00193 if( ov_open( f, &oggFile, 0, 0 ) )
00194 {
00195 qDebug() << "Error opening " << d->fileName << " for decoding...";
00196 return 0;
00197 }
00198
00199
00200 pInfo = ov_info( &oggFile, -1 );
00201
00202
00203 if( pInfo->channels == 1 )
00204 {
00205 format = AL_FORMAT_MONO16;
00206 }
00207 else
00208 {
00209 format = AL_FORMAT_STEREO16;
00210 }
00211
00212
00213 freq = pInfo->rate;
00214
00215
00216 do
00217 {
00218
00219 bytes = ov_read( &oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream );
00220
00221 if( bytes < 0 )
00222 {
00223 ov_clear( &oggFile );
00224 qDebug() << "Error decoding " << d->fileName << "..." ;
00225 return 0;
00226 }
00227
00228
00229 buffer.insert( buffer.end(), array, array + bytes );
00230 }
00231 while( bytes > 0 );
00232
00233
00234 ov_clear( &oggFile );
00235
00236
00237 alGetError();
00238 ALuint albuffer;
00239 alGenBuffers( 1, &albuffer );
00240 if( alGetError() != AL_NO_ERROR )
00241 {
00242 qDebug() << "Error generating buffer.";
00243 return 0;
00244 }
00245
00246 alBufferData( albuffer, format, &buffer[0], static_cast<ALsizei>( buffer.size() ), freq );
00247
00248 int error = alGetError();
00249 if( error != AL_NO_ERROR )
00250 {
00251 qDebug() << "Could not read the samples: " << error;
00252 return 0;
00253 }
00254
00255 return albuffer;
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 }
00286 QString SoundReader::fileName() const
00287 {
00288 return d->fileName;
00289 }
00290 QString SoundReader::format() const
00291 {
00292 QFileInfo file( d->fileName );
00293 return file.completeSuffix();
00294 }