| 90 | } |
| 91 | |
| 92 | std::optional<BufferId> loadMusicSample(PathId asset) |
| 93 | { |
| 94 | auto res = _musicSamples.find(asset); |
| 95 | if (res != std::end(_musicSamples)) |
| 96 | { |
| 97 | return res->second; |
| 98 | } |
| 99 | |
| 100 | const auto path = Environment::getPath(asset); |
| 101 | try |
| 102 | { |
| 103 | FileStream fs(path, StreamMode::read); |
| 104 | |
| 105 | const auto sig = fs.readValue<uint32_t>(); |
| 106 | if (sig != 0x46464952) |
| 107 | { |
| 108 | throw Exception::RuntimeError("Invalid signature."); |
| 109 | } |
| 110 | |
| 111 | fs.readValue<uint32_t>(); |
| 112 | |
| 113 | const auto riffType = fs.readValue<uint32_t>(); |
| 114 | if (riffType != 0x45564157) |
| 115 | { |
| 116 | throw Exception::RuntimeError("Invalid format."); |
| 117 | } |
| 118 | |
| 119 | const auto fmtMarker = fs.readValue<uint32_t>(); |
| 120 | if (fmtMarker != 0x20746d66 && fmtMarker != 0x00746d66) |
| 121 | { |
| 122 | throw Exception::RuntimeError("Invalid format marker."); |
| 123 | } |
| 124 | |
| 125 | fs.readValue<uint32_t>(); |
| 126 | |
| 127 | const auto typeFormat = fs.readValue<uint16_t>(); |
| 128 | if (typeFormat != 1) |
| 129 | { |
| 130 | throw Exception::RuntimeError("Invalid format type, expected PCM."); |
| 131 | } |
| 132 | |
| 133 | const auto channels = fs.readValue<uint16_t>(); |
| 134 | const auto sampleRate = fs.readValue<uint32_t>(); |
| 135 | |
| 136 | fs.readValue<uint32_t>(); |
| 137 | fs.readValue<uint16_t>(); |
| 138 | |
| 139 | const auto bits = fs.readValue<uint16_t>(); |
| 140 | |
| 141 | const auto dataMarker = fs.readValue<uint32_t>(); |
| 142 | if (dataMarker != 0x61746164) |
| 143 | { |
| 144 | throw Exception::RuntimeError("Invalid data marker."); |
| 145 | } |
| 146 | |
| 147 | const auto pcmLen = fs.readValue<uint32_t>(); |
| 148 | |
| 149 | std::vector<std::uint8_t> pcm(pcmLen); |