SilentEye 0.4.1

modules/seformatwav/audiowav.cpp

Go to the documentation of this file.
00001 //  This file is part of SilentEye.
00002 //
00003 //  SilentEye is free software: you can redistribute it and/or modify
00004 //  it under the terms of the GNU General Public License as published by
00005 //  the Free Software Foundation, either version 3 of the License, or
00006 //  (at your option) any later version.
00007 //
00008 //  SilentEye is distributed in the hope that it will be useful,
00009 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 //  GNU General Public License for more details.
00012 //
00013 //  You should have received a copy of the GNU General Public License
00014 //  along with SilentEye.  If not, see <http://www.gnu.org/licenses/>.
00015 
00016 #include "audiowav.h"
00017 
00018 #include <moduleexception.h>
00019 
00020 namespace SEFormatWAV {
00021 
00022     AudioWav::AudioWav(const QString& filePath)
00023         : Audio(filePath)
00024     {
00025         init();
00026     }
00027 
00028     AudioWav::AudioWav(const Audio& audio)
00029         : Audio(audio)
00030     {
00031         init();
00032     }
00033 
00034     AudioWav::AudioWav(Audio* audio)
00035         : Audio(audio)
00036     {
00037         init();
00038     }
00039     
00040     void AudioWav::init() {
00041         computeNewFileName("wav");
00042         setObjectName("AudioWav");
00043         m_logger = new Logger(this);
00044 
00045         m_nbBitsUsed = 2;
00046         m_nbChannelUsed = m_numChannels;
00047         m_headerPosition = ENDING;
00048         m_distribution = EQUI;
00049     }
00050     
00051     AudioWav::~AudioWav()
00052     {
00053         if (!m_logger.isNull())
00054         {
00055             delete m_logger;
00056         }
00057     }
00058 
00059     quint16 AudioWav::nbBitsUsed() const
00060     {
00061         return m_nbBitsUsed;
00062     }
00063 
00064     void AudioWav::setNbBitsUsed(const quint16 value)
00065     {
00066         m_nbBitsUsed = value;
00067     }
00068 
00069     quint16 AudioWav::nbChannelUsed() const
00070     {
00071         return m_nbChannelUsed;
00072     }
00073 
00074     void AudioWav::setNbChannelUsed(const quint16 value)
00075     {
00076         if (value > m_numChannels) {
00077             m_nbChannelUsed = m_numChannels;
00078         } else {
00079             m_nbChannelUsed = value;
00080         }
00081     }
00082 
00083     void AudioWav::setDistribution(DataDistribution value)
00084     {
00085         m_distribution = value;
00086     }
00087 
00088     void AudioWav::setHeaderPosition(HeaderPosition value)
00089     {
00090         m_headerPosition = value;
00091     }
00092 
00093     quint32 AudioWav::capacity() const
00094     {
00095         /*m_logger->debug("nbSample: " + QString::number(sampleSize())
00096                         + ";m_nbChannelUsed: " + QString::number(m_nbChannelUsed)
00097                         + ";m_nbBitsUsed: " + QString::number(m_nbBitsUsed));*/
00098         return floor(sampleSize() * m_nbChannelUsed * m_nbBitsUsed) / 8.0;
00099     }
00100     
00101     bool AudioWav::loadData()
00102     {
00103         m_logger->debug("channels used:" + QString::number(m_nbChannelUsed)
00104                         + ", bits used: " + QString::number(m_nbBitsUsed));
00105 
00106         EncodedData dataSize(Data::UINT32);
00107         dataSize.initialize(m_nbBitsUsed);
00108 
00109         if (m_data.isNull())
00110             m_data = new EncodedData();
00111         else
00112             m_data->clear();
00113 
00114         m_data->initialize(m_nbBitsUsed);
00115         unsigned short int andOperator = EncodedData::andOperator(m_nbBitsUsed);
00116 
00117         if (!openSamples())
00118         {
00119             throw ModuleException("Technical error during file reading",
00120                                   "Cannot read source file! (" + m_filePath + ")");
00121         }
00122 
00123         if (m_headerPosition == ENDING) {
00124             m_logger->debug("Skip to header pos: "
00125                             + QString::number(sampleSize() - computeHeaderSampleSize())
00126                             + " / " + QString::number(sampleSize())
00127                             + ". subDataSize: " + QString::number(m_subDataSize)
00128                             + ", bitPerSample: " + QString::number(m_bitPerSample)
00129                             + ", numChannels: " + QString::number(m_numChannels));
00130             skipSample(sampleSize() - computeHeaderSampleSize());
00131         }
00132 
00133         int nbBitsRead = 0;
00134         while(hasNextSample() && nbBitsRead<32) {
00135             QList<quint32> samples = readSample();
00136             for (int i=0; i<m_nbChannelUsed && nbBitsRead<32; i++)
00137             {
00138                 int val = samples.at(i)&andOperator;
00139                 dataSize.append(val);
00140                 nbBitsRead += m_nbBitsUsed;
00141             }
00142         }
00143 
00144         closeSamples();
00145 
00146         quint32 nbOctets = dataSize.toUInt32();
00147         m_logger->debug("loaded size: " + QString::number(nbOctets));
00148 
00149         if (nbOctets > capacity()) {
00150             m_logger->warning("size > capacity");
00151             return false;
00152         }
00153 
00154         if (!openSamples())
00155         {
00156             throw ModuleException("Technical error during file reading",
00157                                   "Cannot read source file! (" + m_filePath + ")");
00158         }
00159 
00160         if (m_headerPosition == BEGINNING) {
00161             skipSample(computeHeaderSampleSize());
00162         }
00163 
00164         nbBitsRead = 0;
00165         int nbBits = nbOctets*8;
00166         int step = computeDistributionStep(nbOctets);
00167         while(hasNextSample() && nbBitsRead < nbBits) {
00168             QList<quint32> samples = readSample();
00169             for (int i=0; i<m_nbChannelUsed && nbBitsRead < nbBits; i++)
00170             {
00171                 int val = samples.at(i)&andOperator;
00172                 m_data->append(val);
00173                 nbBitsRead += m_nbBitsUsed;
00174             }
00175 
00176             skipSample(step-1);
00177         }
00178 
00179         closeSamples();
00180         
00181         m_isLoaded = m_data->size()>0;
00182         return m_isLoaded;
00183     }
00184     
00185     bool AudioWav::saveToDir(QString& outputDirPath)
00186     {
00187         if (!outputDirPath.endsWith('/'))
00188         {
00189             outputDirPath += "/";
00190         }
00191 
00192         m_logger->debug("channels used:" + QString::number(m_nbChannelUsed)
00193                         + ", bits used: " + QString::number(m_nbBitsUsed));
00194 
00195         if (m_data.isNull())
00196             throw ModuleException("Technical error during encoding process",
00197                                   "Cannot insert null data into wave");
00198 
00199         // Open sample using current filepath
00200         if (!openSamples())
00201         {
00202             throw ModuleException("Technical error during file writing",
00203                                   "Cannot read source file! (" + m_filePath + ")");
00204         }
00205 
00206         // change filepath for output
00207         if (QFile::exists(outputDirPath+"/"+m_shortName))
00208         {
00209             m_filePath = outputDirPath+"/_"+m_shortName; // for unit test
00210         }
00211         else
00212         {
00213             m_filePath = outputDirPath+"/"+m_shortName;
00214         }
00215 
00216         QFile output(m_filePath);
00217 
00218         if (!output.open(QIODevice::WriteOnly))
00219         {
00220             throw ModuleException("Technical error during file writing",
00221                                   "Cannot create destination file! (" + m_filePath + ")");
00222         }
00223         QDataStream out(&output);
00224         writeWaveHeader(out);
00225 
00226         // prepare output for writing
00227         if (m_byteOrder == QAudioFormat::BigEndian) {
00228             out.setByteOrder(QDataStream::BigEndian);
00229         } else {
00230             out.setByteOrder(QDataStream::LittleEndian);
00231         }
00232 
00233         EncodedData sizeData(m_data->size());
00234         m_logger->debug("Setted size: " + QString::number(sizeData.toUInt32())
00235                         + "/" + QString::number(capacity()));
00236 
00237         sizeData.initialize(m_nbBitsUsed);
00238 
00239         int swap = 255 - EncodedData::andOperator(m_nbBitsUsed);
00240         qint32 sampleIndex = 0;
00241 
00242         if (m_headerPosition == BEGINNING) {
00243             while(hasNextSample() && sizeData.hasNext()) {
00244                 QList<quint32> samples = readSample();
00245                 sampleIndex ++;
00246                 int i;
00247                 for (i=0; i<m_nbChannelUsed && sizeData.hasNext(); i++)
00248                 {
00249                     int val = sizeData.read();
00250                     quint32 sample = samples.at(i);
00251                     sample = (sample&swap)+val;
00252 
00253                     writeSampleChannel(out, sample);
00254                 }
00255 
00256                 for (;i<samples.size();i++)
00257                 {
00258                     writeSampleChannel(out, samples.at(i));
00259                 }
00260             }
00261         }
00262 
00263         int headNbSample = computeHeaderSampleSize();
00264         qint32 step = computeDistributionStep(m_data->size());
00265 
00266         m_data->initialize(m_nbBitsUsed);
00267         while(hasNextSample() && m_data->hasNext()) {
00268             QList<quint32> samples = readSample();
00269             sampleIndex ++;
00270             int i;
00271             for (i=0; i<m_nbChannelUsed && m_data->hasNext(); i++)
00272             {
00273                 int val = m_data->read();
00274                 quint32 sample = samples.at(i);
00275                 sample = (sample&swap)+val;
00276 
00277                 writeSampleChannel(out, sample);
00278             }
00279 
00280             for (;i<samples.size();i++)
00281             {
00282                 writeSampleChannel(out, samples.at(i));
00283             }
00284 
00285             if (sampleIndex + step < sampleSize()-headNbSample) {
00286                 for(int j=0; j < step-1 && hasNextSample(); j++) {
00287                     samples = readSample();
00288                     sampleIndex ++;
00289                     for (int i=0;i<samples.size();i++)
00290                     {
00291                         writeSampleChannel(out, samples.at(i));
00292                     }
00293                 }
00294             }
00295         }
00296         m_logger->debug("Last data pos: " + QString::number(sampleIndex));
00297 
00298         while(hasNextSample())
00299         {
00300             QList<quint32> samples = readSample();
00301             sampleIndex ++;
00302             if (m_headerPosition == ENDING && sampleIndex > sampleSize()-headNbSample)
00303             {
00304                 if (sampleIndex == sampleSize()-headNbSample+1) {
00305                     m_logger->debug("Header start pos: " + QString::number(sampleIndex));
00306                 }
00307                 int i;
00308                 for (i=0; i<m_nbChannelUsed && sizeData.hasNext(); i++)
00309                 {
00310                     int val = sizeData.read();
00311                     quint32 sample = samples.at(i);
00312                     sample = (sample&swap)+val;
00313 
00314                     writeSampleChannel(out, sample);
00315                 }
00316 
00317                 for (;i<samples.size();i++)
00318                 {
00319                     writeSampleChannel(out, samples.at(i));
00320                 }
00321             } else {
00322                 for (int i=0;i<samples.size();i++)
00323                 {
00324                     writeSampleChannel(out, samples.at(i));
00325                 }
00326             }
00327         }
00328 
00329         m_logger->debug("Last sample pos: " + QString::number(sampleIndex)
00330                         + " / " + QString::number(sampleSize()) + "."
00331                         + " headNbSample: " + QString::number(headNbSample)
00332                         + ", dataSize: " + QString::number(m_subDataSize)
00333                         + ", bitPerSample: " + QString::number(m_bitPerSample)
00334                         + ", numChannels: " + QString::number(m_numChannels));
00335         closeSamples();
00336 
00337         output.close();
00338         return true;
00339     }
00340 
00341     int AudioWav::computeHeaderSampleSize() const
00342     {
00343         return ceil(32.0 /  (m_nbChannelUsed * m_nbBitsUsed));
00344     }
00345 
00346     qint32 AudioWav::computeDistributionStep(quint32 size) const {
00347         qint32 step = 1;
00348         if(m_distribution == EQUI)
00349         {
00350             qint32 sampleDataNeed = ceil((size * 8.0)/(m_nbChannelUsed*m_nbBitsUsed));
00351             step = floor(((double)sampleSize()) / sampleDataNeed);
00352             if (step <= 0) {
00353                 m_logger->debug("computed step was 0 => set 1");
00354                 step = 1;
00355             }
00356             m_logger->debug("computed step: " + QString::number(step)
00357                             + ", size: " + QString::number(size));
00358         }
00359         return step;
00360     }
00361 
00362     bool AudioWav::writeSampleChannel(QDataStream& out, quint32 sample) {
00363         if (m_bitPerSample == 8) {
00364             out << quint8(sample);
00365         } else if (m_bitPerSample == 16) {
00366             out << quint16(sample);
00367         } else if (m_bitPerSample == 32) {
00368             out << sample;
00369         } else {
00370             m_logger->warning("bitpersample: " + QString::number(m_bitPerSample));
00371             return false;
00372         }
00373         return true;
00374     }
00375 }