• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Razakhel / RaZ / 18062694977

27 Sep 2025 04:20PM UTC coverage: 74.093% (+0.04%) from 74.05%
18062694977

push

github

Razakhel
[Utils/Logger] Added formatted logging overloads

- Formatted calls to logging functions and made use of std::format() in several other places

100 of 170 new or added lines in 36 files covered. (58.82%)

4 existing lines in 2 files now uncovered.

8334 of 11248 relevant lines covered (74.09%)

1757.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.78
/src/RaZ/Data/WavLoad.cpp
1
#include "RaZ/Audio/AudioData.hpp"
2
#include "RaZ/Data/WavFormat.hpp"
3
#include "RaZ/Utils/FilePath.hpp"
4
#include "RaZ/Utils/Logger.hpp"
5

6
#include "tracy/Tracy.hpp"
7

8
#include <array>
9
#include <fstream>
10
#include <optional>
11
#include <string>
12

13
namespace Raz::WavFormat {
14

15
namespace {
16

17
constexpr uint32_t fromLittleEndian(const std::array<uint8_t, 4>& bytes) {
29✔
18
  return static_cast<uint32_t>((bytes[0] << 0u) | (bytes[1] << 8u) | (bytes[2] << 16u) | (bytes[3] << 24u));
29✔
19
}
20

21
constexpr uint16_t fromLittleEndian(uint8_t byte1, uint8_t byte2) {
20✔
22
  return static_cast<uint16_t>((byte1 << 0u) | (byte2 << 8u));
20✔
23
}
24

25
struct WavInfo {
26
  uint32_t fileSize {};
27
  uint32_t formatBlockSize {};
28
  uint16_t audioFormat {};
29
  uint16_t channelCount {};
30
  uint32_t frequency {};
31
  uint32_t bytesPerSecond {};
32
  uint16_t bytesPerBlock {};
33
  uint16_t bitsPerSample {};
34
  uint32_t dataSize {};
35
};
36

37
void loadFmt(std::ifstream& file, WavInfo& info) {
5✔
38
  std::array<uint8_t, 4> bytes {};
5✔
39

40
  file.read(reinterpret_cast<char*>(bytes.data()), 4); // Format block size - 16
10✔
41
  info.formatBlockSize = fromLittleEndian(bytes);
5✔
42

43
  file.read(reinterpret_cast<char*>(bytes.data()), 2); // Audio format
10✔
44
  info.audioFormat = fromLittleEndian(bytes[0], bytes[1]);
5✔
45
  // 0: Unknown
46
  // 1: PCM (uncompressed)
47
  // 2: Microsoft ADPCM
48
  // 3: IEEE float
49
  // 6: 8-bit ITU-T G.711 A-law
50
  // 7: 8-bit ITU-T G.711 ยต-law
51
  // 17: IMA ADPCM
52
  // 20: ITU G.723 ADPCM (Yamaha)
53
  // 49: GSM 6.10
54
  // 64: ITU G.721 ADPCM
55
  // 80: MPEG
56

57
  if (info.audioFormat != 1)
5✔
58
    Logger::warn("[WavLoad] Only WAV files with a PCM format are supported");
×
59

60
  file.read(reinterpret_cast<char*>(bytes.data()), 2); // Channel count
10✔
61
  info.channelCount = fromLittleEndian(bytes[0], bytes[1]);
5✔
62
  // 1 channel:  mono
63
  // 2 channels: stereo
64
  // 3 channels: left, center & right
65
  // 4 channels: front left, front right, back left & back right
66
  // 5 channels: left, center, right & surround
67
  // 6 channels: left, center left, center, center right, right & surround
68

69
  file.read(reinterpret_cast<char*>(bytes.data()), 4); // Sampling frequency
10✔
70
  info.frequency = fromLittleEndian(bytes);
5✔
71

72
  file.read(reinterpret_cast<char*>(bytes.data()), 4); // Bytes per second (frequency * bytes per block)
10✔
73
  info.bytesPerSecond = fromLittleEndian(bytes);
5✔
74

75
  file.read(reinterpret_cast<char*>(bytes.data()), 2); // Bytes per block (bits per sample / 8 * channel count)
10✔
76
  info.bytesPerBlock = fromLittleEndian(bytes[0], bytes[1]);
5✔
77

78
  file.read(reinterpret_cast<char*>(bytes.data()), 2); // Bits per sample (bit depth)
10✔
79
  info.bitsPerSample = fromLittleEndian(bytes[0], bytes[1]);
5✔
80
}
5✔
81

82
std::optional<WavInfo> validateWav(std::ifstream& file) {
5✔
83
  WavInfo info {};
5✔
84

85
  std::array<uint8_t, 4> bytes {};
5✔
86

87
  file.read(reinterpret_cast<char*>(bytes.data()), 4); // 'RIFF'
10✔
88
  if (bytes[0] != 'R' && bytes[1] != 'I' && bytes[2] != 'F' && bytes[3] != 'F')
5✔
89
    return std::nullopt;
×
90

91
  file.read(reinterpret_cast<char*>(bytes.data()), 4); // File size - 8
10✔
92
  info.fileSize = fromLittleEndian(bytes); // Values are in little-endian; they must be converted
5✔
93

94
  file.read(reinterpret_cast<char*>(bytes.data()), 4); // 'WAVE'
10✔
95
  if (bytes[0] != 'W' && bytes[1] != 'A' && bytes[2] != 'V' && bytes[3] != 'E')
5✔
96
    return std::nullopt;
×
97

98
  // Additional chunks can be present (such as 'JUNK', 'cue ', 'LIST', 'bext' and others), which aren't supported there. They must be skipped
99
  // See:
100
  // - https://en.wikipedia.org/wiki/WAV#File_specifications
101
  // - https://en.wikipedia.org/wiki/Broadcast_Wave_Format#Details
102
  // - https://stackoverflow.com/a/76137824/3292304
103
  while (file) {
14✔
104
    file.read(reinterpret_cast<char*>(bytes.data()), 4);
28✔
105

106
    if (bytes[0] == 'f' && bytes[1] == 'm' && bytes[2] == 't' && bytes[3] == ' ') {
14✔
107
      loadFmt(file, info);
5✔
108
      continue;
5✔
109
    }
110

111
    if (bytes[0] == 'd' && bytes[1] == 'a' && bytes[2] == 't' && bytes[3] == 'a') {
9✔
112
      file.read(reinterpret_cast<char*>(bytes.data()), 4); // Data size (file size - header size (theoretically 44 bytes))
10✔
113
      info.dataSize = fromLittleEndian(bytes);
5✔
114

115
      return info;
5✔
116
    }
117

118
    // Unsupported chunk, skip it
119
    file.read(reinterpret_cast<char*>(bytes.data()), 4); // Chunk size
8✔
120
    file.ignore(fromLittleEndian(bytes));
4✔
121
  }
122

123
  throw std::invalid_argument("[WavLoad] No data block found");
×
124
}
125

126
} // namespace
127

128
AudioData load(const FilePath& filePath) {
5✔
129
  ZoneScopedN("WavFormat::load");
130
  ZoneTextF("Path: %s", filePath.toUtf8().c_str());
131

132
  Logger::debug("[WavLoad] Loading WAV file ('{}')...", filePath);
5✔
133

134
  std::ifstream file(filePath, std::ios_base::binary);
5✔
135

136
  if (!file)
5✔
NEW
137
    throw std::invalid_argument(std::format("[WavLoad] Could not open the WAV file '{}'", filePath));
×
138

139
  const std::optional<WavInfo> info = validateWav(file);
5✔
140

141
  if (info == std::nullopt)
5✔
NEW
142
    throw std::runtime_error(std::format("[WavLoad] '{}' is not a valid WAV audio file", filePath));
×
143

144
  AudioData audioData {};
5✔
145

146
  // Determining the right audio format
147
  switch (info->bitsPerSample) {
5✔
148
    case 8:
×
149
      if (info->channelCount == 1)
×
150
        audioData.format = AudioFormat::MONO_U8;
×
151
      else if (info->channelCount == 2)
×
152
        audioData.format = AudioFormat::STEREO_U8;
×
153
      break;
×
154

155
    case 16:
5✔
156
      if (info->channelCount == 1)
5✔
157
        audioData.format = AudioFormat::MONO_I16;
5✔
158
      else if (info->channelCount == 2)
×
159
        audioData.format = AudioFormat::STEREO_I16;
×
160
      break;
5✔
161

162
    case 32:
×
163
      if (info->channelCount == 1)
×
164
        audioData.format = AudioFormat::MONO_F32;
×
165
      else if (info->channelCount == 2)
×
166
        audioData.format = AudioFormat::STEREO_F32;
×
167
      break;
×
168

169
    case 64:
×
170
      if (info->channelCount == 1)
×
171
        audioData.format = AudioFormat::MONO_F64;
×
172
      else if (info->channelCount == 2)
×
173
        audioData.format = AudioFormat::STEREO_F64;
×
174
      break;
×
175

176
    default:
×
NEW
177
      throw std::runtime_error(std::format("[WavLoad] {} bits WAV files are unsupported", info->bitsPerSample));
×
178
  }
179

180
  // If the format is still unassigned, it is invalid
181
  if (static_cast<int>(audioData.format) == 0)
5✔
182
    throw std::runtime_error("[WavLoad] Unsupported WAV channel count");
×
183

184
  audioData.frequency = static_cast<int>(info->frequency);
5✔
185

186
  // Reading the actual audio data from the file
187
  audioData.buffer.resize(info->dataSize);
5✔
188
  file.read(reinterpret_cast<char*>(audioData.buffer.data()), static_cast<std::streamsize>(audioData.buffer.size()));
5✔
189

190
  Logger::debug("[WavLoad] Loaded WAV file");
5✔
191

192
  return audioData;
10✔
193
}
5✔
194

195
} // namespace Raz::WavFormat
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc