diff options
Diffstat (limited to 'demos/spectrum/app/wavfile.cpp')
-rw-r--r-- | demos/spectrum/app/wavfile.cpp | 205 |
1 files changed, 50 insertions, 155 deletions
diff --git a/demos/spectrum/app/wavfile.cpp b/demos/spectrum/app/wavfile.cpp index 74d5918..44c3ac5 100644 --- a/demos/spectrum/app/wavfile.cpp +++ b/demos/spectrum/app/wavfile.cpp @@ -78,179 +78,74 @@ struct CombinedHeader WAVEHeader wave; }; - - -WavFile::WavFile(const QAudioFormat &format, qint64 dataLength) - : m_format(format) - , m_dataLength(dataLength) - , m_dataPosition(0) -{ -} - -bool WavFile::readHeader(QIODevice &device) -{ - if (!device.isSequential()) { - if (!device.seek(0)) - return false; - // XXX: else, assume that current position is the start of the header - } - - CombinedHeader header; - if (device.read(reinterpret_cast<char *>(&header), sizeof(CombinedHeader)) != sizeof(CombinedHeader)) - return false; - - if ((memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0 - || memcmp(&header.riff.descriptor.id, "RIFX", 4) == 0) - && memcmp(&header.riff.type, "WAVE", 4) == 0 - && memcmp(&header.wave.descriptor.id, "fmt ", 4) == 0 - && (header.wave.audioFormat == 1 || header.wave.audioFormat == 0)) { - - // Read off remaining header information - DATAHeader dataHeader; - - if (qFromLittleEndian<quint32>(header.wave.descriptor.size) > sizeof(WAVEHeader)) { - // Extended data available - quint16 extraFormatBytes; - if (device.peek((char*)&extraFormatBytes, sizeof(quint16)) != sizeof(quint16)) - return false; - const qint64 throwAwayBytes = sizeof(quint16) + qFromLittleEndian<quint16>(extraFormatBytes); - if (device.read(throwAwayBytes).size() != throwAwayBytes) - return false; - } - - if (device.read((char*)&dataHeader, sizeof(DATAHeader)) != sizeof(DATAHeader)) - return false; - - // Establish format - if (memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0) - m_format.setByteOrder(QAudioFormat::LittleEndian); - else - m_format.setByteOrder(QAudioFormat::BigEndian); - - int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample); - m_format.setChannels(qFromLittleEndian<quint16>(header.wave.numChannels)); - m_format.setCodec("audio/pcm"); - m_format.setFrequency(qFromLittleEndian<quint32>(header.wave.sampleRate)); - m_format.setSampleSize(qFromLittleEndian<quint16>(header.wave.bitsPerSample)); - m_format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt); - - m_dataLength = qFromLittleEndian<quint32>(dataHeader.descriptor.size); - m_dataPosition = 0; - } - - return true; -} - -bool WavFile::writeHeader(QIODevice &device) +WavFile::WavFile(QObject *parent) + : QFile(parent) + , m_headerLength(0) { - CombinedHeader header; - DATAHeader dataHeader; - - memset(&header, 0, sizeof(CombinedHeader)); - - // RIFF header - if (m_format.byteOrder() == QAudioFormat::LittleEndian) - strncpy(&header.riff.descriptor.id[0], "RIFF", 4); - else - strncpy(&header.riff.descriptor.id[0], "RIFX", 4); - qToLittleEndian<quint32>(quint32(m_dataLength + sizeof(CombinedHeader) + sizeof(DATAHeader) - sizeof(chunk)), - reinterpret_cast<unsigned char*>(&header.riff.descriptor.size)); - strncpy(&header.riff.type[0], "WAVE", 4); - - // WAVE header - strncpy(&header.wave.descriptor.id[0], "fmt ", 4); - qToLittleEndian<quint32>(quint32(16), - reinterpret_cast<unsigned char*>(&header.wave.descriptor.size)); - qToLittleEndian<quint16>(quint16(1), - reinterpret_cast<unsigned char*>(&header.wave.audioFormat)); - qToLittleEndian<quint16>(quint16(m_format.channels()), - reinterpret_cast<unsigned char*>(&header.wave.numChannels)); - qToLittleEndian<quint32>(quint32(m_format.frequency()), - reinterpret_cast<unsigned char*>(&header.wave.sampleRate)); - qToLittleEndian<quint32>(quint32(m_format.frequency() * m_format.channels() * m_format.sampleSize() / 8), - reinterpret_cast<unsigned char*>(&header.wave.byteRate)); - qToLittleEndian<quint16>(quint16(m_format.channels() * m_format.sampleSize() / 8), - reinterpret_cast<unsigned char*>(&header.wave.blockAlign)); - qToLittleEndian<quint16>(quint16(m_format.sampleSize()), - reinterpret_cast<unsigned char*>(&header.wave.bitsPerSample)); - - // DATA header - strncpy(dataHeader.descriptor.id, "data", 4); - qToLittleEndian<quint32>(quint32(m_dataLength), - reinterpret_cast<unsigned char*>(&dataHeader.descriptor.size)); - return device.write(reinterpret_cast<const char *>(&header), sizeof(CombinedHeader)) == sizeof(CombinedHeader) - && device.write(reinterpret_cast<const char*>(&dataHeader), sizeof(DATAHeader)) == sizeof(DATAHeader); } -const QAudioFormat& WavFile::format() const +bool WavFile::open(const QString &fileName) { - return m_format; + close(); + setFileName(fileName); + return QFile::open(QIODevice::ReadOnly) && readHeader(); } -qint64 WavFile::dataLength() const +const QAudioFormat &WavFile::fileFormat() const { - return m_dataLength; + return m_fileFormat; } -qint64 WavFile::headerLength() +qint64 WavFile::headerLength() const { - return sizeof(CombinedHeader); -} - -bool WavFile::writeDataLength(QIODevice &device, qint64 dataLength) -{ - bool result = false; - if (!device.isSequential()) { - device.seek(40); - unsigned char dataLengthLE[4]; - qToLittleEndian<quint32>(quint32(dataLength), dataLengthLE); - result = (device.write(reinterpret_cast<const char *>(dataLengthLE), 4) == 4); - } - return result; +return m_headerLength; } -qint64 WavFile::readData(QIODevice &device, QByteArray &buffer, - QAudioFormat outputFormat) +bool WavFile::readHeader() { - // Sanity checks - if (!outputFormat.isValid()) - outputFormat = m_format; - - if (!isPCMS16LE(outputFormat) || !isPCMS16LE(m_format)) - return 0; - - if (m_dataPosition == m_dataLength) - return 0; - - // Process - qint64 result = 0; - - const int frameSize = 2 * m_format.channels(); // 16 bit samples - QVector<char> inputSample(frameSize); - - qint16 *output = reinterpret_cast<qint16*>(buffer.data()); + seek(0); + CombinedHeader header; + bool result = read(reinterpret_cast<char *>(&header), sizeof(CombinedHeader)) == sizeof(CombinedHeader); + if (result) { + if ((memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0 + || memcmp(&header.riff.descriptor.id, "RIFX", 4) == 0) + && memcmp(&header.riff.type, "WAVE", 4) == 0 + && memcmp(&header.wave.descriptor.id, "fmt ", 4) == 0 + && (header.wave.audioFormat == 1 || header.wave.audioFormat == 0)) { + + // Read off remaining header information + DATAHeader dataHeader; + + if (qFromLittleEndian<quint32>(header.wave.descriptor.size) > sizeof(WAVEHeader)) { + // Extended data available + quint16 extraFormatBytes; + if (peek((char*)&extraFormatBytes, sizeof(quint16)) != sizeof(quint16)) + return false; + const qint64 throwAwayBytes = sizeof(quint16) + qFromLittleEndian<quint16>(extraFormatBytes); + if (read(throwAwayBytes).size() != throwAwayBytes) + return false; + } - while (result < buffer.size()) { - if (m_dataPosition == m_dataLength) - break; + if (read((char*)&dataHeader, sizeof(DATAHeader)) != sizeof(DATAHeader)) + return false; - // XXX only working with particular alignments - if (device.read(inputSample.data(), inputSample.count())) { - int inputIdx = 0; - for (int outputIdx = 0; outputIdx < outputFormat.channels(); ++outputIdx) { - const qint16* input = reinterpret_cast<const qint16*>(inputSample.data() + 2 * inputIdx); - *output++ = qFromLittleEndian<qint16>(*input); - result += 2; - if (inputIdx < m_format.channels()) - ++inputIdx; - } - m_dataPosition += frameSize; + // Establish format + if (memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0) + m_fileFormat.setByteOrder(QAudioFormat::LittleEndian); + else + m_fileFormat.setByteOrder(QAudioFormat::BigEndian); + + int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample); + m_fileFormat.setChannels(qFromLittleEndian<quint16>(header.wave.numChannels)); + m_fileFormat.setCodec("audio/pcm"); + m_fileFormat.setFrequency(qFromLittleEndian<quint32>(header.wave.sampleRate)); + m_fileFormat.setSampleSize(qFromLittleEndian<quint16>(header.wave.bitsPerSample)); + m_fileFormat.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt); } else { - break; + result = false; } } - + m_headerLength = pos(); return result; } - |