Codefix: Documentation comment in IndustryDirectoryWindow (#13059)
[openttd-github.git] / src / sound.cpp
blob2e51d31b268c7e1b1e78376de42ec99c1694e87f
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
8 /** @file sound.cpp Handling of playing sounds. */
10 #include "stdafx.h"
11 #include "landscape.h"
12 #include "mixer.h"
13 #include "newgrf_sound.h"
14 #include "random_access_file_type.h"
15 #include "window_func.h"
16 #include "window_gui.h"
17 #include "vehicle_base.h"
19 /* The type of set we're replacing */
20 #define SET_TYPE "sounds"
21 #include "base_media_func.h"
23 #include "safeguards.h"
25 static SoundEntry _original_sounds[ORIGINAL_SAMPLE_COUNT];
27 static void OpenBankFile(const std::string &filename)
29 /**
30 * The sound file for the original sounds, i.e. those not defined/overridden by a NewGRF.
31 * Needs to be kept alive during the game as _original_sounds[n].file refers to this.
33 static std::unique_ptr<RandomAccessFile> original_sound_file;
35 memset(_original_sounds, 0, sizeof(_original_sounds));
37 /* If there is no sound file (nosound set), don't load anything */
38 if (filename.empty()) return;
40 original_sound_file.reset(new RandomAccessFile(filename, BASESET_DIR));
41 size_t pos = original_sound_file->GetPos();
42 uint count = original_sound_file->ReadDword();
44 /* The new format has the highest bit always set */
45 bool new_format = HasBit(count, 31);
46 ClrBit(count, 31);
47 count /= 8;
49 /* Simple check for the correct number of original sounds. */
50 if (count != ORIGINAL_SAMPLE_COUNT) {
51 /* Corrupt sample data? Just leave the allocated memory as those tell
52 * there is no sound to play (size = 0 due to calloc). Not allocating
53 * the memory disables valid NewGRFs that replace sounds. */
54 Debug(misc, 6, "Incorrect number of sounds in '{}', ignoring.", filename);
55 return;
58 original_sound_file->SeekTo(pos, SEEK_SET);
60 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
61 _original_sounds[i].file = original_sound_file.get();
62 _original_sounds[i].file_offset = GB(original_sound_file->ReadDword(), 0, 31) + pos;
63 _original_sounds[i].file_size = original_sound_file->ReadDword();
66 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
67 SoundEntry *sound = &_original_sounds[i];
68 char name[255];
70 original_sound_file->SeekTo(sound->file_offset, SEEK_SET);
72 /* Check for special case, see else case */
73 original_sound_file->ReadBlock(name, original_sound_file->ReadByte()); // Read the name of the sound
74 if (new_format || strcmp(name, "Corrupt sound") != 0) {
75 original_sound_file->SeekTo(12, SEEK_CUR); // Skip past RIFF header
77 /* Read riff tags */
78 for (;;) {
79 uint32_t tag = original_sound_file->ReadDword();
80 uint32_t size = original_sound_file->ReadDword();
82 if (tag == ' tmf') {
83 original_sound_file->ReadWord(); // wFormatTag
84 sound->channels = original_sound_file->ReadWord(); // wChannels
85 sound->rate = original_sound_file->ReadDword(); // samples per second
86 if (!new_format) sound->rate = 11025; // seems like all old samples should be played at this rate.
87 original_sound_file->ReadDword(); // avg bytes per second
88 original_sound_file->ReadWord(); // alignment
89 sound->bits_per_sample = original_sound_file->ReadByte(); // bits per sample
90 original_sound_file->SeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
91 } else if (tag == 'atad') {
92 sound->file_size = size;
93 sound->file = original_sound_file.get();
94 sound->file_offset = original_sound_file->GetPos();
95 break;
96 } else {
97 sound->file_size = 0;
98 break;
101 } else {
103 * Special case for the jackhammer sound
104 * (name in sample.cat is "Corrupt sound")
105 * It's no RIFF file, but raw PCM data
107 sound->channels = 1;
108 sound->rate = 11025;
109 sound->bits_per_sample = 8;
110 sound->file = original_sound_file.get();
111 sound->file_offset = original_sound_file->GetPos();
116 static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound)
118 assert(sound != nullptr);
120 /* Check for valid sound size. */
121 if (sound->file_size == 0 || sound->file_size > SIZE_MAX - 2) return false;
123 int8_t *mem = MallocT<int8_t>(sound->file_size + 2);
124 /* Add two extra bytes so rate conversion can read these
125 * without reading out of its input buffer. */
126 mem[sound->file_size ] = 0;
127 mem[sound->file_size + 1] = 0;
129 RandomAccessFile *file = sound->file;
130 file->SeekTo(sound->file_offset, SEEK_SET);
131 file->ReadBlock(mem, sound->file_size);
133 /* 16-bit PCM WAV files should be signed by default */
134 if (sound->bits_per_sample == 8) {
135 for (uint i = 0; i != sound->file_size; i++) {
136 mem[i] += -128; // Convert unsigned sound data to signed
140 if constexpr (std::endian::native == std::endian::big) {
141 if (sound->bits_per_sample == 16) {
142 size_t num_samples = sound->file_size / 2;
143 int16_t *samples = reinterpret_cast<int16_t *>(mem);
144 for (size_t i = 0; i < num_samples; i++) {
145 samples[i] = BSWAP16(samples[i]);
150 assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16);
151 assert(sound->channels == 1);
152 assert(sound->file_size != 0 && sound->rate != 0);
154 MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16);
156 return true;
159 void InitializeSound()
161 Debug(misc, 1, "Loading sound effects...");
162 OpenBankFile(BaseSounds::GetUsedSet()->files->filename);
165 /* Low level sound player */
166 static void StartSound(SoundID sound_id, float pan, uint volume)
168 if (volume == 0) return;
170 SoundEntry *sound = GetSound(sound_id);
171 if (sound == nullptr) return;
173 /* NewGRF sound that wasn't loaded yet? */
174 if (sound->rate == 0 && sound->file != nullptr) {
175 if (!LoadNewGRFSound(sound)) {
176 /* Mark as invalid. */
177 sound->file = nullptr;
178 return;
182 /* Empty sound? */
183 if (sound->rate == 0) return;
185 MixerChannel *mc = MxAllocateChannel();
186 if (mc == nullptr) return;
188 if (!SetBankSource(mc, sound)) return;
190 /* Apply the sound effect's own volume. */
191 volume = sound->volume * volume;
193 MxSetChannelVolume(mc, volume, pan);
194 MxActivateChannel(mc);
198 static const uint8_t _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87};
199 static_assert(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_END);
201 static const uint8_t _sound_base_vol[] = {
202 128, 90, 128, 128, 128, 128, 128, 128,
203 128, 90, 90, 128, 128, 128, 128, 128,
204 128, 128, 128, 80, 128, 128, 128, 128,
205 128, 128, 128, 128, 128, 128, 128, 128,
206 128, 128, 90, 90, 90, 128, 90, 128,
207 128, 90, 128, 128, 128, 90, 128, 128,
208 128, 128, 128, 128, 90, 128, 128, 128,
209 128, 90, 128, 128, 128, 128, 128, 128,
210 128, 128, 90, 90, 90, 128, 128, 128,
214 static const uint8_t _sound_idx[] = {
215 2, 3, 4, 5, 6, 7, 8, 9,
216 10, 11, 12, 13, 14, 15, 16, 17,
217 18, 19, 20, 21, 22, 23, 24, 25,
218 26, 27, 28, 29, 30, 31, 32, 33,
219 34, 35, 36, 37, 38, 39, 40, 0,
220 1, 41, 42, 43, 44, 45, 46, 47,
221 48, 49, 50, 51, 52, 53, 54, 55,
222 56, 57, 58, 59, 60, 61, 62, 63,
223 64, 65, 66, 67, 68, 69, 70, 71,
227 void SndCopyToPool()
229 SoundEntry *sound = AllocateSound(ORIGINAL_SAMPLE_COUNT);
230 for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
231 sound[i] = _original_sounds[_sound_idx[i]];
232 sound[i].volume = _sound_base_vol[i];
233 sound[i].priority = 0;
238 * Change the configured sound set and reset sounds.
239 * @param index Index of sound set to switch to.
241 void ChangeSoundSet(int index)
243 if (BaseSounds::GetIndexOfUsedSet() == index) return;
245 auto set = BaseSounds::GetSet(index);
246 BaseSounds::ini_set = set->name;
247 BaseSounds::SetSet(set);
249 MxCloseAllChannels();
250 InitializeSound();
252 /* Replace baseset sounds in the pool with the updated original sounds. This is safe to do as
253 * any sound still playing owns its sample data. */
254 for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
255 SoundEntry *sound = GetSound(i);
256 /* GRF Container 0 means the sound comes from the baseset, and isn't overridden by NewGRF. */
257 if (sound == nullptr || sound->grf_container_ver != 0) continue;
259 *sound = _original_sounds[_sound_idx[i]];
260 sound->volume = _sound_base_vol[i];
261 sound->priority = 0;
264 InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_OPTIONS, 0, true);
268 * Decide 'where' (between left and right speaker) to play the sound effect.
269 * Note: Callers must determine if sound effects are enabled. This plays a sound regardless of the setting.
270 * @param sound Sound effect to play
271 * @param left Left edge of virtual coordinates where the sound is produced
272 * @param right Right edge of virtual coordinates where the sound is produced
273 * @param top Top edge of virtual coordinates where the sound is produced
274 * @param bottom Bottom edge of virtual coordinates where the sound is produced
276 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
278 /* Iterate from back, so that main viewport is checked first */
279 for (const Window *w : Window::IterateFromBack()) {
280 const Viewport *vp = w->viewport;
282 if (vp != nullptr &&
283 left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
284 top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
285 int screen_x = (left + right) / 2 - vp->virtual_left;
286 int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
287 float panning = (float)screen_x / width;
289 StartSound(
290 sound,
291 panning,
292 _vol_factor_by_zoom[vp->zoom]
294 return;
299 void SndPlayTileFx(SoundID sound, TileIndex tile)
301 /* emits sound from center of the tile */
302 int x = std::min(Map::MaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
303 int y = std::min(Map::MaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
304 int z = (y < 0 ? 0 : GetSlopePixelZ(x, y));
305 Point pt = RemapCoords(x, y, z);
306 y += 2 * TILE_SIZE;
307 Point pt2 = RemapCoords(x, y, GetSlopePixelZ(x, y));
308 SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
311 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
313 SndPlayScreenCoordFx(sound,
314 v->coord.left, v->coord.right,
315 v->coord.top, v->coord.bottom
319 void SndPlayFx(SoundID sound)
321 StartSound(sound, 0.5, UINT8_MAX);
324 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<SoundsSet>, SoundsSet)
326 /** Names corresponding to the sound set's files */
327 static const char * const _sound_file_names[] = { "samples" };
330 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
331 /* static */ const char * const *BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names = _sound_file_names;
333 template <class Tbase_set>
334 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
336 return ".obs"; // OpenTTD Base Sounds
339 template <class Tbase_set>
340 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
342 if (BaseMedia<Tbase_set>::used_set != nullptr) return true;
344 const Tbase_set *best = nullptr;
345 for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != nullptr; c = c->next) {
346 /* Skip unusable sets */
347 if (c->GetNumMissing() != 0) continue;
349 if (best == nullptr ||
350 (best->fallback && !c->fallback) ||
351 best->valid_files < c->valid_files ||
352 (best->valid_files == c->valid_files &&
353 (best->shortname == c->shortname && best->version < c->version))) {
354 best = c;
358 BaseMedia<Tbase_set>::used_set = best;
359 return BaseMedia<Tbase_set>::used_set != nullptr;