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 "audio.h" 00017 00018 #include "moduleexception.h" 00019 00020 namespace SilentEyeFramework { 00021 00022 /*Audio::Audio(const QAudioFormat &format, qint64 dataLength) 00023 : m_format(format), m_dataLength(dataLength) 00024 { 00025 setObjectName("Audio"); 00026 m_type = AUDIO; 00027 }*/ 00028 00029 Audio::Audio(const QString& filePath) 00030 : Media(filePath) 00031 { 00032 setObjectName("Audio"); 00033 m_type = AUDIO; 00034 00035 readWaveHeader(); 00036 } 00037 00038 Audio::Audio(const Audio& aud) 00039 : Media(aud) 00040 { 00041 setObjectName("Audio"); 00042 m_type = AUDIO; 00043 00044 readWaveHeader(); 00045 } 00046 00047 Audio::Audio(Audio* aud) 00048 : Media(aud) 00049 { 00050 setObjectName("Audio"); 00051 m_type = AUDIO; 00052 00053 readWaveHeader(); 00054 } 00055 00056 Audio::~Audio() 00057 { 00058 // NOTHING TO DO 00059 } 00060 00061 void Audio::readWaveHeader() { 00062 QFile file(m_filePath); 00063 if (!file.open(QIODevice::ReadOnly)) 00064 { 00065 throw ModuleException("Cannot read selected file: " + m_filePath, file.errorString()); 00066 } 00067 00068 QDataStream stream(&file); 00069 stream.setByteOrder(QDataStream::BigEndian); 00070 00071 // CHUNK DESCRIPTION 00072 quint32 len = 4; 00073 char* buffer = new char[len+1]; 00074 stream.readRawData(buffer, len); // ChunkID 00075 buffer[len] = '\0'; 00076 QString identifier(buffer); 00077 delete buffer; 00078 00079 if (identifier == "RIFF") 00080 { 00081 m_byteOrder = QAudioFormat::BigEndian; 00082 } 00083 else if (identifier == "RIFX ") 00084 { 00085 m_byteOrder = QAudioFormat::LittleEndian; 00086 } 00087 else 00088 { 00089 throw ModuleException("Selected file is not in a valid/supported WAVE format.", 00090 "Identifier must be TIFF or RIFX (found: '" + identifier + "'')"); 00091 } 00092 m_format.setByteOrder(m_byteOrder); 00093 00094 stream.setByteOrder(QDataStream::LittleEndian); 00095 stream >> m_totalSize; // ChunkSize 00096 00097 buffer = new char[len+1]; 00098 stream.readRawData(buffer, len); // Format 00099 buffer[len] = '\0'; 00100 if ("WAVE" != QString(buffer)) 00101 { 00102 delete buffer; 00103 throw ModuleException("Selected file is not in a valid WAVE format.", 00104 "Format must be \"WAVE\"!"); 00105 } 00106 delete buffer; 00107 00108 // SUB CHUNK FMT 00109 buffer = new char[len+1]; 00110 stream.readRawData(buffer, len); // Subchunk1ID 00111 buffer[len] = '\0'; 00112 if("fmt " != QString(buffer)) 00113 { 00114 throw ModuleException("Selected file is not in a valid WAVE format", 00115 "Subchunk1ID must be \"fmt \"!"); 00116 delete buffer; 00117 } 00118 delete buffer; 00119 00120 stream >> m_subFmtSize; 00121 stream >> m_audioFormat; 00122 if (m_audioFormat != 1 || m_subFmtSize != 16) 00123 { 00124 throw ModuleException("Selected file is not in a valid/supported WAVE format.", 00125 "Audio format must be 1 for PCM!"); 00126 } 00127 m_format.setCodec("audio/pcm"); 00128 stream >> m_numChannels; 00129 m_format.setChannels(m_numChannels); 00130 stream >> m_sampleRate; 00131 m_format.setFrequency(m_sampleRate); 00132 stream >> m_byteRate; 00133 stream >> m_blockAlign; 00134 stream >> m_bitPerSample; 00135 m_format.setSampleSize(m_bitPerSample); 00136 if (m_bitPerSample == 8) { 00137 m_format.setSampleType(QAudioFormat::UnSignedInt); 00138 } else if (m_bitPerSample == 16) { 00139 m_format.setSampleType(QAudioFormat::SignedInt); 00140 } else { 00141 throw ModuleException("Selected file is not in a valid/supported WAVE format.", 00142 "BitsPerSample must be 8 or 16!"); 00143 } 00144 00145 00146 // SUB CHUNK DATA 00147 len = 4; 00148 buffer = new char[len+1]; 00149 stream.readRawData(buffer, len); 00150 buffer[len] = '\0'; 00151 if("data" != QString(buffer)) 00152 { 00153 throw ModuleException("Selected file is not in a valid/supported WAVE format.", 00154 "Subchunk2ID mus be \"data\"!"); 00155 delete buffer; 00156 } 00157 delete buffer; 00158 00159 stream >> m_subDataSize; 00160 00161 file.close(); 00162 00163 m_duration = (m_subDataSize / (m_bitPerSample/8.0)) / (m_sampleRate * m_numChannels); 00164 m_bitRate = floor((m_subDataSize * 8.0) / m_duration); 00165 } 00166 00167 QAudioFormat Audio::format() const 00168 { 00169 return m_format; 00170 } 00171 00172 double Audio::duration() 00173 { 00174 return m_duration; 00175 } 00176 00177 quint32 Audio::bitRate() 00178 { 00179 return m_bitRate; 00180 } 00181 00182 qint32 Audio::sampleSize() const { 00183 return floor((m_subDataSize * 8.0) / (m_bitPerSample * m_numChannels)); 00184 } 00185 00186 bool Audio::openSamples() 00187 { 00188 if (m_file.isOpen()) { 00189 m_file.close(); 00190 } 00191 m_file.setFileName(m_filePath); 00192 if(!m_file.open(QIODevice::ReadOnly)) { 00193 return false; 00194 } 00195 m_sampleStream.setDevice(&m_file); 00196 m_sampleStream.skipRawData(headerLength()); 00197 00198 if (m_byteOrder == QAudioFormat::BigEndian) { 00199 m_sampleStream.setByteOrder(QDataStream::BigEndian); 00200 } else { 00201 m_sampleStream.setByteOrder(QDataStream::LittleEndian); 00202 } 00203 00204 return true; 00205 } 00206 00207 bool Audio::hasNextSample() 00208 { 00209 if (!m_file.isOpen()) { 00210 return false; 00211 } 00212 return !m_sampleStream.atEnd(); 00213 } 00214 00215 QList<quint32> Audio::readSample() 00216 { 00217 QList<quint32> sample; 00218 for (int i=0; i<m_numChannels; i++) { 00219 if (m_bitPerSample == 8) { 00220 quint8 val; 00221 m_sampleStream >> val; 00222 sample << val; 00223 } else if (m_bitPerSample == 16) { 00224 quint16 val; 00225 m_sampleStream >> val; 00226 sample << val; 00227 } 00228 } 00229 return sample; 00230 } 00231 00232 void Audio::skipSample(qint32 length) { 00233 int skip = length * m_numChannels * (m_bitPerSample/8.0);; 00234 m_sampleStream.skipRawData(skip); 00235 } 00236 00237 bool Audio::closeSamples() 00238 { 00239 if (m_file.isOpen()) { 00240 m_file.close(); 00241 m_sampleStream.resetStatus(); 00242 return true; 00243 } else { 00244 return false; 00245 } 00246 } 00247 00248 void Audio::writeWaveHeader(QDataStream& stream) 00249 { 00250 stream.setByteOrder(QDataStream::BigEndian); 00251 00252 // CHUNK DESCRIPTION 00253 if (m_byteOrder == QAudioFormat::LittleEndian) { 00254 stream.writeRawData("RIFX", 4); 00255 } else { 00256 stream.writeRawData("RIFF", 4); 00257 } 00258 00259 stream.setByteOrder(QDataStream::LittleEndian); 00260 stream << m_totalSize; // ChunkSize 00261 00262 stream.writeRawData("WAVE", 4); // Format 00263 00264 // SUB CHUNK FMT 00265 stream.writeRawData("fmt ", 4); // Subchunk1ID 00266 00267 stream << m_subFmtSize; 00268 stream << m_audioFormat; 00269 stream << m_numChannels; 00270 stream << m_sampleRate; 00271 stream << m_byteRate; 00272 stream << m_blockAlign; 00273 stream << m_bitPerSample; 00274 00275 // SUB CHUNK DATA 00276 stream.writeRawData("data", 4); 00277 stream << m_subDataSize; 00278 } 00279 }