OpenTTD Source 20260206-master-g4d4e37dbf1
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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
84bool LoadNewGRFSound(SoundEntry &sound, SoundID sound_id)
85{
86 if (sound.file_offset == SIZE_MAX || sound.file == nullptr) return false;
87
88 RandomAccessFile &file = *sound.file;
89 file.SeekTo(sound.file_offset, SEEK_SET);
90
91 /* Skip ID for container version >= 2 as we only look at the first
92 * entry and ignore any further entries with the same ID. */
93 if (sound.grf_container_ver >= 2) file.ReadDword();
94
95 /* Format: <num> <FF> <FF> <name_len> <name> '\0' <data> */
96
97 sound.file_size = sound.grf_container_ver >= 2 ? file.ReadDword() : file.ReadWord();
98 if (file.ReadByte() != 0xFF) return false;
99 if (file.ReadByte() != 0xFF) return false;
100
101 uint8_t name_len = file.ReadByte();
102 std::string name(name_len + 1, '\0');
103 file.ReadBlock(name.data(), name_len + 1);
104
105 /* Test string termination */
106 if (name[name_len] != '\0') {
107 Debug(grf, 2, "LoadNewGRFSound [{}]: Name not properly terminated", file.GetSimplifiedFilename());
108 return false;
109 }
110
111 if (LoadSoundData(sound, true, sound_id, StrMakeValid(name))) return true;
112
113 Debug(grf, 1, "LoadNewGRFSound [{}]: does not contain any sound data", file.GetSimplifiedFilename());
114
115 /* Clear everything that was read */
116 sound = {};
117 return false;
118}
119
126SoundID GetNewGRFSoundID(const GRFFile *file, SoundID sound_id)
127{
128 /* Global sound? */
129 if (sound_id < ORIGINAL_SAMPLE_COUNT) return sound_id;
130
131 sound_id -= ORIGINAL_SAMPLE_COUNT;
132 if (file == nullptr || sound_id >= file->num_sounds) return INVALID_SOUND;
133
134 return file->sound_offset + sound_id;
135}
136
144bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event, bool force)
145{
146 if (!_settings_client.sound.vehicle && !force) return true;
147
148 const GRFFile *file = v->GetGRF();
149 uint16_t callback;
150
151 /* If the engine has no GRF ID associated it can't ever play any new sounds */
152 if (file == nullptr) return false;
153
154 /* Check that the vehicle type uses the sound effect callback */
155 if (!EngInfo(v->engine_type)->callback_mask.Test(VehicleCallbackMask::SoundEffect)) return false;
156
157 callback = GetVehicleCallback(CBID_VEHICLE_SOUND_EFFECT, event, 0, v->engine_type, v);
158 /* Play default sound if callback fails */
159 if (callback == CALLBACK_FAILED) return false;
160
161 callback = GetNewGRFSoundID(file, callback);
162
163 /* Play no sound, if result is invalid */
164 if (callback == INVALID_SOUND) return true;
165
166 assert(callback < GetNumSounds());
167 SndPlayVehicleFx(callback, v);
168 return true;
169}
170
177void PlayTileSound(const GRFFile *file, SoundID sound_id, TileIndex tile)
178{
179 sound_id = GetNewGRFSoundID(file, sound_id);
180 if (sound_id == INVALID_SOUND) return;
181
182 assert(sound_id < GetNumSounds());
183 SndPlayTileFx(sound_id, tile);
184}
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,...)
Output a line of debugging information.
Definition debug.h:37
Base class for engines.
Base for the NewGRF implementation.
@ SoundEffect
Vehicle uses custom sound effects.
@ CBID_VEHICLE_SOUND_EFFECT
Called to play a special sound effect.
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, std::span< int32_t > regs100)
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:60
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:125
Functions related to sound loaders.
Definition of base types and functions in a cross-platform compatible way.
static void StrMakeValid(Builder &builder, StringConsumer &consumer, StringValidationSettings settings)
Copies the valid (UTF-8) characters from consumer to the builder.
Definition string.cpp:119
Functions related to low-level strings.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:117
uint8_t grf_container_ver
NewGRF container version if the sound is from a NewGRF.
Definition sound_type.h:31
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:729
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
Base class for all vehicles.