(svn r27756) -Codechange: Add StringTab enum
[openttd.git] / src / sound.cpp
blob79dd988bfaf41a4ec6f5556a7cd13c382ebb9089
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 == NULL) 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(misc, 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 != NULL);
115 /* Check for valid sound size. */
116 if (sound->file_size == 0 || sound->file_size > ((size_t)-1) - 2) return false;
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;
124 FioSeekToFile(sound->file_slot, sound->file_offset);
125 FioReadBlock(mem, sound->file_size);
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
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]);
142 #endif
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);
148 MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16);
150 return true;
153 void InitializeSound()
155 DEBUG(misc, 1, "Loading sound effects...");
156 OpenBankFile(BaseSounds::GetUsedSet()->files->filename);
159 /* Low level sound player */
160 static void StartSound(SoundID sound_id, float pan, uint volume)
162 if (volume == 0) return;
164 SoundEntry *sound = GetSound(sound_id);
165 if (sound == NULL) return;
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;
176 /* Empty sound? */
177 if (sound->rate == 0) return;
179 MixerChannel *mc = MxAllocateChannel();
180 if (mc == NULL) return;
182 if (!SetBankSource(mc, sound)) return;
184 /* Apply the sound effect's own volume. */
185 volume = sound->volume * volume;
187 MxSetChannelVolume(mc, volume, pan);
188 MxActivateChannel(mc);
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);
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,
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,
221 void SndCopyToPool()
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;
232 * Decide 'where' (between left and right speaker) to play the sound effect.
233 * @param sound Sound effect to play
234 * @param left Left edge of virtual coordinates where the sound is produced
235 * @param right Right edge of virtual coordinates where the sound is produced
236 * @param top Top edge of virtual coordinates where the sound is produced
237 * @param bottom Bottom edge of virtual coordinates where the sound is produced
239 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
241 if (_settings_client.music.effect_vol == 0) return;
243 const Window *w;
244 FOR_ALL_WINDOWS_FROM_BACK(w) {
245 const ViewPort *vp = w->viewport;
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;
254 StartSound(
255 sound,
256 panning,
257 (_settings_client.music.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
259 return;
264 void SndPlayTileFx(SoundID sound, TileIndex tile)
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);
276 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
278 SndPlayScreenCoordFx(sound,
279 v->coord.left, v->coord.right,
280 v->coord.top, v->coord.bottom
284 void SndPlayFx(SoundID sound)
286 StartSound(sound, 0.5, _settings_client.music.effect_vol);
289 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<SoundsSet>, SoundsSet)
291 /** Names corresponding to the sound set's files */
292 static const char * const _sound_file_names[] = { "samples" };
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;
298 template <class Tbase_set>
299 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
301 return ".obs"; // OpenTTD Base Sounds
304 template <class Tbase_set>
305 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
307 if (BaseMedia<Tbase_set>::used_set != NULL) return true;
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;
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;
323 BaseMedia<Tbase_set>::used_set = best;
324 return BaseMedia<Tbase_set>::used_set != NULL;