Fix crash when setting separation mode for vehicles with no orders list.
[openttd-joker.git] / src / sound.cpp
blob1075ab73cc12f9d2e762481e81a4b15ff94e57b8
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file sound.cpp Handling of playing sounds. */
12 #include "stdafx.h"
13 #include "landscape.h"
14 #include "mixer.h"
15 #include "newgrf_sound.h"
16 #include "fios.h"
17 #include "window_gui.h"
18 #include "vehicle_base.h"
20 /* The type of set we're replacing */
21 #define SET_TYPE "sounds"
22 #include "base_media_func.h"
24 #include "safeguards.h"
26 static SoundEntry _original_sounds[ORIGINAL_SAMPLE_COUNT];
28 static void OpenBankFile(const char *filename)
30 memset(_original_sounds, 0, sizeof(_original_sounds));
32 /* If there is no sound file (nosound set), don't load anything */
33 if (filename == nullptr) return;
35 FioOpenFile(SOUND_SLOT, filename, BASESET_DIR);
36 size_t pos = FioGetPos();
37 uint count = FioReadDword();
39 /* The new format has the highest bit always set */
40 bool new_format = HasBit(count, 31);
41 ClrBit(count, 31);
42 count /= 8;
44 /* Simple check for the correct number of original sounds. */
45 if (count != ORIGINAL_SAMPLE_COUNT) {
46 /* Corrupt sample data? Just leave the allocated memory as those tell
47 * there is no sound to play (size = 0 due to calloc). Not allocating
48 * the memory disables valid NewGRFs that replace sounds. */
49 DEBUG(sound, 6, "Incorrect number of sounds in '%s', ignoring.", filename);
50 return;
53 FioSeekTo(pos, SEEK_SET);
55 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
56 _original_sounds[i].file_slot = SOUND_SLOT;
57 _original_sounds[i].file_offset = GB(FioReadDword(), 0, 31) + pos;
58 _original_sounds[i].file_size = FioReadDword();
61 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
62 SoundEntry *sound = &_original_sounds[i];
63 char name[255];
65 FioSeekTo(sound->file_offset, SEEK_SET);
67 /* Check for special case, see else case */
68 FioReadBlock(name, FioReadByte()); // Read the name of the sound
69 if (new_format || strcmp(name, "Corrupt sound") != 0) {
70 FioSeekTo(12, SEEK_CUR); // Skip past RIFF header
72 /* Read riff tags */
73 for (;;) {
74 uint32 tag = FioReadDword();
75 uint32 size = FioReadDword();
77 if (tag == ' tmf') {
78 FioReadWord(); // wFormatTag
79 sound->channels = FioReadWord(); // wChannels
80 sound->rate = FioReadDword(); // samples per second
81 if (!new_format) sound->rate = 11025; // seems like all old samples should be played at this rate.
82 FioReadDword(); // avg bytes per second
83 FioReadWord(); // alignment
84 sound->bits_per_sample = FioReadByte(); // bits per sample
85 FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
86 } else if (tag == 'atad') {
87 sound->file_size = size;
88 sound->file_slot = SOUND_SLOT;
89 sound->file_offset = FioGetPos();
90 break;
91 } else {
92 sound->file_size = 0;
93 break;
96 } else {
98 * Special case for the jackhammer sound
99 * (name in sample.cat is "Corrupt sound")
100 * It's no RIFF file, but raw PCM data
102 sound->channels = 1;
103 sound->rate = 11025;
104 sound->bits_per_sample = 8;
105 sound->file_slot = SOUND_SLOT;
106 sound->file_offset = FioGetPos();
111 static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound)
113 assert(sound != nullptr);
115 /* Check for valid sound size. */
116 if (sound->file_size == 0 || sound->file_size > ((size_t)-1) - 2) return false;
118 if (!(sound->bits_per_sample == 8 || sound->bits_per_sample == 16)) {
119 DEBUG(sound, 0, "SetBankSource: Incorrect bits_per_sample: %u", sound->bits_per_sample);
120 return false;
122 if (sound->channels != 1) {
123 DEBUG(sound, 0, "SetBankSource: Incorrect number of channels: %u", sound->channels);
124 return false;
126 if (sound->rate == 0) {
127 DEBUG(sound, 0, "SetBankSource: Incorrect rate: %u", sound->rate);
128 return false;
131 int8 *mem = MallocT<int8>(sound->file_size + 2);
132 /* Add two extra bytes so rate conversion can read these
133 * without reading out of its input buffer. */
134 mem[sound->file_size ] = 0;
135 mem[sound->file_size + 1] = 0;
137 FioSeekToFile(sound->file_slot, sound->file_offset);
138 FioReadBlock(mem, sound->file_size);
140 /* 16-bit PCM WAV files should be signed by default */
141 if (sound->bits_per_sample == 8) {
142 for (uint i = 0; i != sound->file_size; i++) {
143 mem[i] += -128; // Convert unsigned sound data to signed
147 #if TTD_ENDIAN == TTD_BIG_ENDIAN
148 if (sound->bits_per_sample == 16) {
149 uint num_samples = sound->file_size / 2;
150 int16 *samples = (int16 *)mem;
151 for (uint i = 0; i < num_samples; i++) {
152 samples[i] = BSWAP16(samples[i]);
155 #endif
157 assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16);
158 assert(sound->channels == 1);
159 assert(sound->file_size != 0 && sound->rate != 0);
161 MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16);
163 return true;
166 void InitializeSound()
168 DEBUG(sound, 1, "Loading sound effects...");
169 OpenBankFile(BaseSounds::GetUsedSet()->files->filename);
172 /* Low level sound player */
173 static void StartSound(SoundID sound_id, float pan, uint volume)
175 if (volume == 0) return;
177 SoundEntry *sound = GetSound(sound_id);
178 if (sound == nullptr) return;
180 /* NewGRF sound that wasn't loaded yet? */
181 if (sound->rate == 0 && sound->file_slot != 0) {
182 if (!LoadNewGRFSound(sound)) {
183 /* Mark as invalid. */
184 sound->file_slot = 0;
185 return;
189 /* Empty sound? */
190 if (sound->rate == 0) return;
192 MixerChannel *mc = MxAllocateChannel();
193 if (mc == nullptr) return;
195 if (!SetBankSource(mc, sound)) return;
197 /* Apply the sound effect's own volume. */
198 volume = sound->volume * volume;
200 MxSetChannelVolume(mc, volume, pan);
201 MxActivateChannel(mc);
205 static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87, 10, 1, 1, 1};
206 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
208 static const byte _sound_base_vol[] = {
209 128, 90, 128, 128, 128, 128, 128, 128,
210 128, 90, 90, 128, 128, 128, 128, 128,
211 128, 128, 128, 80, 128, 128, 128, 128,
212 128, 128, 128, 128, 128, 128, 128, 128,
213 128, 128, 90, 90, 90, 128, 90, 128,
214 128, 90, 128, 128, 128, 90, 128, 128,
215 128, 128, 128, 128, 90, 128, 128, 128,
216 128, 90, 128, 128, 128, 128, 128, 128,
217 128, 128, 90, 90, 90, 128, 128, 128,
221 static const byte _sound_idx[] = {
222 2, 3, 4, 5, 6, 7, 8, 9,
223 10, 11, 12, 13, 14, 15, 16, 17,
224 18, 19, 20, 21, 22, 23, 24, 25,
225 26, 27, 28, 29, 30, 31, 32, 33,
226 34, 35, 36, 37, 38, 39, 40, 0,
227 1, 41, 42, 43, 44, 45, 46, 47,
228 48, 49, 50, 51, 52, 53, 54, 55,
229 56, 57, 58, 59, 60, 61, 62, 63,
230 64, 65, 66, 67, 68, 69, 70, 71,
234 void SndCopyToPool()
236 SoundEntry *sound = AllocateSound(ORIGINAL_SAMPLE_COUNT);
237 for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
238 sound[i] = _original_sounds[_sound_idx[i]];
239 sound[i].volume = _sound_base_vol[i];
240 sound[i].priority = 0;
245 * Decide 'where' (between left and right speaker) to play the sound effect.
246 * @param sound Sound effect to play
247 * @param left Left edge of virtual coordinates where the sound is produced
248 * @param right Right edge of virtual coordinates where the sound is produced
249 * @param top Top edge of virtual coordinates where the sound is produced
250 * @param bottom Bottom edge of virtual coordinates where the sound is produced
252 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
254 if (_settings_client.music.effect_vol == 0) return;
256 const Window *w;
257 FOR_ALL_WINDOWS_FROM_BACK(w) {
258 const ViewPort *vp = w->viewport;
260 if (vp != nullptr &&
261 left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
262 top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
263 int screen_x = (left + right) / 2 - vp->virtual_left;
264 int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
265 float panning = (float)screen_x / width;
267 StartSound(
268 sound,
269 panning,
270 (_settings_client.music.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
272 return;
277 void SndPlayTileFx(SoundID sound, TileIndex tile)
279 /* emits sound from center of the tile */
280 int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
281 int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
282 int z = (y < 0 ? 0 : GetSlopePixelZ(x, y));
283 Point pt = RemapCoords(x, y, z);
284 y += 2 * TILE_SIZE;
285 Point pt2 = RemapCoords(x, y, GetSlopePixelZ(x, y));
286 SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
289 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
291 SndPlayScreenCoordFx(sound,
292 v->coord.left, v->coord.right,
293 v->coord.top, v->coord.bottom
297 void SndPlayFx(SoundID sound)
299 StartSound(sound, 0.5, _settings_client.music.effect_vol);
302 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<SoundsSet>, SoundsSet)
304 /** Names corresponding to the sound set's files */
305 static const char * const _sound_file_names[] = { "samples" };
308 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
309 /* static */ const char * const *BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names = _sound_file_names;
311 template <class Tbase_set>
312 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
314 return ".obs"; // OpenTTD Base Sounds
317 template <class Tbase_set>
318 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
320 if (BaseMedia<Tbase_set>::used_set != nullptr) return true;
322 const Tbase_set *best = nullptr;
323 for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != nullptr; c = c->next) {
324 /* Skip unusable sets */
325 if (c->GetNumMissing() != 0) continue;
327 if (best == nullptr ||
328 (best->fallback && !c->fallback) ||
329 best->valid_files < c->valid_files ||
330 (best->valid_files == c->valid_files &&
331 (best->shortname == c->shortname && best->version < c->version))) {
332 best = c;
336 BaseMedia<Tbase_set>::used_set = best;
337 return BaseMedia<Tbase_set>::used_set != nullptr;