OpenTTD
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 
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 {
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 
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>
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 
324  return BaseMedia<Tbase_set>::used_set != NULL;
325 }
326