MP3FileReader.cpp

Go to the documentation of this file.
00001 
00002 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00003 
00004 /*
00005     Sonic Visualiser
00006     An audio file viewer and annotation editor.
00007     Centre for Digital Music, Queen Mary, University of London.
00008     This file copyright 2006 Chris Cannam.
00009     
00010     This program is free software; you can redistribute it and/or
00011     modify it under the terms of the GNU General Public License as
00012     published by the Free Software Foundation; either version 2 of the
00013     License, or (at your option) any later version.  See the file
00014     COPYING included with this distribution for more information.
00015 */
00016 
00017 #ifdef HAVE_MAD
00018 
00019 #include "MP3FileReader.h"
00020 #include "ProgressPrinter.h"
00021 
00022 #include "system/System.h"
00023 
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <fcntl.h>
00027 
00028 #include <iostream>
00029 
00030 #ifdef HAVE_ID3TAG
00031 #include <id3tag.h>
00032 #endif
00033 #define DEBUG_ID3TAG 1
00034 
00035 #include <QApplication>
00036 #include <QFileInfo>
00037 #include <QProgressDialog>
00038 
00039 MP3FileReader::MP3FileReader(FileSource source, DecodeMode decodeMode, 
00040                              CacheMode mode, size_t targetRate) :
00041     CodedAudioFileReader(mode, targetRate),
00042     m_source(source),
00043     m_path(source.getLocalFilename()),
00044     m_decodeThread(0)
00045 {
00046     m_channelCount = 0;
00047     m_fileRate = 0;
00048     m_fileSize = 0;
00049     m_bitrateNum = 0;
00050     m_bitrateDenom = 0;
00051     m_cancelled = false;
00052     m_completion = 0;
00053     m_done = false;
00054     m_progress = 0;
00055 
00056     struct stat stat;
00057     if (::stat(m_path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) {
00058         m_error = QString("File %1 does not exist.").arg(m_path);
00059         return;
00060     }
00061 
00062     m_fileSize = stat.st_size;
00063 
00064     int fd = -1;
00065     if ((fd = ::open(m_path.toLocal8Bit().data(), O_RDONLY
00066 #ifdef _WIN32
00067                      | O_BINARY
00068 #endif
00069                      , 0)) < 0) {
00070         m_error = QString("Failed to open file %1 for reading.").arg(m_path);
00071         return;
00072     }   
00073 
00074     m_filebuffer = 0;
00075     m_samplebuffer = 0;
00076     m_samplebuffersize = 0;
00077 
00078     try {
00079         m_filebuffer = new unsigned char[m_fileSize];
00080     } catch (...) {
00081         m_error = QString("Out of memory");
00082         ::close(fd);
00083         return;
00084     }
00085     
00086     ssize_t sz = 0;
00087     size_t offset = 0;
00088     while (offset < m_fileSize) {
00089         sz = ::read(fd, m_filebuffer + offset, m_fileSize - offset);
00090         if (sz < 0) {
00091             m_error = QString("Read error for file %1 (after %2 bytes)")
00092                 .arg(m_path).arg(offset);
00093             delete[] m_filebuffer;
00094             ::close(fd);
00095             return;
00096         } else if (sz == 0) {
00097             std::cerr << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes")
00098                 .arg(offset).arg(m_fileSize).toStdString() << std::endl;
00099             m_fileSize = offset;
00100             break;
00101         }
00102         offset += sz;
00103     }
00104 
00105     ::close(fd);
00106 
00107     loadTags();
00108 
00109     if (decodeMode == DecodeAtOnce) {
00110 
00111         if (dynamic_cast<QApplication *>(QCoreApplication::instance())) {
00112             m_progress = new QProgressDialog
00113                 (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()),
00114                  QObject::tr("Stop"), 0, 100);
00115             m_progress->hide();
00116         } else {
00117             ProgressPrinter *pp = new ProgressPrinter(tr("Decoding..."), this);
00118             connect(this, SIGNAL(progress(int)), pp, SLOT(progress(int)));
00119         }
00120 
00121         if (!decode(m_filebuffer, m_fileSize)) {
00122             m_error = QString("Failed to decode file %1.").arg(m_path);
00123         }
00124         
00125         delete[] m_filebuffer;
00126         m_filebuffer = 0;
00127 
00128         if (isDecodeCacheInitialised()) finishDecodeCache();
00129 
00130         delete m_progress;
00131         m_progress = 0;
00132 
00133     } else {
00134 
00135         m_decodeThread = new DecodeThread(this);
00136         m_decodeThread->start();
00137 
00138         while ((m_channelCount == 0 || m_fileRate == 0) && !m_done) {
00139             usleep(10);
00140         }
00141     }
00142 }
00143 
00144 MP3FileReader::~MP3FileReader()
00145 {
00146     if (m_decodeThread) {
00147         m_cancelled = true;
00148         m_decodeThread->wait();
00149         delete m_decodeThread;
00150     }
00151 }
00152 
00153 void
00154 MP3FileReader::loadTags()
00155 {
00156     m_title = "";
00157 
00158 #ifdef HAVE_ID3TAG
00159 
00160     id3_file *file = id3_file_open(m_path.toLocal8Bit().data(),
00161                                    ID3_FILE_MODE_READONLY);
00162     if (!file) return;
00163 
00164     // We can do this a lot more elegantly, but we'll leave that for
00165     // when we implement support for more than just the one tag!
00166     
00167     id3_tag *tag = id3_file_tag(file);
00168     if (!tag) {
00169 #ifdef DEBUG_ID3TAG
00170         std::cerr << "MP3FileReader::loadTags: No ID3 tag found" << std::endl;
00171 #endif
00172         id3_file_close(file);
00173         return;
00174     }
00175 
00176     m_title = loadTag(tag, "TIT2"); // work title
00177     if (m_title == "") m_title = loadTag(tag, "TIT1");
00178 
00179     m_maker = loadTag(tag, "TPE1"); // "lead artist"
00180     if (m_maker == "") m_maker = loadTag(tag, "TPE2");
00181 
00182     id3_file_close(file);
00183 
00184 #else
00185 #ifdef DEBUG_ID3TAG
00186     std::cerr << "MP3FileReader::loadTags: ID3 tag support not compiled in"
00187               << std::endl;
00188 #endif
00189 #endif
00190 }
00191 
00192 QString
00193 MP3FileReader::loadTag(void *vtag, const char *name)
00194 {
00195 #ifdef HAVE_ID3TAG
00196     id3_tag *tag = (id3_tag *)vtag;
00197 
00198     id3_frame *frame = id3_tag_findframe(tag, name, 0);
00199     if (!frame) {
00200 #ifdef DEBUG_ID3TAG
00201         std::cerr << "MP3FileReader::loadTags: No \"" << name << "\" in ID3 tag" << std::endl;
00202 #endif
00203         return "";
00204     }
00205         
00206     if (frame->nfields < 2) {
00207         std::cerr << "MP3FileReader::loadTags: WARNING: Not enough fields (" << frame->nfields << ") for \"" << name << "\" in ID3 tag" << std::endl;
00208         return "";
00209     }
00210 
00211     unsigned int nstrings = id3_field_getnstrings(&frame->fields[1]);
00212     if (nstrings == 0) {
00213 #ifdef DEBUG_ID3TAG
00214         std::cerr << "MP3FileReader::loadTags: No strings for \"" << name << "\" in ID3 tag" << std::endl;
00215 #endif
00216         return "";
00217     }
00218 
00219     id3_ucs4_t const *ustr = id3_field_getstrings(&frame->fields[1], 0);
00220     if (!ustr) {
00221 #ifdef DEBUG_ID3TAG
00222         std::cerr << "MP3FileReader::loadTags: Invalid or absent data for \"" << name << "\" in ID3 tag" << std::endl;
00223 #endif
00224         return "";
00225     }
00226         
00227     id3_utf8_t *u8str = id3_ucs4_utf8duplicate(ustr);
00228     if (!u8str) {
00229         std::cerr << "MP3FileReader::loadTags: ERROR: Internal error: Failed to convert UCS4 to UTF8 in ID3 title" << std::endl;
00230         return "";
00231     }
00232         
00233     QString rv = QString::fromUtf8((const char *)u8str);
00234     free(u8str);
00235 
00236 #ifdef DEBUG_ID3TAG
00237         std::cerr << "MP3FileReader::loadTags: tag \"" << name << "\" -> \""
00238         << rv.toStdString() << "\"" << std::endl;
00239 #endif
00240 
00241 
00242     return rv;
00243 
00244 #else
00245     return "";
00246 #endif
00247 }
00248 
00249 void
00250 MP3FileReader::DecodeThread::run()
00251 {
00252     if (!m_reader->decode(m_reader->m_filebuffer, m_reader->m_fileSize)) {
00253         m_reader->m_error = QString("Failed to decode file %1.").arg(m_reader->m_path);
00254     }
00255 
00256     delete[] m_reader->m_filebuffer;
00257     m_reader->m_filebuffer = 0;
00258 
00259     if (m_reader->m_samplebuffer) {
00260         for (size_t c = 0; c < m_reader->m_channelCount; ++c) {
00261             delete[] m_reader->m_samplebuffer[c];
00262         }
00263         delete[] m_reader->m_samplebuffer;
00264         m_reader->m_samplebuffer = 0;
00265     }
00266 
00267     if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
00268 
00269     m_reader->m_done = true;
00270     m_reader->m_completion = 100;
00271 
00272     m_reader->endSerialised();
00273 } 
00274 
00275 bool
00276 MP3FileReader::decode(void *mm, size_t sz)
00277 {
00278     DecoderData data;
00279     struct mad_decoder decoder;
00280 
00281     data.start = (unsigned char const *)mm;
00282     data.length = (unsigned long)sz;
00283     data.reader = this;
00284 
00285     mad_decoder_init(&decoder, &data, input, 0, 0, output, error, 0);
00286     mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
00287     mad_decoder_finish(&decoder);
00288 
00289     m_done = true;
00290     return true;
00291 }
00292 
00293 enum mad_flow
00294 MP3FileReader::input(void *dp, struct mad_stream *stream)
00295 {
00296     DecoderData *data = (DecoderData *)dp;
00297 
00298     if (!data->length) return MAD_FLOW_STOP;
00299 
00300     unsigned char const *start = data->start;
00301     unsigned long length = data->length;
00302 
00303 #ifdef HAVE_ID3TAG
00304     if (length > ID3_TAG_QUERYSIZE) {
00305         int taglen = id3_tag_query(start, ID3_TAG_QUERYSIZE);
00306         if (taglen > 0) {
00307 //            std::cerr << "ID3 tag length to skip: " << taglen << std::endl;
00308             start += taglen;
00309             length -= taglen;
00310         }
00311     }
00312 #endif
00313 
00314     mad_stream_buffer(stream, start, length);
00315     data->length = 0;
00316 
00317     return MAD_FLOW_CONTINUE;
00318 }
00319 
00320 enum mad_flow
00321 MP3FileReader::output(void *dp,
00322                       struct mad_header const *header,
00323                       struct mad_pcm *pcm)
00324 {
00325     DecoderData *data = (DecoderData *)dp;
00326     return data->reader->accept(header, pcm);
00327 }
00328 
00329 enum mad_flow
00330 MP3FileReader::accept(struct mad_header const *header,
00331                       struct mad_pcm *pcm)
00332 {
00333     int channels = pcm->channels;
00334     int frames = pcm->length;
00335 
00336     if (header) {
00337         m_bitrateNum += header->bitrate;
00338         m_bitrateDenom ++;
00339     }
00340 
00341     if (frames < 1) return MAD_FLOW_CONTINUE;
00342 
00343     if (m_channelCount == 0) {
00344 
00345         m_fileRate = pcm->samplerate;
00346         m_channelCount = channels;
00347 
00348         initialiseDecodeCache();
00349 
00350         if (m_cacheMode == CacheInTemporaryFile) {
00351 //            m_completion = 1;
00352             std::cerr << "MP3FileReader::accept: channel count " << m_channelCount << ", file rate " << m_fileRate << ", about to start serialised section" << std::endl;
00353             startSerialised("MP3FileReader::Decode");
00354         }
00355     }
00356     
00357     if (m_bitrateDenom > 0) {
00358         double bitrate = m_bitrateNum / m_bitrateDenom;
00359         double duration = double(m_fileSize * 8) / bitrate;
00360         double elapsed = double(m_frameCount) / m_sampleRate;
00361         double percent = 100;
00362         if (duration > 0.0) percent = ((elapsed * 100.0) / duration);
00363         int p = int(percent);
00364         if (p < 1) p = 1;
00365         if (p > 99) p = 99;
00366         if (m_completion != p || (m_progress && !m_progress->isVisible())) {
00367             m_completion = p;
00368             emit progress(m_completion);
00369             if (m_progress) {
00370                 if (m_completion > m_progress->value()) {
00371                     m_progress->setValue(m_completion);
00372                     m_progress->show();
00373                     m_progress->raise();
00374                     qApp->processEvents();
00375                     if (m_progress->wasCanceled()) {
00376                         m_cancelled = true;
00377                     }
00378                 }
00379             }
00380         }
00381     }
00382 
00383     if (m_cancelled) return MAD_FLOW_STOP;
00384 
00385     if (!isDecodeCacheInitialised()) {
00386         initialiseDecodeCache();
00387     }
00388 
00389     if (m_samplebuffersize < frames) {
00390         if (!m_samplebuffer) {
00391             m_samplebuffer = new float *[channels];
00392             for (int c = 0; c < channels; ++c) {
00393                 m_samplebuffer[c] = 0;
00394             }
00395         }
00396         for (int c = 0; c < channels; ++c) {
00397             delete[] m_samplebuffer[c];
00398             m_samplebuffer[c] = new float[frames];
00399         }
00400         m_samplebuffersize = frames;
00401     }
00402 
00403     int activeChannels = int(sizeof(pcm->samples) / sizeof(pcm->samples[0]));
00404 
00405     for (int ch = 0; ch < channels; ++ch) {
00406 
00407         for (int i = 0; i < frames; ++i) {
00408 
00409             mad_fixed_t sample = 0;
00410             if (ch < activeChannels) {
00411                 sample = pcm->samples[ch][i];
00412             }
00413             float fsample = float(sample) / float(MAD_F_ONE);
00414             
00415             m_samplebuffer[ch][i] = fsample;
00416         }
00417     }
00418 
00419     addSamplesToDecodeCache(m_samplebuffer, frames);
00420 
00421     return MAD_FLOW_CONTINUE;
00422 }
00423 
00424 enum mad_flow
00425 MP3FileReader::error(void *dp,
00426                      struct mad_stream *stream,
00427                      struct mad_frame *)
00428 {
00429     DecoderData *data = (DecoderData *)dp;
00430 
00431     fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",
00432             stream->error, mad_stream_errorstr(stream),
00433             stream->this_frame - data->start);
00434 
00435     return MAD_FLOW_CONTINUE;
00436 }
00437 
00438 void
00439 MP3FileReader::getSupportedExtensions(std::set<QString> &extensions)
00440 {
00441     extensions.insert("mp3");
00442 }
00443 
00444 bool
00445 MP3FileReader::supportsExtension(QString extension)
00446 {
00447     std::set<QString> extensions;
00448     getSupportedExtensions(extensions);
00449     return (extensions.find(extension.toLower()) != extensions.end());
00450 }
00451 
00452 bool
00453 MP3FileReader::supportsContentType(QString type)
00454 {
00455     return (type == "audio/mpeg");
00456 }
00457 
00458 bool
00459 MP3FileReader::supports(FileSource &source)
00460 {
00461     return (supportsExtension(source.getExtension()) ||
00462             supportsContentType(source.getContentType()));
00463 }
00464 
00465 
00466 #endif

Generated on Wed Feb 20 15:45:27 2008 for SonicVisualiser by  doxygen 1.5.1