OpenTTD Source 20241224-master-gee860a5c8e
newgrf_sound.cpp
Go to the documentation of this file.
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 */
7
10#include "stdafx.h"
11#include "engine_base.h"
12#include "newgrf.h"
13#include "newgrf_engine.h"
14#include "newgrf_sound.h"
15#include "vehicle_base.h"
16#include "sound_func.h"
17#include "soundloader_func.h"
18#include "string_func.h"
20#include "debug.h"
21#include "settings_type.h"
22
23#include "safeguards.h"
24
25static std::vector<SoundEntry> _sounds;
26
27
34{
35 size_t pos = _sounds.size();
36 _sounds.insert(_sounds.end(), num, SoundEntry());
37 return &_sounds[pos];
38}
39
40
41void InitializeSoundPool()
42{
43 _sounds.clear();
44
45 /* Copy original sound data to the pool */
46 SndCopyToPool();
47}
48
49
50SoundEntry *GetSound(SoundID index)
51{
52 if (index >= _sounds.size()) return nullptr;
53 return &_sounds[index];
54}
55
56
57uint GetNumSounds()
58{
59 return (uint)_sounds.size();
60}
61
67{
68 size_t bytes = 0;
69 for (SoundEntry &sound : _sounds) {
70 if (sound.data == nullptr) continue;
71
72 const auto &data = *sound.data;
73 bytes += data.capacity() * sizeof(data[0]);
74 }
75 return bytes;
76}
77
83bool LoadNewGRFSound(SoundEntry &sound, SoundID sound_id)
84{
85 if (sound.file_offset == SIZE_MAX || sound.file == nullptr) return false;
86
87 RandomAccessFile &file = *sound.file;
88 file.SeekTo(sound.file_offset, SEEK_SET);
89
90 /* Skip ID for container version >= 2 as we only look at the first
91 * entry and ignore any further entries with the same ID. */
92 if (sound.grf_container_ver >= 2) file.ReadDword();
93
94 /* Format: <num> <FF> <FF> <name_len> <name> '\0' <data> */
95
96 sound.file_size = sound.grf_container_ver >= 2 ? file.ReadDword() : file.ReadWord();
97 if (file.ReadByte() != 0xFF) return false;
98 if (file.ReadByte() != 0xFF) return false;
99
100 uint8_t name_len = file.ReadByte();
101 std::string name(name_len + 1, '\0');
102 file.ReadBlock(name.data(), name_len + 1);
103
104 /* Test string termination */
105 if (name[name_len] != '\0') {
106 Debug(grf, 2, "LoadNewGRFSound [{}]: Name not properly terminated", file.GetSimplifiedFilename());
107 return false;
108 }
109
110 if (LoadSoundData(sound, true, sound_id, StrMakeValid(name))) return true;
111
112 Debug(grf, 1, "LoadNewGRFSound [{}]: does not contain any sound data", file.GetSimplifiedFilename());
113
114 /* Clear everything that was read */
115 sound = {};
116 return false;
117}
118
125SoundID GetNewGRFSoundID(const GRFFile *file, SoundID sound_id)
126{
127 /* Global sound? */
128 if (sound_id < ORIGINAL_SAMPLE_COUNT) return sound_id;
129
130 sound_id -= ORIGINAL_SAMPLE_COUNT;
131 if (file == nullptr || sound_id >= file->num_sounds) return INVALID_SOUND;
132
133 return file->sound_offset + sound_id;
134}
135
143bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event, bool force)
144{
145 if (!_settings_client.sound.vehicle && !force) return true;
146
147 const GRFFile *file = v->GetGRF();
148 uint16_t callback;
149
150 /* If the engine has no GRF ID associated it can't ever play any new sounds */
151 if (file == nullptr) return false;
152
153 /* Check that the vehicle type uses the sound effect callback */
154 if (!HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_SOUND_EFFECT)) return false;
155
156 callback = GetVehicleCallback(CBID_VEHICLE_SOUND_EFFECT, event, 0, v->engine_type, v);
157 /* Play default sound if callback fails */
158 if (callback == CALLBACK_FAILED) return false;
159
160 callback = GetNewGRFSoundID(file, callback);
161
162 /* Play no sound, if result is invalid */
163 if (callback == INVALID_SOUND) return true;
164
165 assert(callback < GetNumSounds());
166 SndPlayVehicleFx(callback, v);
167 return true;
168}
169
176void PlayTileSound(const GRFFile *file, SoundID sound_id, TileIndex tile)
177{
178 sound_id = GetNewGRFSoundID(file, sound_id);
179 if (sound_id == INVALID_SOUND) return;
180
181 assert(sound_id < GetNumSounds());
182 SndPlayTileFx(sound_id, tile);
183}
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
A file from which bytes, words and double words are read in (potentially) a random order.
void ReadBlock(void *ptr, size_t size)
Read a block.
void SeekTo(size_t pos, int mode)
Seek in the current file.
uint8_t ReadByte()
Read a byte from the file.
const std::string & GetSimplifiedFilename() const
Get the simplified filename of the opened file.
uint32_t ReadDword()
Read a double word (32 bits) from the file (in low endian format).
uint16_t ReadWord()
Read a word (16 bits) from the file (in low endian format).
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
Base class for engines.
Base for the NewGRF implementation.
@ CBID_VEHICLE_SOUND_EFFECT
Called to play a special sound effect.
@ CBM_VEHICLE_SOUND_EFFECT
Vehicle uses custom sound effects.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
Functions for NewGRF engines.
SoundEntry * AllocateSound(uint num)
Allocate sound slots.
void PlayTileSound(const GRFFile *file, SoundID sound_id, TileIndex tile)
Play a NewGRF sound effect at the location of a specific tile.
bool LoadNewGRFSound(SoundEntry &sound, SoundID sound_id)
Extract meta data from a NewGRF sound.
bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event, bool force)
Checks whether a NewGRF wants to play a different vehicle sound effect.
size_t GetSoundPoolAllocatedMemory()
Get size of memory allocated to sound effects.
SoundID GetNewGRFSoundID(const GRFFile *file, SoundID sound_id)
Resolve NewGRF sound ID.
Functions related to NewGRF provided sounds.
VehicleSoundEvent
Events at which a sound might be played.
Class related to random access to files.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
Types related to global configuration settings.
Functions related to sound.
static const uint ORIGINAL_SAMPLE_COUNT
The number of sounds in the original sample.cat.
Definition sound_type.h:124
Functions related to sound loaders.
Definition of base types and functions in a cross-platform compatible way.
static void StrMakeValid(T &dst, const char *str, const char *last, StringValidationSettings settings)
Copies the valid (UTF-8) characters from str up to last to the dst.
Definition string.cpp:107
Functions related to low-level strings.
SoundSettings sound
sound effect settings
uint16_t callback_mask
Bitmask of vehicle callbacks that have to be called.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:108
uint8_t grf_container_ver
NewGRF container version if the sound is from a NewGRF.
Definition sound_type.h:30
bool vehicle
Play vehicle sound effects.
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
const GRFFile * GetGRF() const
Retrieve the NewGRF the vehicle is tied to.
Definition vehicle.cpp:757
Base class for all vehicles.