Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/soundsourcesndfile.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           soundsourcesndfile.cpp  -  description
00003                              -------------------
00004     copyright            : (C) 2002 by Tue and Ken Haste Andersen
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/flacfile.h>
00018 #include <taglib/aifffile.h>
00019 #include <taglib/rifffile.h>
00020 #include <taglib/wavfile.h>
00021 
00022 #include "trackinfoobject.h"
00023 #include "soundsourcesndfile.h"
00024 #include <qstring.h>
00025 #include <QtDebug>
00026 
00027 /*
00028    Class for reading files using libsndfile
00029  */
00030 SoundSourceSndFile::SoundSourceSndFile(QString qFilename) :
00031     Mixxx::SoundSource(qFilename)
00032 {
00033     m_bOpened = false;
00034     info = new SF_INFO;
00035     info->format = 0;   // Must be set to 0 per the API for reading (non-RAW files)
00036     filelength = 0;
00037 }
00038 
00039 SoundSourceSndFile::~SoundSourceSndFile()
00040 {
00041     if (m_bOpened) {
00042         sf_close(fh);
00043     }
00044     delete info;
00045 }
00046 
00047 QList<QString> SoundSourceSndFile::supportedFileExtensions()
00048 {
00049     QList<QString> list;
00050     list.push_back("aiff");
00051     list.push_back("aif");
00052     list.push_back("wav");
00053     list.push_back("flac");
00054     return list;
00055 }
00056 
00057 int SoundSourceSndFile::open() {
00058 #ifdef __WINDOWS__
00059     QByteArray qbaFilename = m_qFilename.toLocal8Bit();
00060 #else
00061     QByteArray qbaFilename = m_qFilename.toUtf8();
00062 #endif
00063     fh = sf_open( qbaFilename.data(), SFM_READ, info );
00064 
00065     if (fh == NULL) {   // sf_format_check is only for writes
00066         qWarning() << "libsndfile: Error opening file" << m_qFilename << sf_strerror(fh);
00067         return -1;
00068     }
00069 
00070     if (sf_error(fh)>0) {
00071         qWarning() << "libsndfile: Error opening file" << m_qFilename << sf_strerror(fh);
00072         return -1;
00073     }
00074 
00075     channels = info->channels;
00076 
00077     // This is the 'virtual' filelength. No matter how many channels the file
00078     // actually has, we pretend it has 2.
00079     filelength = 2*info->frames; // File length with two interleaved channels
00080     m_iSampleRate =  info->samplerate;
00081     m_bOpened = true;
00082     return OK;
00083 }
00084 
00085 long SoundSourceSndFile::seek(long filepos)
00086 {
00087     unsigned long filepos2 = (unsigned long)filepos;
00088     if (filelength>0)
00089     {
00090         filepos2 = math_min(filepos2,filelength);
00091         sf_seek(fh, (sf_count_t)filepos2/2, SEEK_SET);
00092         //Note that we don't error check sf_seek because it reports
00093         //benign errors under normal usage (ie. we sometimes seek past the end
00094         //of a song, and it will stop us.)
00095         return filepos2;
00096     }
00097     return 0;
00098 }
00099 
00100 /*
00101    read <size> samples into <destination>, and return the number of
00102    samples actually read. A sample is a single float representing a
00103    sample on one channel of the audio. In the case of a monaural file
00104    then size/2 samples are read from the mono file, and they are
00105    doubled into stereo.
00106  */
00107 unsigned SoundSourceSndFile::read(unsigned long size, const SAMPLE * destination)
00108 {
00109     SAMPLE * dest = (SAMPLE *)destination;
00110     if (filelength > 0)
00111     {
00112         if (channels==2)
00113         {
00114             unsigned long no = sf_read_short(fh, dest, size);
00115 
00116             // rryan 2/2009 This code used to lie and say we read
00117             // 'size' samples no matter what. I left this array
00118             // zeroing code here in case the Reader doesn't check
00119             // against this.
00120             for (unsigned long i=no; i<size; ++i)
00121                 dest[i] = 0;
00122 
00123             return no;
00124         }
00125         else if(channels==1)
00126         {
00127             // We are not dealing with a stereo file. Read fewer
00128             // samples than requested and double them because we
00129             // pretend to every reader that all files are in stereo.
00130             int readNo = sf_read_short(fh, dest, size/2);
00131 
00132             // readNo*2 is strictly less than available buffer space
00133 
00134             // rryan 2/2009
00135             // Mini-proof of the below:
00136             // size = 20, destination is a 20 element array 0-19
00137             // readNo = 10 (or less, but 10 in this case)
00138             // i = 10-1 = 9, so dest[9*2] and dest[9*2+1],
00139             // so the first iteration touches the very ends of destination
00140             // on the last iteration, dest[0] and dest[1] are assigned to dest[0]
00141 
00142             for(int i=(readNo-1); i>=0; i--) {
00143                 dest[i*2]     = dest[i];
00144                 dest[(i*2)+1] = dest[i];
00145             }
00146 
00147             // We doubled the readNo bytes we read into stereo.
00148             return readNo * 2;
00149         } else {
00150             // We do not support music with more than 2 channels.
00151             return 0;
00152         }
00153     }
00154 
00155     // The file has errors or is not open. Tell the truth and return 0.
00156     return 0;
00157 }
00158 
00159 int SoundSourceSndFile::parseHeader()
00160 {
00161     QString location = getFilename();
00162     setType(location.section(".",-1).toLower());
00163 
00164     bool result;
00165     bool is_flac = location.endsWith("flac", Qt::CaseInsensitive);
00166     bool is_wav = location.endsWith("wav", Qt::CaseInsensitive);
00167 
00168 #ifdef __WINDOWS__
00169     /* From Tobias: A Utf-8 string did not work on my Windows XP (German edition)
00170      * If you try this conversion, f.isValid() will return false in many cases
00171      * and processTaglibFile() will fail
00172      *
00173      * The method toLocal8Bit() returns the local 8-bit representation of the string as a QByteArray.
00174      * The returned byte array is undefined if the string contains characters not supported
00175      * by the local 8-bit encoding.
00176      */
00177     QByteArray qBAFilename = m_qFilename.toLocal8Bit();
00178 #else
00179     QByteArray qBAFilename = m_qFilename.toUtf8();
00180 #endif
00181 
00182     if (is_flac) {
00183         TagLib::FLAC::File f(qBAFilename.constData());
00184         result = processTaglibFile(f);
00185         TagLib::ID3v2::Tag* id3v2 = f.ID3v2Tag();
00186         TagLib::Ogg::XiphComment* xiph = f.xiphComment();
00187         if (id3v2) {
00188             processID3v2Tag(id3v2);
00189         }
00190         if (xiph) {
00191             processXiphComment(xiph);
00192         }
00193     } else if (is_wav) {
00194         TagLib::RIFF::WAV::File f(qBAFilename.constData());
00195         result = processTaglibFile(f);
00196 
00197         TagLib::ID3v2::Tag* id3v2 = f.tag();
00198         if (id3v2) {
00199             processID3v2Tag(id3v2);
00200         }
00201 
00202         if (getDuration() <= 0) {
00203             // we're using a taglib version which doesn't know how to do wav
00204             // durations, set it with info from sndfile -bkgood
00205             // XXX remove this when ubuntu ships with an sufficiently
00206             // intelligent version of taglib, should happen in 11.10
00207 
00208             // Have to open the file for info to be valid.
00209             if (!m_bOpened) {
00210                 open();
00211             }
00212 
00213             if (info->samplerate > 0) {
00214                 setDuration(info->frames / info->samplerate);
00215             } else {
00216                 qDebug() << "WARNING: WAV file with invalid samplerate."
00217                          << "Can't get duration using libsndfile.";
00218             }
00219         }
00220     } else {
00221         // Try AIFF
00222         TagLib::RIFF::AIFF::File f(qBAFilename.constData());
00223         result = processTaglibFile(f);
00224 
00225         TagLib::ID3v2::Tag* id3v2 = f.tag();
00226         if (id3v2) {
00227             processID3v2Tag(id3v2);
00228         }
00229     }
00230 
00231     if (result)
00232         return OK;
00233     return ERR;
00234 }
00235 
00236 /*
00237    Return the length of the file in samples.
00238  */
00239 inline long unsigned SoundSourceSndFile::length()
00240 {
00241     return filelength;
00242 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines