Add non-animated SSSE3 blitter
[openttd/fttd.git] / src / newgrf_sound.cpp
blobc7739558fd458f19328ea649c522fda719003dff
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 newgrf_sound.cpp Handling NewGRF provided sounds. */
12 #include "stdafx.h"
13 #include "engine_base.h"
14 #include "newgrf.h"
15 #include "newgrf_engine.h"
16 #include "newgrf_sound.h"
17 #include "vehicle_base.h"
18 #include "sound_func.h"
19 #include "fileio_func.h"
20 #include "debug.h"
21 #include "settings_type.h"
23 static SmallVector<SoundEntry, 8> _sounds;
26 /**
27 * Allocate sound slots.
28 * @param num Number of slots to allocate.
29 * @return First allocated slot.
31 SoundEntry *AllocateSound(uint num)
33 SoundEntry *sound = _sounds.Append(num);
34 MemSetT(sound, 0, num);
35 return sound;
39 void InitializeSoundPool()
41 _sounds.Clear();
43 /* Copy original sound data to the pool */
44 SndCopyToPool();
48 SoundEntry *GetSound(SoundID index)
50 if (index >= _sounds.Length()) return NULL;
51 return &_sounds[index];
55 uint GetNumSounds()
57 return _sounds.Length();
61 /**
62 * Extract meta data from a NewGRF sound.
63 * @param sound Sound to load.
64 * @return True if a valid sound was loaded.
66 bool LoadNewGRFSound(SoundEntry *sound)
68 if (sound->file_offset == SIZE_MAX || sound->file_slot == 0) return false;
70 FioSeekToFile(sound->file_slot, sound->file_offset);
72 /* Skip ID for container version >= 2 as we only look at the first
73 * entry and ignore any further entries with the same ID. */
74 if (sound->grf_container_ver >= 2) FioReadDword();
76 /* Format: <num> <FF> <FF> <name_len> <name> '\0' <data> */
78 uint32 num = sound->grf_container_ver >= 2 ? FioReadDword() : FioReadWord();
79 if (FioReadByte() != 0xFF) return false;
80 if (FioReadByte() != 0xFF) return false;
82 uint8 name_len = FioReadByte();
83 char *name = AllocaM(char, name_len + 1);
84 FioReadBlock(name, name_len + 1);
86 /* Test string termination */
87 if (name[name_len] != 0) {
88 DEBUG(grf, 2, "LoadNewGRFSound [%s]: Name not properly terminated", FioGetFilename(sound->file_slot));
89 return false;
92 DEBUG(grf, 2, "LoadNewGRFSound [%s]: Sound name '%s'...", FioGetFilename(sound->file_slot), name);
94 if (FioReadDword() != BSWAP32('RIFF')) {
95 DEBUG(grf, 1, "LoadNewGRFSound [%s]: Missing RIFF header", FioGetFilename(sound->file_slot));
96 return false;
99 uint32 total_size = FioReadDword();
100 uint header_size = 11;
101 if (sound->grf_container_ver >= 2) header_size++; // The first FF in the sprite is only counted for container version >= 2.
102 if (total_size + name_len + header_size > num) {
103 DEBUG(grf, 1, "LoadNewGRFSound [%s]: RIFF was truncated", FioGetFilename(sound->file_slot));
104 return false;
107 if (FioReadDword() != BSWAP32('WAVE')) {
108 DEBUG(grf, 1, "LoadNewGRFSound [%s]: Invalid RIFF type", FioGetFilename(sound->file_slot));
109 return false;
112 while (total_size >= 8) {
113 uint32 tag = FioReadDword();
114 uint32 size = FioReadDword();
115 total_size -= 8;
116 if (total_size < size) {
117 DEBUG(grf, 1, "LoadNewGRFSound [%s]: Invalid RIFF", FioGetFilename(sound->file_slot));
118 return false;
120 total_size -= size;
122 switch (tag) {
123 case ' tmf': // 'fmt '
124 /* Audio format, must be 1 (PCM) */
125 if (size < 16 || FioReadWord() != 1) {
126 DEBUG(grf, 1, "LoadGRFSound [%s]: Invalid audio format", FioGetFilename(sound->file_slot));
127 return false;
129 sound->channels = FioReadWord();
130 sound->rate = FioReadDword();
131 FioReadDword();
132 FioReadWord();
133 sound->bits_per_sample = FioReadWord();
135 /* The rest will be skipped */
136 size -= 16;
137 break;
139 case 'atad': // 'data'
140 sound->file_size = size;
141 sound->file_offset = FioGetPos();
143 DEBUG(grf, 2, "LoadNewGRFSound [%s]: channels %u, sample rate %u, bits per sample %u, length %u", FioGetFilename(sound->file_slot), sound->channels, sound->rate, sound->bits_per_sample, size);
144 return true; // the fmt chunk has to appear before data, so we are finished
146 default:
147 /* Skip unknown chunks */
148 break;
151 /* Skip rest of chunk */
152 if (size > 0) FioSkipBytes(size);
155 DEBUG(grf, 1, "LoadNewGRFSound [%s]: RIFF does not contain any sound data", FioGetFilename(sound->file_slot));
157 /* Clear everything that was read */
158 MemSetT(sound, 0);
159 return false;
164 * Checks whether a NewGRF wants to play a different vehicle sound effect.
165 * @param v Vehicle to play sound effect for.
166 * @param event Trigger for the sound effect.
167 * @return false if the default sound effect shall be played instead.
169 bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event)
171 if (!_settings_client.sound.vehicle) return true;
173 const GRFFile *file = v->GetGRF();
174 uint16 callback;
176 /* If the engine has no GRF ID associated it can't ever play any new sounds */
177 if (file == NULL) return false;
179 /* Check that the vehicle type uses the sound effect callback */
180 if (!HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_SOUND_EFFECT)) return false;
182 callback = GetVehicleCallback(CBID_VEHICLE_SOUND_EFFECT, event, 0, v->engine_type, v);
183 /* Play default sound if callback fails */
184 if (callback == CALLBACK_FAILED) return false;
186 if (callback >= ORIGINAL_SAMPLE_COUNT) {
187 callback -= ORIGINAL_SAMPLE_COUNT;
189 /* Play no sound if result is out of range */
190 if (callback > file->num_sounds) return true;
192 callback += file->sound_offset;
195 assert(callback < GetNumSounds());
196 SndPlayVehicleFx(callback, v);
197 return true;
201 * Play a NewGRF sound effect at the location of a specific tile.
202 * @param file NewGRF triggering the sound effect.
203 * @param sound_id Sound effect the NewGRF wants to play.
204 * @param tile Location of the effect.
206 void PlayTileSound(const GRFFile *file, SoundID sound_id, TileIndex tile)
208 if (sound_id >= ORIGINAL_SAMPLE_COUNT) {
209 sound_id -= ORIGINAL_SAMPLE_COUNT;
210 if (sound_id > file->num_sounds) return;
211 sound_id += file->sound_offset;
214 assert(sound_id < GetNumSounds());
215 SndPlayTileFx(sound_id, tile);