OpenTTD Source: src/sound.cpp Source File

OpenTTD Source 1.11.0-RC1

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 "fios.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 {
28 memset(_original_sounds, 0, sizeof(_original_sounds));
29
30 /* If there is no sound file (nosound set), don't load anything */
31 if (filename == nullptr) return;
32
33 FioOpenFile(SOUND_SLOT, filename, BASESET_DIR);
34 size_t pos = FioGetPos();
35 uint count = FioReadDword();
36
37 /* The new format has the highest bit always set */
38 bool new_format = HasBit(count, 31);
39 ClrBit(count, 31);
40 count /= 8;
41
42 /* Simple check for the correct number of original sounds. */
43 if (count != ORIGINAL_SAMPLE_COUNT) {
44 /* Corrupt sample data? Just leave the allocated memory as those tell
45 * there is no sound to play (size = 0 due to calloc). Not allocating
46 * the memory disables valid NewGRFs that replace sounds. */
47 DEBUG(misc, 6, "Incorrect number of sounds in '%s', ignoring.", filename);
48 return;
49 }
50
51 FioSeekTo(pos, SEEK_SET);
52
53 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
54 _original_sounds[i].file_slot = SOUND_SLOT;
55 _original_sounds[i].file_offset = GB(FioReadDword(), 0, 31) + pos;
56 _original_sounds[i].file_size = FioReadDword();
57 }
58
59 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
60 SoundEntry *sound = &_original_sounds[i];
61 char name[255];
62
63 FioSeekTo(sound->file_offset, SEEK_SET);
64
65 /* Check for special case, see else case */
66 FioReadBlock(name, FioReadByte()); // Read the name of the sound
67 if (new_format || strcmp(name, "Corrupt sound") != 0) {
68 FioSeekTo(12, SEEK_CUR); // Skip past RIFF header
69
70 /* Read riff tags */
71 for (;;) {
72 uint32 tag = FioReadDword();
73 uint32 size = FioReadDword();
74
75 if (tag == ' tmf') {
76 FioReadWord(); // wFormatTag
77 sound->channels = FioReadWord(); // wChannels
78 sound->rate = FioReadDword(); // samples per second
79 if (!new_format) sound->rate = 11025; // seems like all old samples should be played at this rate.
80 FioReadDword(); // avg bytes per second
81 FioReadWord(); // alignment
82 sound->bits_per_sample = FioReadByte(); // bits per sample
83 FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
84 } else if (tag == 'atad') {
85 sound->file_size = size;
86 sound->file_slot = SOUND_SLOT;
87 sound->file_offset = FioGetPos();
88 break;
89 } else {
90 sound->file_size = 0;
91 break;
92 }
93 }
94 } else {
95 /*
96 * Special case for the jackhammer sound
97 * (name in sample.cat is "Corrupt sound")
98 * It's no RIFF file, but raw PCM data
99 */
100 sound->channels = 1;
101 sound->rate = 11025;
102 sound->bits_per_sample = 8;
103 sound->file_slot = SOUND_SLOT;
104 sound->file_offset = FioGetPos();
105 }
106 }
107 }
108
109 static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound)
110 {
111 assert(sound != nullptr);
112
113 /* Check for valid sound size. */
114 if (sound->file_size == 0 || sound->file_size > ((size_t)-1) - 2) return false;
115
116 int8 *mem = MallocT<int8>(sound->file_size + 2);
117 /* Add two extra bytes so rate conversion can read these
118 * without reading out of its input buffer. */
119 mem[sound->file_size ] = 0;
120 mem[sound->file_size + 1] = 0;
121
122 FioSeekToFile(sound->file_slot, sound->file_offset);
123 FioReadBlock(mem, sound->file_size);
124
125 /* 16-bit PCM WAV files should be signed by default */
126 if (sound->bits_per_sample == 8) {
127 for (uint i = 0; i != sound->file_size; i++) {
128 mem[i] += -128; // Convert unsigned sound data to signed
129 }
130 }
131
132 #if TTD_ENDIAN == TTD_BIG_ENDIAN
133 if (sound->bits_per_sample == 16) {
134 uint num_samples = sound->file_size / 2;
135 int16 *samples = (int16 *)mem;
136 for (uint i = 0; i < num_samples; i++) {
137 samples[i] = BSWAP16(samples[i]);
138 }
139 }
140 #endif
141
142 assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16);
143 assert(sound->channels == 1);
144 assert(sound->file_size != 0 && sound->rate != 0);
145
146 MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16);
147
148 return true;
149 }
150
151 void InitializeSound()
152 {
153 DEBUG(misc, 1, "Loading sound effects...");
154 OpenBankFile(BaseSounds::GetUsedSet()->files->filename);
155 }
156
157 /* Low level sound player */
158 static void StartSound(SoundID sound_id, float pan, uint volume)
159 {
160 if (volume == 0) return;
161
162 SoundEntry *sound = GetSound(sound_id);
163 if (sound == nullptr) return;
164
165 /* NewGRF sound that wasn't loaded yet? */
166 if (sound->rate == 0 && sound->file_slot != 0) {
167 if (!LoadNewGRFSound(sound)) {
168 /* Mark as invalid. */
169 sound->file_slot = 0;
170 return;
171 }
172 }
173
174 /* Empty sound? */
175 if (sound->rate == 0) return;
176
177 MixerChannel *mc = MxAllocateChannel();
178 if (mc == nullptr) return;
179
180 if (!SetBankSource(mc, sound)) return;
181
182 /* Apply the sound effect's own volume. */
183 volume = sound->volume * volume;
184
185 MxSetChannelVolume(mc, volume, pan);
186 MxActivateChannel(mc);
187 }
188
189
190 static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87};
191 static_assert(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
192
193 static const byte _sound_base_vol[] = {
194 128, 90, 128, 128, 128, 128, 128, 128,
195 128, 90, 90, 128, 128, 128, 128, 128,
196 128, 128, 128, 80, 128, 128, 128, 128,
197 128, 128, 128, 128, 128, 128, 128, 128,
198 128, 128, 90, 90, 90, 128, 90, 128,
199 128, 90, 128, 128, 128, 90, 128, 128,
200 128, 128, 128, 128, 90, 128, 128, 128,
201 128, 90, 128, 128, 128, 128, 128, 128,
202 128, 128, 90, 90, 90, 128, 128, 128,
203 90,
204 };
205
206 static const byte _sound_idx[] = {
207 2, 3, 4, 5, 6, 7, 8, 9,
208 10, 11, 12, 13, 14, 15, 16, 17,
209 18, 19, 20, 21, 22, 23, 24, 25,
210 26, 27, 28, 29, 30, 31, 32, 33,
211 34, 35, 36, 37, 38, 39, 40, 0,
212 1, 41, 42, 43, 44, 45, 46, 47,
213 48, 49, 50, 51, 52, 53, 54, 55,
214 56, 57, 58, 59, 60, 61, 62, 63,
215 64, 65, 66, 67, 68, 69, 70, 71,
216 72,
217 };
218
219 void SndCopyToPool()
220 {
221 SoundEntry *sound = AllocateSound(ORIGINAL_SAMPLE_COUNT);
222 for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
223 sound[i] = _original_sounds[_sound_idx[i]];
224 sound[i].volume = _sound_base_vol[i];
225 sound[i].priority = 0;
226 }
227 }
228
237 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
238 {
239 if (_settings_client.music.effect_vol == 0) return;
240
241 const Window *w;
242 FOR_ALL_WINDOWS_FROM_BACK(w) {
243 const Viewport *vp = w->viewport;
244
245 if (vp != nullptr &&
246 left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
247 top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
248 int screen_x = (left + right) / 2 - vp->virtual_left;
249 int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
250 float panning = (float)screen_x / width;
251
252 StartSound(
253 sound,
254 panning,
255 (_settings_client.music.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
256 );
257 return;
258 }
259 }
260 }
261
262 void SndPlayTileFx(SoundID sound, TileIndex tile)
263 {
264 /* emits sound from center of the tile */
265 int x = std::min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
266 int y = std::min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
267 int z = (y < 0 ? 0 : GetSlopePixelZ(x, y));
268 Point pt = RemapCoords(x, y, z);
269 y += 2 * TILE_SIZE;
270 Point pt2 = RemapCoords(x, y, GetSlopePixelZ(x, y));
271 SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
272 }
273
274 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
275 {
276 SndPlayScreenCoordFx(sound,
277 v->coord.left, v->coord.right,
278 v->coord.top, v->coord.bottom
279 );
280 }
281
282 void SndPlayFx(SoundID sound)
283 {
284 StartSound(sound, 0.5, _settings_client.music.effect_vol);
285 }
286
287 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<SoundsSet>, SoundsSet)
288
289
290 static const char * const _sound_file_names[] = { "samples" };
291
292
293 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
294 /* static */ const char * const *BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names = _sound_file_names;
295
296 template <class Tbase_set>
297 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
298 {
299 return ".obs"; // OpenTTD Base Sounds
300 }
301
302 template <class Tbase_set>
303 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
304 {
305 if (BaseMedia<Tbase_set>::used_set != nullptr) return true;
306
307 const Tbase_set *best = nullptr;
308 for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != nullptr; c = c->next) {
309 /* Skip unusable sets */
310 if (c->GetNumMissing() != 0) continue;
311
312 if (best == nullptr ||
313 (best->fallback && !c->fallback) ||
314 best->valid_files < c->valid_files ||
315 (best->valid_files == c->valid_files &&
316 (best->shortname == c->shortname && best->version < c->version))) {
317 best = c;
318 }
319 }
320
321 BaseMedia<Tbase_set>::used_set = best;
322 return BaseMedia<Tbase_set>::used_set != nullptr;
323 }
324
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:78
base_media_func.h
BaseMedia::DetermineBestSet
static bool DetermineBestSet()
Determine the graphics pack that has to be used.
Definition: gfxinit.cpp:426
FioReadBlock
void FioReadBlock(void *ptr, size_t size)
Read a block.
Definition: fileio.cpp:161
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
FioReadWord
uint16 FioReadWord()
Read a word (16 bits) from the file (in low endian format).
Definition: fileio.cpp:140
FioOpenFile
void FioOpenFile(int slot, const std::string &filename, Subdirectory subdir)
Open a slotted file.
Definition: fileio.cpp:196
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
Window::viewport
ViewportData * viewport
Pointer to viewport data, if present.
Definition: window_gui.h:326
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:79
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:222
Viewport::virtual_top
int virtual_top
Virtual top coordinate.
Definition: viewport_type.h:29
fios.h
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:395
FioReadDword
uint32 FioReadDword()
Read a double word (32 bits) from the file (in low endian format).
Definition: fileio.cpp:150
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
DEBUG
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:35
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
FioSeekTo
void FioSeekTo(size_t pos, int mode)
Seek in the current file.
Definition: fileio.cpp:79
landscape.h
FioGetPos
size_t FioGetPos()
Get position in the current file.
Definition: fileio.cpp:59
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:237
FioReadByte
byte FioReadByte()
Read a byte from the file.
Definition: fileio.cpp:107
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:18
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:209
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
Vehicle::coord
Rect coord
NOSAVE: Graphical bounding box of the vehicle, i.e. what to redraw on moves.
Definition: vehicle_base.h:255
lengthof
#define lengthof(x)
Return the length of an fixed size array.
Definition: stdafx.h:367
MusicSettings::effect_vol
byte effect_vol
The requested effects volume.
Definition: settings_type.h:208
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:290
SOUND_SLOT
@ SOUND_SLOT
Slot for the sound.
Definition: fios.h:95
Window
Data structure for an opened window.
Definition: window_gui.h:276
FioSeekToFile
void FioSeekToFile(uint8 slot, size_t pos)
Switch to a different file and seek to a position.
Definition: fileio.cpp:94
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:450
ClientSettings::music
MusicSettings music
settings related to music/sound
Definition: settings_type.h:581
mixer.h