SilentEye 0.4.1
|
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 }