![]() |
Mixxx
|
00001 /*************************************************************************** 00002 soundsourceoggvorbis.cpp - ogg vorbis decoder 00003 ------------------- 00004 copyright : (C) 2003 by Svein Magne Bang 00005 email : 00006 ***************************************************************************/ 00007 00008 /*************************************************************************** 00009 * * 00010 * This program is free software; you can redistribute it and/or modify * 00011 * it under the terms of the GNU General Public License as published by * 00012 * the Free Software Foundation; either version 2 of the License, or * 00013 * (at your option) any later version. * 00014 * * 00015 ***************************************************************************/ 00016 00017 #include <taglib/vorbisfile.h> 00018 00019 #include "trackinfoobject.h" 00020 #include "soundsourceoggvorbis.h" 00021 #include <QtDebug> 00022 #ifdef __WINDOWS__ 00023 #include <io.h> 00024 #include <fcntl.h> 00025 #endif 00026 00027 #ifdef __APPLE__ 00028 #ifdef __i386 00029 #define OV_ENDIAN_ARG 0 00030 #else 00031 #define OV_ENDIAN_ARG 1 00032 #endif 00033 #endif 00034 00035 #ifdef __LINUX__ 00036 #include <endian.h> 00037 #if __BYTE_ORDER == __LITTLE_ENDIAN 00038 #define OV_ENDIAN_ARG 0 00039 #else 00040 #define OV_ENDIAN_ARG 1 00041 #endif 00042 #else 00043 #define OV_ENDIAN_ARG 0 00044 #endif 00045 00046 /* 00047 Class for reading Ogg Vorbis 00048 */ 00049 00050 SoundSourceOggVorbis::SoundSourceOggVorbis(QString qFilename) 00051 : Mixxx::SoundSource(qFilename) 00052 { 00053 filelength = 0; 00054 } 00055 00056 SoundSourceOggVorbis::~SoundSourceOggVorbis() 00057 { 00058 if (filelength > 0){ 00059 ov_clear(&vf); 00060 } 00061 } 00062 00063 int SoundSourceOggVorbis::open() 00064 { 00065 #ifdef __WINDOWS__ 00066 QByteArray qBAFilename = m_qFilename.toLocal8Bit(); 00067 if(ov_fopen(qBAFilename.data(), &vf) < 0) { 00068 qDebug() << "oggvorbis: Input does not appear to be an Ogg bitstream."; 00069 filelength = 0; 00070 return ERR; 00071 } 00072 #else 00073 QByteArray qBAFilename = m_qFilename.toUtf8(); 00074 FILE *vorbisfile = fopen(qBAFilename.data(), "r"); 00075 00076 if (!vorbisfile) { 00077 qDebug() << "oggvorbis: cannot open" << m_qFilename; 00078 return ERR; 00079 } 00080 00081 if(ov_open(vorbisfile, &vf, NULL, 0) < 0) { 00082 qDebug() << "oggvorbis: Input does not appear to be an Ogg bitstream."; 00083 filelength = 0; 00084 return ERR; 00085 } 00086 #endif 00087 00088 // lookup the ogg's channels and samplerate 00089 vorbis_info * vi = ov_info(&vf, -1); 00090 00091 channels = vi->channels; 00092 m_iSampleRate = vi->rate; 00093 00094 if(channels > 2){ 00095 qDebug() << "oggvorbis: No support for more than 2 channels!"; 00096 ov_clear(&vf); 00097 filelength = 0; 00098 return ERR; 00099 } 00100 00101 // ov_pcm_total returns the total number of frames in the ogg file. The 00102 // frame is the channel-independent measure of samples. The total samples in 00103 // the file is channels * ov_pcm_total. rryan 7/2009 I verified this by 00104 // hand. a 30 second long 48khz mono ogg and a 48khz stereo ogg both report 00105 // 1440000 for ov_pcm_total. 00106 ogg_int64_t ret = ov_pcm_total(&vf, -1); 00107 00108 if (ret >= 0) { 00109 // We pretend that the file is stereo to the rest of the world. 00110 filelength = ret * 2; 00111 } 00112 else //error 00113 { 00114 if (ret == OV_EINVAL) { 00115 //The file is not seekable. Not sure if any action is needed. 00116 } 00117 } 00118 00119 return OK; 00120 00121 } 00122 00123 /* 00124 seek to <filepos> 00125 */ 00126 00127 long SoundSourceOggVorbis::seek(long filepos) 00128 { 00129 // In our speak, filepos is a sample in the file abstraction (i.e. it's 00130 // stereo no matter what). filepos/2 is the frame we want to seek to. 00131 Q_ASSERT(filepos%2==0); 00132 00133 if (ov_seekable(&vf)){ 00134 if(ov_pcm_seek(&vf, filepos/2) != 0) { 00135 // This is totally common (i.e. you're at EOF). Let's not leave this 00136 // qDebug on. 00137 00138 // qDebug() << "ogg vorbis: Seek ERR on seekable."; 00139 } 00140 00141 // Even if an error occured, return them the current position because 00142 // that's what we promised. (Double it because ov_pcm_tell returns 00143 // frames and we pretend to the world that everything is stereo) 00144 return ov_pcm_tell(&vf) * 2; 00145 } else{ 00146 qDebug() << "ogg vorbis: Seek ERR."; 00147 return 0; 00148 } 00149 } 00150 00151 00152 /* 00153 read <size> samples into <destination>, and return the number of 00154 samples actually read. 00155 */ 00156 00157 unsigned SoundSourceOggVorbis::read(volatile unsigned long size, const SAMPLE * destination) 00158 { 00159 00160 Q_ASSERT(size%2==0); 00161 00162 char *pRead = (char*) destination; 00163 SAMPLE *dest = (SAMPLE*) destination; 00164 00165 00166 00167 // 'needed' is size of buffer in bytes. 'size' is size in SAMPLEs, 00168 // which is 2 bytes. If the stream is mono, we read 'size' bytes, 00169 // so that half the buffer is full, then below we double each 00170 // sample on the left and right channel. If the stream is stereo, 00171 // then ov_read interleaves the samples into the full length of 00172 // the buffer. 00173 00174 // ov_read speaks bytes, we speak words. needed is the bytes to 00175 // read, not words to read. 00176 00177 // size is the maximum space in words that we have in 00178 // destination. For stereo files, read the full buffer (size*2 00179 // bytes). For mono files, only read half the buffer (size bytes), 00180 // and we will double the buffer to be in stereo later. 00181 unsigned int needed = size * channels; 00182 00183 unsigned int index=0,ret=0; 00184 00185 // loop until requested number of samples has been retrieved 00186 while (needed > 0) { 00187 // read samples into buffer 00188 ret = ov_read(&vf, pRead+index, needed, OV_ENDIAN_ARG, 2, 1, ¤t_section); 00189 00190 if (ret <= 0) { 00191 // An error or EOF occured, break out and return what we have sofar. 00192 break; 00193 } 00194 00195 index += ret; 00196 needed -= ret; 00197 } 00198 00199 // As of here, index is the total bytes read. (index/2/channels) is the 00200 // total frames read. 00201 00202 // convert into stereo if file is mono 00203 if (channels == 1) { 00204 // rryan 2/2009 00205 // Mini-proof of the below: 00206 // size = 20, destination is a 20 element array 0-19 00207 // readNo = 10 (or less, but 10 in this case) 00208 // i = 10-1 = 9, so dest[9*2] and dest[9*2+1], 00209 // so the first iteration touches the very ends of destination 00210 // on the last iteration, dest[0] and dest[1] are assigned to dest[0] 00211 for(int i=(index/2-1); i>=0; i--) { 00212 dest[i*2] = dest[i]; 00213 dest[(i*2)+1] = dest[i]; 00214 } 00215 00216 // Pretend we read twice as many bytes as we did, since we just repeated 00217 // each pair of bytes. 00218 index *= 2; 00219 } 00220 00221 // index is the total bytes read, so the words read is index/2 00222 return index / 2; 00223 } 00224 00225 /* 00226 Parse the the file to get metadata 00227 */ 00228 int SoundSourceOggVorbis::parseHeader() { 00229 setType("ogg"); 00230 00231 #ifdef __WINDOWS__ 00232 /* From Tobias: A Utf-8 string did not work on my Windows XP (German edition) 00233 * If you try this conversion, f.isValid() will return false in many cases 00234 * and processTaglibFile() will fail 00235 * 00236 * The method toLocal8Bit() returns the local 8-bit representation of the string as a QByteArray. 00237 * The returned byte array is undefined if the string contains characters not supported 00238 * by the local 8-bit encoding. 00239 */ 00240 QByteArray qBAFilename = m_qFilename.toLocal8Bit(); 00241 #else 00242 QByteArray qBAFilename = m_qFilename.toUtf8(); 00243 #endif 00244 TagLib::Ogg::Vorbis::File f(qBAFilename.constData()); 00245 00246 // Takes care of all the default metadata 00247 bool result = processTaglibFile(f); 00248 00249 00250 TagLib::Ogg::XiphComment *tag = f.tag(); 00251 00252 if (tag) { 00253 processXiphComment(tag); 00254 } 00255 00256 if (result) 00257 return OK; 00258 return ERR; 00259 } 00260 00261 /* 00262 Return the length of the file in samples. 00263 */ 00264 00265 inline long unsigned SoundSourceOggVorbis::length() 00266 { 00267 return filelength; 00268 } 00269 00270 QList<QString> SoundSourceOggVorbis::supportedFileExtensions() 00271 { 00272 QList<QString> list; 00273 list.push_back("ogg"); 00274 return list; 00275 }