CLAM-Development
1.1
|
00001 /* 00002 * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) 00003 * UNIVERSITAT POMPEU FABRA 00004 * 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 * 00020 */ 00021 00022 #if USE_OGGVORBIS != 1 00023 #error USE_OGGVORBIS was not set to 1 in your settings.cfg file, but you are including files that require this. Please fix your settings.cfg 00024 #endif 00025 00026 #include <cstdio> 00027 #include <string> 00028 #include <algorithm> 00029 #include <vorbis/vorbisfile.h> 00030 #include <iostream> 00031 #include "AudioFileFormats.hxx" 00032 #include "AudioFile.hxx" 00033 #include "OggVorbisCodec.hxx" 00034 #include "OggVorbisAudioStream.hxx" 00035 00036 namespace CLAM 00037 { 00038 00039 namespace AudioCodecs 00040 { 00041 OggVorbisCodec::OggVorbisCodec() 00042 { 00043 } 00044 00045 OggVorbisCodec::~OggVorbisCodec() 00046 { 00047 } 00048 00049 OggVorbisCodec& OggVorbisCodec::Instantiate() 00050 { 00051 static OggVorbisCodec theInstance; 00052 00053 return theInstance; 00054 } 00055 00056 bool OggVorbisCodec::IsReadable( std::string uri ) const 00057 { 00058 FILE* fileHandle; 00059 OggVorbis_File vorbisFile; 00060 00061 memset( &vorbisFile, 0, sizeof(OggVorbis_File) ); 00062 00063 fileHandle = fopen( uri.c_str(), "rb" ); 00064 00065 if ( !fileHandle || ferror(fileHandle) != 0 ) 00066 { 00067 //:TODO: possible exception throwing 00068 //std::cerr << uri << std::endl; 00069 //std::cerr << "Open failed! " << strerror( errno ) << std::endl; 00070 return false; 00071 } 00072 00073 int retval = ov_open( fileHandle, &vorbisFile, NULL, 0 ); 00074 00075 if ( retval < 0 ) 00076 { 00077 fclose( fileHandle ); 00078 00079 return false; 00080 } 00081 00082 // MRJ: No need to close the fileHandle since libvorbisfile takes 00083 // its ownership if the ov_open call is successful 00084 ov_clear( &vorbisFile ); 00085 00086 return true; 00087 00088 } 00089 00090 bool OggVorbisCodec::IsWritable( std::string uri, const AudioFileHeader& hdr ) const 00091 { 00092 // MRJ: These values were documented ( sort of ) in 00093 // the Vorbis I specification document 00094 00095 if ( (hdr.GetChannels() < 0) || ( hdr.GetChannels() > 255) ) 00096 return false; 00097 if ( (hdr.GetSampleRate() < 8000.) || ( hdr.GetSampleRate() > 192000.) ) 00098 return false; 00099 00100 return true; 00101 } 00102 00103 Stream* OggVorbisCodec::GetStreamFor( const AudioFile& file ) 00104 { 00105 return new OggVorbisAudioStream(file); 00106 } 00107 00108 void OggVorbisCodec::RetrieveHeaderData( std::string uri, AudioFileHeader& hdr ) 00109 { 00110 FILE* fileHandle; 00111 OggVorbis_File vorbisFile; 00112 00113 if ( ( fileHandle = fopen( uri.c_str(), "rb" ) ) == NULL ) 00114 return; 00115 00116 if ( ov_open( fileHandle, &vorbisFile, NULL, 0 ) < 0 ) 00117 { 00118 fclose( fileHandle ); 00119 return; 00120 } 00121 00122 vorbis_info* fileInfo = ov_info( &vorbisFile, -1 ); 00123 00124 if ( !fileInfo ) // File was encoded improperly 00125 return; 00126 00127 hdr.AddSampleRate(); 00128 hdr.AddChannels(); 00129 hdr.AddSamples(); 00130 hdr.AddFormat(); 00131 hdr.AddEncoding(); 00132 hdr.AddEndianess(); 00133 hdr.AddLength(); 00134 hdr.UpdateData(); 00135 00136 hdr.SetSampleRate( (TData)fileInfo->rate ); 00137 hdr.SetChannels( (TSize)fileInfo->channels ); 00138 hdr.SetLength( (TTime)ov_time_total( &vorbisFile, -1) * 1000. ); 00139 hdr.SetFormat( EAudioFileFormat::eVorbisMk1 ); 00140 hdr.SetEncoding( EAudioFileEncoding::eDefault ); 00141 hdr.SetEndianess( EAudioFileEndianess::eDefault ); 00142 00143 double duration = hdr.GetLength()/1000.; 00144 hdr.SetSamples( TSize(duration*hdr.GetSampleRate()) ); 00145 00146 // MRJ: No need to close the fileHandle since libvorbisfile takes 00147 // its ownership if the ov_open call is successful 00148 ov_clear( &vorbisFile ); 00149 } 00150 00151 void OggVorbisCodec::RetrieveTextDescriptors( std::string uri, AudioTextDescriptors& txtDesc ) 00152 { 00153 FILE* fileHandle; 00154 OggVorbis_File vorbisFile; 00155 00156 if ( ( fileHandle = fopen( uri.c_str(), "rb" ) ) == NULL ) 00157 return; 00158 00159 if ( ov_open( fileHandle, &vorbisFile, NULL, 0 ) < 0 ) 00160 { 00161 fclose( fileHandle ); 00162 return; 00163 } 00164 00165 vorbis_info* fileInfo = ov_info( &vorbisFile, -1 ); 00166 00167 if ( !fileInfo ) // File was encoded improperly 00168 return; 00169 00170 00171 vorbis_comment* fileComments = ov_comment( &vorbisFile, -1 ); 00172 00173 if ( !fileComments ) // there were no comments in the file! 00174 { 00175 return; 00176 } 00177 00178 int nComments = fileComments->comments; 00179 char** commentVector = fileComments->user_comments; 00180 int* commentLenVector = fileComments->comment_lengths; 00181 00182 for ( int i = 0; i < nComments; i++ ) 00183 { 00184 // convert the current comment string into a std::string 00185 std::string currentComment; 00186 currentComment.assign( commentVector[i], 00187 commentVector[i]+commentLenVector[i] ); 00188 00189 std::string::iterator eqPos = std::find( currentComment.begin(), 00190 currentComment.end(), '=' ); 00191 00192 if ( eqPos < currentComment.end() ) 00193 { 00194 std::string fieldName; 00195 fieldName.assign( currentComment.begin(), eqPos ); 00196 00197 if( fieldName == "ARTIST" ) 00198 { 00199 txtDesc.AddArtist(); 00200 txtDesc.UpdateData(); 00201 txtDesc.GetArtist().assign( eqPos+1, currentComment.end() ); 00202 } 00203 else if ( fieldName == "TITLE" ) 00204 { 00205 txtDesc.AddTitle(); 00206 txtDesc.UpdateData(); 00207 txtDesc.GetTitle().assign( eqPos+1, currentComment.end() ); 00208 } 00209 else if ( fieldName == "ALBUM" ) 00210 { 00211 txtDesc.AddAlbum(); 00212 txtDesc.UpdateData(); 00213 txtDesc.GetAlbum().assign( eqPos+1, currentComment.end() ); 00214 } 00215 else if ( fieldName == "TRACKNUMBER" ) 00216 { 00217 txtDesc.AddTrackNumber(); 00218 txtDesc.UpdateData(); 00219 txtDesc.GetTrackNumber().assign( eqPos+1, currentComment.end() ); 00220 } 00221 else if ( fieldName == "PERFORMER" ) 00222 { 00223 txtDesc.AddPerformer(); 00224 txtDesc.UpdateData(); 00225 txtDesc.GetPerformer().assign( eqPos+1, currentComment.end() ); 00226 } 00227 else if ( fieldName == "COMPOSER" ) 00228 { 00229 txtDesc.AddComposer(); 00230 txtDesc.UpdateData(); 00231 txtDesc.GetComposer().assign( eqPos+1, currentComment.end() ); 00232 } 00233 else 00234 { 00235 std::string msg = fieldName; 00236 msg+= ": Ignored comment field!"; 00237 //CLAM_WARNING( false, msg.c_str() ); 00238 } 00239 } 00240 00241 } 00242 00243 ov_clear( &vorbisFile ); 00244 } 00245 } 00246 00247 } 00248