swift
wavfile.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2019 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "wavfile.h"
5 
6 #include <qendian.h>
7 
8 #include <limits> // Workaround for QTBUG-90395
9 
10 #include <QDebug>
11 #include <QVector>
12 // #include "utils.h"
13 
14 namespace swift::sound::wav
15 {
17  struct chunk
18  {
19  char id[4];
20  quint32 size;
21  };
22 
24  struct RIFFHeader
25  {
27  char type[4];
28  };
29 
31  struct WAVEHeader
32  {
34  quint16 audioFormat;
35  quint16 numChannels;
36  quint32 sampleRate;
37  quint32 byteRate;
38  quint16 blockAlign;
39  quint16 bitsPerSample;
40  };
41 
43  struct DATAHeader
44  {
46  };
47 
50  {
53  };
54 
55  CWavFile::CWavFile(QObject *parent) : QFile(parent), m_headerLength(0) {}
56 
57  bool CWavFile::open(const QString &fileName)
58  {
59  this->close();
60  this->setFileName(fileName);
61  return QFile::open(QIODevice::ReadOnly) && readHeader();
62  }
63 
64  const QAudioFormat &CWavFile::fileFormat() const { return m_fileFormat; }
65 
66  qint64 CWavFile::headerLength() const { return m_headerLength; }
67 
68  bool CWavFile::readHeader()
69  {
70  seek(0);
71  CombinedHeader header;
72  DATAHeader dataHeader;
73  bool result = read(reinterpret_cast<char *>(&header), sizeof(CombinedHeader)) == sizeof(CombinedHeader);
74  if (result)
75  {
76  if ((memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0 ||
77  memcmp(&header.riff.descriptor.id, "RIFX", 4) == 0) &&
78  memcmp(&header.riff.type, "WAVE", 4) == 0 && memcmp(&header.wave.descriptor.id, "fmt ", 4) == 0 &&
79  (header.wave.audioFormat == 1 || header.wave.audioFormat == 0 || header.wave.audioFormat == 3))
80  {
81  // Read off remaining header information
82  if (qFromLittleEndian<quint32>(header.wave.descriptor.size) > sizeof(WAVEHeader))
83  {
84  // Extended data available
85  quint16 extraFormatBytes;
86  if (peek((char *)&extraFormatBytes, sizeof(quint16)) != sizeof(quint16)) return false;
87  const qint64 throwAwayBytes = sizeof(quint16) + qFromLittleEndian<quint16>(extraFormatBytes);
88  if (read(throwAwayBytes).size() != throwAwayBytes) return false;
89  }
90 
91  if (read((char *)&dataHeader, sizeof(DATAHeader)) != sizeof(DATAHeader)) return false;
92 
93  // Establish format
94  int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample);
95  m_fileFormat.setChannelCount(qFromLittleEndian<quint16>(header.wave.numChannels));
96  m_fileFormat.setSampleRate(qFromLittleEndian<quint32>(header.wave.sampleRate));
97 
98  if (header.wave.audioFormat == 1 || header.wave.audioFormat == 0)
99  {
100  if (bps == 8) { m_fileFormat.setSampleFormat(QAudioFormat::UInt8); }
101  else if (bps == 16) { m_fileFormat.setSampleFormat(QAudioFormat::Int16); }
102  else { m_fileFormat.setSampleFormat(QAudioFormat::Int32); }
103  }
104  else { m_fileFormat.setSampleFormat(QAudioFormat::Float); }
105  }
106  else { result = false; }
107  }
108  m_headerLength = pos();
109 
110  if (memcmp(&dataHeader.descriptor.id, "data", 4) == 0)
111  {
112  const qint32 dataLength = qFromLittleEndian<qint32>(dataHeader.descriptor.size);
113  m_audioData = read(dataLength);
114  if (m_audioData.size() != dataLength)
115  {
116  m_audioData.clear();
117  return false;
118  }
119  }
120  return result;
121  }
122 } // namespace swift::sound::wav
const QAudioFormat & fileFormat() const
Audio format.
Definition: wavfile.cpp:64
qint64 headerLength() const
Header length.
Definition: wavfile.cpp:66
bool open(const QString &fileName)
Open.
Definition: wavfile.cpp:57
CWavFile(QObject *parent=nullptr)
Ctor.
Definition: wavfile.cpp:55
RIFFHeader riff
RIFF header.
Definition: wavfile.cpp:51
WAVEHeader wave
WAVE header.
Definition: wavfile.cpp:52
chunk descriptor
chunk descriptor
Definition: wavfile.cpp:45
chunk descriptor
chunk descriptor
Definition: wavfile.cpp:33
quint16 bitsPerSample
bits per sample
Definition: wavfile.cpp:39
quint16 numChannels
number of channels
Definition: wavfile.cpp:35
quint32 sampleRate
sample rate
Definition: wavfile.cpp:36
quint16 blockAlign
block align
Definition: wavfile.cpp:38
quint16 audioFormat
audio format, e.g.
Definition: wavfile.cpp:34
quint32 byteRate
byte rate
Definition: wavfile.cpp:37
quint32 size
chunk size
Definition: wavfile.cpp:20
char id[4]
chunk id
Definition: wavfile.cpp:19