OpenTTD Source: src/sound.cpp Source File

OpenTTD Source 12.0-beta1

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 "landscape.h"
12 #include "mixer.h"
13 #include "newgrf_sound.h"
14 #include "random_access_file_type.h"
15 #include "window_gui.h"
16 #include "vehicle_base.h"
17
18 /* The type of set we're replacing */
19 #define SET_TYPE "sounds"
20 #include "base_media_func.h"
21
22 #include "safeguards.h"
23
24 static SoundEntry _original_sounds[ORIGINAL_SAMPLE_COUNT];
25
26 static void OpenBankFile(const char *filename)
27 {
32 static std::unique_ptr<RandomAccessFile> original_sound_file;
33
34 memset(_original_sounds, 0, sizeof(_original_sounds));
35
36 /* If there is no sound file (nosound set), don't load anything */
37 if (filename == nullptr) return;
38
39 original_sound_file.reset(new RandomAccessFile(filename, BASESET_DIR));
40 size_t pos = original_sound_file->GetPos();
41 uint count = original_sound_file->ReadDword();
42
43 /* The new format has the highest bit always set */
44 bool new_format = HasBit(count, 31);
45 ClrBit(count, 31);
46 count /= 8;
47
48 /* Simple check for the correct number of original sounds. */
49 if (count != ORIGINAL_SAMPLE_COUNT) {
50 /* Corrupt sample data? Just leave the allocated memory as those tell
51 * there is no sound to play (size = 0 due to calloc). Not allocating
52 * the memory disables valid NewGRFs that replace sounds. */
53 Debug(misc, 6, "Incorrect number of sounds in '{}', ignoring.", filename);
54 return;
55 }
56
57 original_sound_file->SeekTo(pos, SEEK_SET);
58
59 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
60 _original_sounds[i].file = original_sound_file.get();
61 _original_sounds[i].file_offset = GB(original_sound_file->ReadDword(), 0, 31) + pos;
62 _original_sounds[i].file_size = original_sound_file->ReadDword();
63 }
64
65 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
66 SoundEntry *sound = &_original_sounds[i];
67 char name[255];
68
69 original_sound_file->SeekTo(sound->file_offset, SEEK_SET);
70
71 /* Check for special case, see else case */
72 original_sound_file->ReadBlock(name, original_sound_file->ReadByte()); // Read the name of the sound
73 if (new_format || strcmp(name, "Corrupt sound") != 0) {
74 original_sound_file->SeekTo(12, SEEK_CUR); // Skip past RIFF header
75
76 /* Read riff tags */
77 for (;;) {
78 uint32 tag = original_sound_file->ReadDword();
79 uint32 size = original_sound_file->ReadDword();
80
81 if (tag == ' tmf') {
82 original_sound_file->ReadWord(); // wFormatTag
83 sound->channels = original_sound_file->ReadWord(); // wChannels
84 sound->rate = original_sound_file->ReadDword(); // samples per second
85 if (!new_format) sound->rate = 11025; // seems like all old samples should be played at this rate.
86 original_sound_file->ReadDword(); // avg bytes per second
87 original_sound_file->ReadWord(); // alignment
88 sound->bits_per_sample = original_sound_file->ReadByte(); // bits per sample
89 original_sound_file->SeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
90 } else if (tag == 'atad') {
91 sound->file_size = size;
92 sound->file = original_sound_file.get();
93 sound->file_offset = original_sound_file->GetPos();
94 break;
95 } else {
96 sound->file_size = 0;
97 break;
98 }
99 }
100 } else {
101 /*
102 * Special case for the jackhammer sound
103 * (name in sample.cat is "Corrupt sound")
104 * It's no RIFF file, but raw PCM data
105 */
106 sound->channels = 1;
107 sound->rate = 11025;
108 sound->bits_per_sample = 8;
109 sound->file = original_sound_file.get();
110 sound->file_offset = original_sound_file->GetPos();
111 }
112 }
113 }
114
115 static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound)
116 {
117 assert(sound != nullptr);
118
119 /* Check for valid sound size. */
120 if (sound->file_size == 0 || sound->file_size > ((size_t)-1) - 2) return false;
121
122 int8 *mem = MallocT<int8>(sound->file_size + 2);
123 /* Add two extra bytes so rate conversion can read these
124 * without reading out of its input buffer. */
125 mem[sound->file_size ] = 0;
126 mem[sound->file_size + 1] = 0;
127
128 RandomAccessFile *file = sound->file;
129 file->SeekTo(sound->file_offset, SEEK_SET);
130 file->ReadBlock(mem, sound->file_size);
131
132 /* 16-bit PCM WAV files should be signed by default */
133 if (sound->bits_per_sample == 8) {
134 for (uint i = 0; i != sound->file_size; i++) {
135 mem[i] += -128; // Convert unsigned sound data to signed
136 }
137 }
138
139 #if TTD_ENDIAN == TTD_BIG_ENDIAN
140 if (sound->bits_per_sample == 16) {
141 uint num_samples = sound->file_size / 2;
142 int16 *samples = (int16 *)mem;
143 for (uint i = 0; i < num_samples; i++) {
144 samples[i] = BSWAP16(samples[i]);
145 }
146 }
147 #endif
148
149 assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16);
150 assert(sound->channels == 1);
151 assert(sound->file_size != 0 && sound->rate != 0);
152
153 MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16);
154
155 return true;
156 }
157
158 void InitializeSound()
159 {
160 Debug(misc, 1, "Loading sound effects...");
161 OpenBankFile(BaseSounds::GetUsedSet()->files->filename);
162 }
163
164 /* Low level sound player */
165 static void StartSound(SoundID sound_id, float pan, uint volume)
166 {
167 if (volume == 0) return;
168
169 SoundEntry *sound = GetSound(sound_id);
170 if (sound == nullptr) return;
171
172 /* NewGRF sound that wasn't loaded yet? */
173 if (sound->rate == 0 && sound->file != nullptr) {
174 if (!LoadNewGRFSound(sound)) {
175 /* Mark as invalid. */
176 sound->file = nullptr;
177 return;
178 }
179 }
180
181 /* Empty sound? */
182 if (sound->rate == 0) return;
183
184 MixerChannel *mc = MxAllocateChannel();
185 if (mc == nullptr) return;
186
187 if (!SetBankSource(mc, sound)) return;
188
189 /* Apply the sound effect's own volume. */
190 volume = sound->volume * volume;
191
192 MxSetChannelVolume(mc, volume, pan);
193 MxActivateChannel(mc);
194 }
195
196
197 static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87};
198 static_assert(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
199
200 static const byte _sound_base_vol[] = {
201 128, 90, 128, 128, 128, 128, 128, 128,
202 128, 90, 90, 128, 128, 128, 128, 128,
203 128, 128, 128, 80, 128, 128, 128, 128,
204 128, 128, 128, 128, 128, 128, 128, 128,
205 128, 128, 90, 90, 90, 128, 90, 128,
206 128, 90, 128, 128, 128, 90, 128, 128,
207 128, 128, 128, 128, 90, 128, 128, 128,
208 128, 90, 128, 128, 128, 128, 128, 128,
209 128, 128, 90, 90, 90, 128, 128, 128,
210 90,
211 };
212
213 static const byte _sound_idx[] = {
214 2, 3, 4, 5, 6, 7, 8, 9,
215 10, 11, 12, 13, 14, 15, 16, 17,
216 18, 19, 20, 21, 22, 23, 24, 25,
217 26, 27, 28, 29, 30, 31, 32, 33,
218 34, 35, 36, 37, 38, 39, 40, 0,
219 1, 41, 42, 43, 44, 45, 46, 47,
220 48, 49, 50, 51, 52, 53, 54, 55,
221 56, 57, 58, 59, 60, 61, 62, 63,
222 64, 65, 66, 67, 68, 69, 70, 71,
223 72,
224 };
225
226 void SndCopyToPool()
227 {
228 SoundEntry *sound = AllocateSound(ORIGINAL_SAMPLE_COUNT);
229 for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
230 sound[i] = _original_sounds[_sound_idx[i]];
231 sound[i].volume = _sound_base_vol[i];
232 sound[i].priority = 0;
233 }
234 }
235
244 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
245 {
246 if (_settings_client.music.effect_vol == 0) return;
247
248 /* Iterate from back, so that main viewport is checked first */
249 for (const Window *w : Window::IterateFromBack()) {
250 const Viewport *vp = w->viewport;
251
252 if (vp != nullptr &&
253 left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
254 top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
255 int screen_x = (left + right) / 2 - vp->virtual_left;
256 int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
257 float panning = (float)screen_x / width;
258
259 StartSound(
260 sound,
261 panning,
262 _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]
263 );
264 return;
265 }
266 }
267 }
268
269 void SndPlayTileFx(SoundID sound, TileIndex tile)
270 {
271 /* emits sound from center of the tile */
272 int x = std::min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
273 int y = std::min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
274 int z = (y < 0 ? 0 : GetSlopePixelZ(x, y));
275 Point pt = RemapCoords(x, y, z);
276 y += 2 * TILE_SIZE;
277 Point pt2 = RemapCoords(x, y, GetSlopePixelZ(x, y));
278 SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
279 }
280
281 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
282 {
283 SndPlayScreenCoordFx(sound,
284 v->coord.left, v->coord.right,
285 v->coord.top, v->coord.bottom
286 );
287 }
288
289 void SndPlayFx(SoundID sound)
290 {
291 StartSound(sound, 0.5, UINT8_MAX);
292 }
293
294 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<SoundsSet>, SoundsSet)
295
296
297 static const char * const _sound_file_names[] = { "samples" };
298
299
300 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
301 /* static */ const char * const *BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names = _sound_file_names;
302
303 template <class Tbase_set>
304 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
305 {
306 return ".obs"; // OpenTTD Base Sounds
307 }
308
309 template <class Tbase_set>
310 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
311 {
312 if (BaseMedia<Tbase_set>::used_set != nullptr) return true;
313
314 const Tbase_set *best = nullptr;
315 for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != nullptr; c = c->next) {
316 /* Skip unusable sets */
317 if (c->GetNumMissing() != 0) continue;
318
319 if (best == nullptr ||
320 (best->fallback && !c->fallback) ||
321 best->valid_files < c->valid_files ||
322 (best->valid_files == c->valid_files &&
323 (best->shortname == c->shortname && best->version < c->version))) {
324 best = c;
325 }
326 }
327
328 BaseMedia<Tbase_set>::used_set = best;
329 return BaseMedia<Tbase_set>::used_set != nullptr;
330 }
331
AllocateSound
SoundEntry * AllocateSound(uint num)
Allocate sound slots.
Definition: newgrf_sound.cpp:31
TileIndex
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:83
base_media_func.h
BaseMedia::DetermineBestSet
static bool DetermineBestSet()
Determine the graphics pack that has to be used.
Definition: gfxinit.cpp:440
SoundsSet
All data of a sounds set.
Definition: base_media_base.h:263
GB
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
Definition: bitmath_func.hpp:32
BASESET_DIR
@ BASESET_DIR
Subdirectory for all base data (base sets, intro game)
Definition: fileio_type.h:116
RemapCoords
static Point RemapCoords(int x, int y, int z)
Map 3D world or tile coordinate to equivalent 2D coordinate as used in the viewports and smallmap.
Definition: landscape.h:82
ZOOM_LVL_COUNT
@ ZOOM_LVL_COUNT
Number of zoom levels.
Definition: zoom_type.h:32
HasBit
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
Definition: bitmath_func.hpp:103
ClrBit
static T ClrBit(T &x, const uint8 y)
Clears a bit in a variable.
Definition: bitmath_func.hpp:151
vehicle_base.h
TILE_SIZE
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:13
_settings_client
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:52
TileY
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:215
Vehicle
Vehicle data structure.
Definition: vehicle_base.h:221
Viewport::virtual_top
int virtual_top
Virtual top coordinate.
Definition: viewport_type.h:29
RandomAccessFile::ReadBlock
void ReadBlock(void *ptr, size_t size)
Read a block.
Definition: random_access_file.cpp:138
ZOOM_LVL_BEGIN
@ ZOOM_LVL_BEGIN
Begin for iteration.
Definition: zoom_type.h:23
TileX
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:205
BSWAP16
static uint16 BSWAP16(uint16 x)
Perform a 16 bits endianness bitswap on x.
Definition: bitmath_func.hpp:405
random_access_file_type.h
window_gui.h
Viewport
Data structure for viewport, display of a part of the world.
Definition: viewport_type.h:22
LoadNewGRFSound
bool LoadNewGRFSound(SoundEntry *sound)
Extract meta data from a NewGRF sound.
Definition: newgrf_sound.cpp:66
Viewport::virtual_left
int virtual_left
Virtual left coordinate.
Definition: viewport_type.h:28
BaseMedia< SoundsSet >
safeguards.h
Viewport::virtual_width
int virtual_width
width << zoom
Definition: viewport_type.h:30
Point
Coordinates of a point in 2D.
Definition: geometry_type.hpp:21
SoundEntry
Definition: sound_type.h:13
stdafx.h
landscape.h
Window::AllWindows
Iterable ensemble of all valid Windows.
Definition: window_gui.h:859
INSTANTIATE_BASE_MEDIA_METHODS
#define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type)
Force instantiation of methods so we don't get linker errors.
Definition: base_media_func.h:377
SndPlayScreenCoordFx
static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
Decide 'where' (between left and right speaker) to play the sound effect.
Definition: sound.cpp:244
newgrf_sound.h
MapMaxY
static uint MapMaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition: map_func.h:111
MixerChannel
Definition: mixer.cpp:20
BaseSet
Information about a single base set.
Definition: base_media_base.h:49
MxSetChannelVolume
void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
Set volume and pan parameters for a sound.
Definition: mixer.cpp:223
ORIGINAL_SAMPLE_COUNT
static const uint ORIGINAL_SAMPLE_COUNT
The number of sounds in the original sample.cat.
Definition: sound_type.h:116
MapMaxX
static uint MapMaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition: map_func.h:102
OpenBankFile
static void OpenBankFile(const char *filename)
Definition: sound.cpp:26
Vehicle::coord
Rect coord
NOSAVE: Graphical bounding box of the vehicle, i.e. what to redraw on moves.
Definition: vehicle_base.h:257
RandomAccessFile::SeekTo
void SeekTo(size_t pos, int mode)
Seek in the current file.
Definition: random_access_file.cpp:83
Debug
#define Debug(name, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
lengthof
#define lengthof(x)
Return the length of an fixed size array.
Definition: stdafx.h:378
MusicSettings::effect_vol
byte effect_vol
The requested effects volume.
Definition: settings_type.h:219
Viewport::zoom
ZoomLevel zoom
The zoom level of the viewport.
Definition: viewport_type.h:33
_sound_file_names
static const char *const _sound_file_names[]
Names corresponding to the sound set's files.
Definition: sound.cpp:297
Window
Data structure for an opened window.
Definition: window_gui.h:279
BaseMedia< SoundsSet >::GetUsedSet
static const SoundsSet * GetUsedSet()
Return the used set.
Definition: base_media_func.h:357
Viewport::virtual_height
int virtual_height
height << zoom
Definition: viewport_type.h:31
BaseMedia::GetExtension
static const char * GetExtension()
Get the extension that is used to identify this set.
Definition: gfxinit.cpp:464
ClientSettings::music
MusicSettings music
settings related to music/sound
Definition: settings_type.h:597
mixer.h
RandomAccessFile
A file from which bytes, words and double words are read in (potentially) a random order.
Definition: random_access_file_type.h:23