Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
LegacyWave.cpp
Go to the documentation of this file.
1#include "LegacyWave.hpp"
2
3#include <algorithm>
4#include <cstddef>
5#include <limits>
6
7namespace monopoly::audio
8{
9 namespace
10 {
11 [[nodiscard]] constexpr std::uint32_t readLe32(
12 std::span<const std::uint8_t> bytes, std::size_t offset) noexcept
13 {
14 return static_cast<std::uint32_t>(bytes[offset]) |
15 (static_cast<std::uint32_t>(bytes[offset + 1U]) << 8U) |
16 (static_cast<std::uint32_t>(bytes[offset + 2U]) << 16U) |
17 (static_cast<std::uint32_t>(bytes[offset + 3U]) << 24U);
18 }
19
20 [[nodiscard]] constexpr bool fourCC(
21 std::span<const std::uint8_t> bytes, std::size_t offset,
22 char a, char b, char c, char d) noexcept
23 {
24 return bytes[offset] == static_cast<std::uint8_t>(a) &&
25 bytes[offset + 1U] == static_cast<std::uint8_t>(b) &&
26 bytes[offset + 2U] == static_cast<std::uint8_t>(c) &&
27 bytes[offset + 3U] == static_cast<std::uint8_t>(d);
28 }
29 }
30
32 std::span<const std::uint8_t> riffWave,
33 std::uint32_t ticksPerSecond) noexcept
34 {
35 if (riffWave.size() < 12U || ticksPerSecond == 0U ||
36 !fourCC(riffWave, 0U, 'R', 'I', 'F', 'F') ||
37 !fourCC(riffWave, 8U, 'W', 'A', 'V', 'E'))
38 return 0U;
39
40 const std::uint64_t riffEnd64 =
41 8ULL + static_cast<std::uint64_t>(readLe32(riffWave, 4U));
42 if (riffEnd64 > riffWave.size() || riffEnd64 < 12U)
43 return 0U;
44 const auto riffEnd = static_cast<std::size_t>(riffEnd64);
45
46 std::uint32_t averageBytesPerSecond{};
47 std::uint32_t dataBytes{};
48 std::size_t offset = 12U;
49 while (offset + 8U <= riffEnd)
50 {
51 const std::uint32_t chunkSize = readLe32(riffWave, offset + 4U);
52 const std::uint64_t payloadEnd64 =
53 static_cast<std::uint64_t>(offset) + 8ULL + chunkSize;
55 return 0U;
56
57 if (fourCC(riffWave, offset, 'f', 'm', 't', ' '))
58 {
59 if (chunkSize < 12U)
60 return 0U;
61 averageBytesPerSecond = readLe32(riffWave, offset + 16U);
62 }
63 else if (fourCC(riffWave, offset, 'd', 'a', 't', 'a'))
65
66 const std::uint64_t next64 = payloadEnd64 + (chunkSize & 1U);
67 if (next64 > riffEnd)
68 return 0U;
69 offset = static_cast<std::size_t>(next64);
70 }
71
72 if (averageBytesPerSecond == 0U || dataBytes == 0U)
73 return 0U;
74
75 const std::uint64_t duration =
76 static_cast<std::uint64_t>(dataBytes) * ticksPerSecond /
77 averageBytesPerSecond;
78 if (duration == 0U)
79 return 1U;
80 return static_cast<std::uint32_t>(
81 std::min<std::uint64_t>(duration,
82 std::numeric_limits<std::uint32_t>::max()));
83 }
84
85}
std::size_t offset
std::vector< std::byte > bytes
unsigned index
std::uint32_t legacyWaveDurationTicks(std::span< const std::uint8_t > riffWave, std::uint32_t ticksPerSecond) noexcept
constexpr std::uint32_t fourCC(char a, char b, char c, char d) noexcept
std::uint32_t readLe32(std::span< const std::uint8_t > bytes, std::size_t offset) noexcept