00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "music.h"
00020
00021 #include <QtCore/QDebug>
00022
00023 using namespace GluonAudio;
00024
00025 static const int BUFFER_SIZE = 4096 * 4;
00026
00027 Music::Music( QString fileName )
00028 {
00029 setFileName( fileName );
00030 }
00031
00032 void Music::open( std::string path )
00033 {
00034 int result;
00035
00036 if( !( oggFile = fopen( path.c_str(), "rb" ) ) )
00037 qDebug() << "Could not open Ogg file.";
00038
00039 if(( result = ov_open( oggFile, &oggStream, 0, 0 ) ) < 0 )
00040 {
00041 fclose( oggFile );
00042 qDebug() << "Could not open Ogg stream. ";
00043 }
00044
00045 vorbisInfo = ov_info( &oggStream, -1 );
00046 vorbisComment = ov_comment( &oggStream, -1 );
00047
00048 if( vorbisInfo->channels == 1 )
00049 {
00050 format = AL_FORMAT_MONO16;
00051 }
00052 else
00053 {
00054 format = AL_FORMAT_STEREO16;
00055 }
00056
00057 alGenBuffers( 2, buffers );
00058 check();
00059 alGenSources( 1, &source );
00060 check();
00061
00062 alSource3f( source, AL_POSITION, 0.0, 0.0, 0.0 );
00063 alSource3f( source, AL_VELOCITY, 0.0, 0.0, 0.0 );
00064 alSource3f( source, AL_DIRECTION, 0.0, 0.0, 0.0 );
00065 alSourcef( source, AL_ROLLOFF_FACTOR, 0.0 );
00066 alSourcei( source, AL_SOURCE_RELATIVE, AL_TRUE );
00067 }
00068
00069 void Music::release()
00070 {
00071 alSourceStop( source );
00072 empty();
00073 alDeleteSources( 1, &source );
00074 check();
00075 alDeleteBuffers( 1, buffers );
00076 check();
00077
00078 ov_clear( &oggStream );
00079 }
00080
00081 void Music::display()
00082 {
00083 qDebug()
00084 << "version " << vorbisInfo->version << "\n"
00085 << "channels " << vorbisInfo->channels << "\n"
00086 << "rate (hz) " << vorbisInfo->rate << "\n"
00087 << "bitrate upper " << vorbisInfo->bitrate_upper << "\n"
00088 << "bitrate nominal " << vorbisInfo->bitrate_nominal << "\n"
00089 << "bitrate lower " << vorbisInfo->bitrate_lower << "\n"
00090 << "bitrate window " << vorbisInfo->bitrate_window << "\n"
00091 << "\n"
00092 << "vendor " << vorbisComment->vendor << "\n";
00093
00094 for( int i = 0; i < vorbisComment->comments; ++i )
00095 {
00096 qDebug() << " " << vorbisComment->user_comments[i] << "\n";
00097 }
00098 }
00099
00100 bool Music::playback()
00101 {
00102 if( isPlaying() )
00103 {
00104 return true;
00105 }
00106
00107 if( !stream( buffers[0] ) )
00108 {
00109 return false;
00110 }
00111
00112 if( !stream( buffers[1] ) )
00113 {
00114 return false;
00115 }
00116
00117 alSourceQueueBuffers( source, 2, buffers );
00118 alSourcePlay( source );
00119
00120 return true;
00121 }
00122
00123 bool Music::isPlaying() const
00124 {
00125 ALenum state;
00126
00127 alGetSourcei( source, AL_SOURCE_STATE, &state );
00128
00129 return ( state == AL_PLAYING );
00130 }
00131
00132 bool Music::update()
00133 {
00134 int processed;
00135 bool active = true;
00136
00137 alGetSourcei( source, AL_BUFFERS_PROCESSED, &processed );
00138
00139 while( --processed )
00140 {
00141 ALuint buffer;
00142
00143 alSourceUnqueueBuffers( source, 1, &buffer );
00144 check();
00145
00146 active = stream( buffer );
00147
00148 alSourceQueueBuffers( source, 1, &buffer );
00149 check();
00150 }
00151
00152 return active;
00153 }
00154
00155 bool Music::stream( ALuint buffer )
00156 {
00157 char pcm[BUFFER_SIZE];
00158 int size = 0;
00159 int section;
00160 int result;
00161
00162 while( size < BUFFER_SIZE )
00163 {
00164 result = ov_read( &oggStream, pcm + size, BUFFER_SIZE - size, 0, 2, 1, §ion );
00165
00166 if( result > 0 )
00167 {
00168 size += result;
00169 }
00170 else
00171 {
00172 if( result < 0 )
00173 {
00174 qDebug() << "errorString(result)";
00175 }
00176 else
00177 {
00178 break;
00179 }
00180 }
00181 }
00182
00183 if( size == 0 )
00184 {
00185 return false;
00186 }
00187
00188 alBufferData( buffer, format, pcm, size, vorbisInfo->rate );
00189 check();
00190
00191 return true;
00192 }
00193
00194 void Music::empty()
00195 {
00196 int queued;
00197
00198 alGetSourcei( source, AL_BUFFERS_QUEUED, &queued );
00199
00200 while( --queued )
00201 {
00202 ALuint buffer;
00203
00204 alSourceUnqueueBuffers( source, 1, &buffer );
00205 check();
00206 }
00207 }
00208
00209 void Music::check()
00210 {
00211 int error = alGetError();
00212
00213 if( error != AL_NO_ERROR )
00214 {
00215 qDebug() << "OpenAL error was raised.";
00216 }
00217 }
00218
00219 std::string Music::errorString( int code )
00220 {
00221 switch( code )
00222 {
00223 case OV_EREAD:
00224 return std::string( "Read from media." );
00225 case OV_ENOTVORBIS:
00226 return std::string( "Not Vorbis data." );
00227 case OV_EVERSION:
00228 return std::string( "Vorbis version mismatch." );
00229 case OV_EBADHEADER:
00230 return std::string( "Invalid Vorbis header." );
00231 case OV_EFAULT:
00232 return std::string( "Internal logic fault (bug or heap/stack corruption." );
00233 default:
00234 return std::string( "Unknown Ogg error." );
00235 }
00236 }
00237
00238 void Music::run()
00239 {
00240 open( m_fileName.toUtf8().data() );
00241 display();
00242 if( !playback() )
00243 {
00244 qDebug() << "Ogg refused to play.";
00245 }
00246
00247 while( update() )
00248 {
00249 if( !isPlaying() )
00250 {
00251 if( !playback() )
00252 {
00253 qDebug() << "Ogg abruptly stopped.";
00254 }
00255 else
00256 {
00257 qDebug() << "Ogg stream was interrupted.\n";
00258 }
00259 }
00260 }
00261 release();
00262 }
00263
00264 #include "music.moc"