| 1099 | // against the live registry — UnregisterWave erases from _waves |
| 1100 | // on destruction, so membership there proves the pointer is |
| 1101 | // still valid. |
| 1102 | if (std::find(_waves.begin(), _waves.end(), wave) == _waves.end()) |
| 1103 | continue; |
| 1104 | wave->_previewMute = false; |
| 1105 | wave->ApplyVolume(); |
| 1106 | } |
| 1107 | LOG_DEBUG(Audio, "ResumeMusicForPreview: restored {} music wave(s)", _suppressedMusic.size()); |
| 1108 | _suppressedMusic.clear(); |
| 1109 | } |
| 1110 | |
| 1111 | void SoundSystemOAL::PreloadWave(const char* name) |
| 1112 | { |
| 1113 | if (!name || !*name) |
| 1114 | { |
| 1115 | return; |
| 1116 | } |
| 1117 | // OGG rides the chunked streaming path and never enters the PCM |
| 1118 | // cache — preloading it would decode a full music track for nothing. |
| 1119 | if (const char* ext = strrchr(name, '.'); ext && !stricmp(ext, ".ogg")) |
| 1120 | { |
| 1121 | return; |
| 1122 | } |
| 1123 | if (_pcmCache.Contains(name)) |
| 1124 | { |
| 1125 | return; |
| 1126 | } |
| 1127 | |
| 1128 | auto work = [this, path = std::string(name)]() |
| 1129 | { |
| 1130 | Ref<WaveStream> stream = SoundLoadFile(path.c_str()); |
| 1131 | if (!stream) |
| 1132 | { |
| 1133 | LOG_DEBUG(Audio, "PreloadWave: '{}' not found", path.c_str()); |
| 1134 | return; |
| 1135 | } |
| 1136 | const int size = stream->GetUncompressedSize(); |
| 1137 | if (size <= 0 || static_cast<size_t>(size) > Audio::PcmCache::kMaxEntryBytes) |
| 1138 | { |
| 1139 | return; // oversized waves decode async at play time instead |
| 1140 | } |
| 1141 | auto entry = std::make_shared<Audio::PcmCache::Entry>(); |
| 1142 | stream->GetFormat(entry->fmt); |
| 1143 | entry->uncompressedSize = static_cast<unsigned int>(size); |
| 1144 | entry->pcm.assign(static_cast<size_t>(size), 0); |
| 1145 | stream->GetData(entry->pcm.data(), 0, size); |
| 1146 | _pcmCache.Insert(path.c_str(), std::move(entry)); |
| 1147 | }; |
| 1148 | |
| 1149 | // The system can be torn down (device switch / shutdown) while a |
| 1150 | // worker holds the lambda; the mission-load call site runs inside |
| 1151 | // the loading screen where that cannot happen, but guard the late |
| 1152 | // case by running synchronously when no pool exists. |
| 1153 | if (auto* pool = GetGlobalTaskPool()) |
| 1154 | { |
nothing calls this directly
no test coverage detected