OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

sound.cpp
Go to the documentation of this file.
1 /* $Id: sound.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2
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 */
9
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"
19
20 /* The type of set we're replacing */
21 #define SET_TYPE "sounds"
22 #include "base_media_func.h"
23
24 #include "safeguards.h"
25
26 static SoundEntry _original_sounds[ORIGINAL_SAMPLE_COUNT];
27
28 static void OpenBankFile(const char *filename)
29 {
30 memset(_original_sounds, 0, sizeof(_original_sounds));
31
32 /* If there is no sound file (nosound set), don't load anything */
33 if (filename == NULL) return;
34
35 FioOpenFile(SOUND_SLOT, filename, BASESET_DIR);
36 size_t pos = FioGetPos();
37 uint count = FioReadDword();
38
39 /* The new format has the highest bit always set */
40 bool new_format = HasBit(count, 31);
41 ClrBit(count, 31);
42 count /= 8;
43
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(misc, 6, "Incorrect number of sounds in '%s', ignoring.", filename);
50 return;
51 }
52
53 FioSeekTo(pos, SEEK_SET);
54
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();
59 }
60
61 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
62 SoundEntry *sound = &_original_sounds[i];
63 char name[255];
64
65 FioSeekTo(sound->file_offset, SEEK_SET);
66
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
71
72 /* Read riff tags */
73 for (;;) {
74 uint32 tag = FioReadDword();
75 uint32 size = FioReadDword();
76
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;
94 }
95 }
96 } else {
97 /*
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
101 */
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();
107 }
108 }
109 }
110
111 static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound)
112 {
113 assert(sound != NULL);
114
115 /* Check for valid sound size. */
116 if (sound->file_size == 0 || sound->file_size > ((size_t)-1) - 2) return false;
117
118 int8 *mem = MallocT<int8>(sound->file_size + 2);
119 /* Add two extra bytes so rate conversion can read these
120 * without reading out of its input buffer. */
121 mem[sound->file_size ] = 0;
122 mem[sound->file_size + 1] = 0;
123
124 FioSeekToFile(sound->file_slot, sound->file_offset);
125 FioReadBlock(mem, sound->file_size);
126
127 /* 16-bit PCM WAV files should be signed by default */
128 if (sound->bits_per_sample == 8) {
129 for (uint i = 0; i != sound->file_size; i++) {
130 mem[i] += -128; // Convert unsigned sound data to signed
131 }
132 }
133
134 #if TTD_ENDIAN == TTD_BIG_ENDIAN
135 if (sound->bits_per_sample == 16) {
136 uint num_samples = sound->file_size / 2;
137 int16 *samples = (int16 *)mem;
138 for (uint i = 0; i < num_samples; i++) {
139 samples[i] = BSWAP16(samples[i]);
140 }
141 }
142 #endif
143
144 assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16);
145 assert(sound->channels == 1);
146 assert(sound->file_size != 0 && sound->rate != 0);
147
148 MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16);
149
150 return true;
151 }
152
153 void InitializeSound()
154 {
155 DEBUG(misc, 1, "Loading sound effects...");
156 OpenBankFile(BaseSounds::GetUsedSet()->files->filename);
157 }
158
159 /* Low level sound player */
160 static void StartSound(SoundID sound_id, float pan, uint volume)
161 {
162 if (volume == 0) return;
163
164 SoundEntry *sound = GetSound(sound_id);
165 if (sound == NULL) return;
166
167 /* NewGRF sound that wasn't loaded yet? */
168 if (sound->rate == 0 && sound->file_slot != 0) {
169 if (!LoadNewGRFSound(sound)) {
170 /* Mark as invalid. */
171 sound->file_slot = 0;
172 return;
173 }
174 }
175
176 /* Empty sound? */
177 if (sound->rate == 0) return;
178
179 MixerChannel *mc = MxAllocateChannel();
180 if (mc == NULL) return;
181
182 if (!SetBankSource(mc, sound)) return;
183
184 /* Apply the sound effect's own volume. */
185 volume = sound->volume * volume;
186
187 MxSetChannelVolume(mc, volume, pan);
188 MxActivateChannel(mc);
189 }
190
191
192 static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87};
193 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
194
195 static const byte _sound_base_vol[] = {
196 128, 90, 128, 128, 128, 128, 128, 128,
197 128, 90, 90, 128, 128, 128, 128, 128,
198 128, 128, 128, 80, 128, 128, 128, 128,
199 128, 128, 128, 128, 128, 128, 128, 128,
200 128, 128, 90, 90, 90, 128, 90, 128,
201 128, 90, 128, 128, 128, 90, 128, 128,
202 128, 128, 128, 128, 90, 128, 128, 128,
203 128, 90, 128, 128, 128, 128, 128, 128,
204 128, 128, 90, 90, 90, 128, 128, 128,
205 90,
206 };
207
208 static const byte _sound_idx[] = {
209 2, 3, 4, 5, 6, 7, 8, 9,
210 10, 11, 12, 13, 14, 15, 16, 17,
211 18, 19, 20, 21, 22, 23, 24, 25,
212 26, 27, 28, 29, 30, 31, 32, 33,
213 34, 35, 36, 37, 38, 39, 40, 0,
214 1, 41, 42, 43, 44, 45, 46, 47,
215 48, 49, 50, 51, 52, 53, 54, 55,
216 56, 57, 58, 59, 60, 61, 62, 63,
217 64, 65, 66, 67, 68, 69, 70, 71,
218 72,
219 };
220
221 void SndCopyToPool()
222 {
223 SoundEntry *sound = AllocateSound(ORIGINAL_SAMPLE_COUNT);
224 for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
225 sound[i] = _original_sounds[_sound_idx[i]];
226 sound[i].volume = _sound_base_vol[i];
227 sound[i].priority = 0;
228 }
229 }
230
239 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
240 {
241 if (_settings_client.music.effect_vol == 0) return;
242
243 const Window *w;
244 FOR_ALL_WINDOWS_FROM_BACK(w) {
245 const ViewPort *vp = w->viewport;
246
247 if (vp != NULL &&
248 left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
249 top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
250 int screen_x = (left + right) / 2 - vp->virtual_left;
251 int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
252 float panning = (float)screen_x / width;
253
254 StartSound(
255 sound,
256 panning,
257 (_settings_client.music.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
258 );
259 return;
260 }
261 }
262 }
263
264 void SndPlayTileFx(SoundID sound, TileIndex tile)
265 {
266 /* emits sound from center of the tile */
267 int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
268 int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
269 int z = (y < 0 ? 0 : GetSlopePixelZ(x, y));
270 Point pt = RemapCoords(x, y, z);
271 y += 2 * TILE_SIZE;
272 Point pt2 = RemapCoords(x, y, GetSlopePixelZ(x, y));
273 SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
274 }
275
276 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
277 {
278 SndPlayScreenCoordFx(sound,
279 v->coord.left, v->coord.right,
280 v->coord.top, v->coord.bottom
281 );
282 }
283
284 void SndPlayFx(SoundID sound)
285 {
286 StartSound(sound, 0.5, _settings_client.music.effect_vol);
287 }
288
289 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<SoundsSet>, SoundsSet)
290
291
292 static const char * const _sound_file_names[] = { "samples" };
293
294
295 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
296 /* static */ const char * const *BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names = _sound_file_names;
297
298 template <class Tbase_set>
299 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
300 {
301 return ".obs"; // OpenTTD Base Sounds
302 }
303
304 template <class Tbase_set>
305 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
306 {
307 if (BaseMedia<Tbase_set>::used_set != NULL) return true;
308
309 const Tbase_set *best = NULL;
310 for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
311 /* Skip unusable sets */
312 if (c->GetNumMissing() != 0) continue;
313
314 if (best == NULL ||
315 (best->fallback && !c->fallback) ||
316 best->valid_files < c->valid_files ||
317 (best->valid_files == c->valid_files &&
318 (best->shortname == c->shortname && best->version < c->version))) {
319 best = c;
320 }
321 }
322
323 BaseMedia<Tbase_set>::used_set = best;
324 return BaseMedia<Tbase_set>::used_set != NULL;
325 }
326