00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "landscape.h"
00014 #include "mixer.h"
00015 #include "newgrf_sound.h"
00016 #include "fios.h"
00017 #include "window_gui.h"
00018 #include "vehicle_base.h"
00019
00020
00021 #define SET_TYPE "sounds"
00022 #include "base_media_func.h"
00023
00024 static SoundEntry _original_sounds[ORIGINAL_SAMPLE_COUNT];
00025
00026 static void OpenBankFile(const char *filename)
00027 {
00028 memset(_original_sounds, 0, sizeof(_original_sounds));
00029
00030
00031 if (filename == NULL) return;
00032
00033 FioOpenFile(SOUND_SLOT, filename, BASESET_DIR);
00034 size_t pos = FioGetPos();
00035 uint count = FioReadDword();
00036
00037
00038 bool new_format = HasBit(count, 31);
00039 ClrBit(count, 31);
00040 count /= 8;
00041
00042
00043 if (count != ORIGINAL_SAMPLE_COUNT) {
00044
00045
00046
00047 DEBUG(misc, 6, "Incorrect number of sounds in '%s', ignoring.", filename);
00048 return;
00049 }
00050
00051 FioSeekTo(pos, SEEK_SET);
00052
00053 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
00054 _original_sounds[i].file_slot = SOUND_SLOT;
00055 _original_sounds[i].file_offset = GB(FioReadDword(), 0, 31) + pos;
00056 _original_sounds[i].file_size = FioReadDword();
00057 }
00058
00059 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
00060 SoundEntry *sound = &_original_sounds[i];
00061 char name[255];
00062
00063 FioSeekTo(sound->file_offset, SEEK_SET);
00064
00065
00066 FioReadBlock(name, FioReadByte());
00067 if (new_format || strcmp(name, "Corrupt sound") != 0) {
00068 FioSeekTo(12, SEEK_CUR);
00069
00070
00071 for (;;) {
00072 uint32 tag = FioReadDword();
00073 uint32 size = FioReadDword();
00074
00075 if (tag == ' tmf') {
00076 FioReadWord();
00077 sound->channels = FioReadWord();
00078 sound->rate = FioReadDword();
00079 if (!new_format) sound->rate = 11025;
00080 FioReadDword();
00081 FioReadWord();
00082 sound->bits_per_sample = FioReadByte();
00083 FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
00084 } else if (tag == 'atad') {
00085 sound->file_size = size;
00086 sound->file_slot = SOUND_SLOT;
00087 sound->file_offset = FioGetPos();
00088 break;
00089 } else {
00090 sound->file_size = 0;
00091 break;
00092 }
00093 }
00094 } else {
00095
00096
00097
00098
00099
00100 sound->channels = 1;
00101 sound->rate = 11025;
00102 sound->bits_per_sample = 8;
00103 sound->file_slot = SOUND_SLOT;
00104 sound->file_offset = FioGetPos();
00105 }
00106 }
00107 }
00108
00109 static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound)
00110 {
00111 assert(sound != NULL);
00112
00113
00114 if (sound->file_size == 0 || sound->file_size > ((size_t)-1) - 2) return false;
00115
00116 int8 *mem = MallocT<int8>(sound->file_size + 2);
00117
00118
00119 mem[sound->file_size ] = 0;
00120 mem[sound->file_size + 1] = 0;
00121
00122 FioSeekToFile(sound->file_slot, sound->file_offset);
00123 FioReadBlock(mem, sound->file_size);
00124
00125
00126 if (sound->bits_per_sample == 8) {
00127 for (uint i = 0; i != sound->file_size; i++) {
00128 mem[i] += -128;
00129 }
00130 }
00131
00132 #if TTD_ENDIAN == TTD_BIG_ENDIAN
00133 if (sound->bits_per_sample == 16) {
00134 uint num_samples = sound->file_size / 2;
00135 int16 *samples = (int16 *)mem;
00136 for (uint i = 0; i < num_samples; i++) {
00137 samples[i] = BSWAP16(samples[i]);
00138 }
00139 }
00140 #endif
00141
00142 assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16);
00143 assert(sound->channels == 1);
00144 assert(sound->file_size != 0 && sound->rate != 0);
00145
00146 MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16);
00147
00148 return true;
00149 }
00150
00151 void InitializeSound()
00152 {
00153 DEBUG(misc, 1, "Loading sound effects...");
00154 OpenBankFile(BaseSounds::GetUsedSet()->files->filename);
00155 }
00156
00157
00158 static void StartSound(SoundID sound_id, float pan, uint volume)
00159 {
00160 if (volume == 0) return;
00161
00162 SoundEntry *sound = GetSound(sound_id);
00163 if (sound == NULL) return;
00164
00165
00166 if (sound->rate == 0 && sound->file_slot != 0) {
00167 if (!LoadNewGRFSound(sound)) {
00168
00169 sound->file_slot = 0;
00170 return;
00171 }
00172 }
00173
00174
00175 if (sound->rate == 0) return;
00176
00177 MixerChannel *mc = MxAllocateChannel();
00178 if (mc == NULL) return;
00179
00180 if (!SetBankSource(mc, sound)) return;
00181
00182
00183 volume = sound->volume * volume;
00184
00185 MxSetChannelVolume(mc, volume, pan);
00186 MxActivateChannel(mc);
00187 }
00188
00189
00190 static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87};
00191 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
00192
00193 static const byte _sound_base_vol[] = {
00194 128, 90, 128, 128, 128, 128, 128, 128,
00195 128, 90, 90, 128, 128, 128, 128, 128,
00196 128, 128, 128, 80, 128, 128, 128, 128,
00197 128, 128, 128, 128, 128, 128, 128, 128,
00198 128, 128, 90, 90, 90, 128, 90, 128,
00199 128, 90, 128, 128, 128, 90, 128, 128,
00200 128, 128, 128, 128, 90, 128, 128, 128,
00201 128, 90, 128, 128, 128, 128, 128, 128,
00202 128, 128, 90, 90, 90, 128, 128, 128,
00203 90,
00204 };
00205
00206 static const byte _sound_idx[] = {
00207 2, 3, 4, 5, 6, 7, 8, 9,
00208 10, 11, 12, 13, 14, 15, 16, 17,
00209 18, 19, 20, 21, 22, 23, 24, 25,
00210 26, 27, 28, 29, 30, 31, 32, 33,
00211 34, 35, 36, 37, 38, 39, 40, 0,
00212 1, 41, 42, 43, 44, 45, 46, 47,
00213 48, 49, 50, 51, 52, 53, 54, 55,
00214 56, 57, 58, 59, 60, 61, 62, 63,
00215 64, 65, 66, 67, 68, 69, 70, 71,
00216 72,
00217 };
00218
00219 void SndCopyToPool()
00220 {
00221 SoundEntry *sound = AllocateSound(ORIGINAL_SAMPLE_COUNT);
00222 for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
00223 sound[i] = _original_sounds[_sound_idx[i]];
00224 sound[i].volume = _sound_base_vol[i];
00225 sound[i].priority = 0;
00226 }
00227 }
00228
00237 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
00238 {
00239 if (_settings_client.music.effect_vol == 0) return;
00240
00241 const Window *w;
00242 FOR_ALL_WINDOWS_FROM_BACK(w) {
00243 const ViewPort *vp = w->viewport;
00244
00245 if (vp != NULL &&
00246 left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
00247 top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
00248 int screen_x = (left + right) / 2 - vp->virtual_left;
00249 int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
00250 float panning = (float)screen_x / width;
00251
00252 StartSound(
00253 sound,
00254 panning,
00255 (_settings_client.music.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
00256 );
00257 return;
00258 }
00259 }
00260 }
00261
00262 void SndPlayTileFx(SoundID sound, TileIndex tile)
00263 {
00264
00265 int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
00266 int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
00267 int z = (y < 0 ? 0 : GetSlopePixelZ(x, y));
00268 Point pt = RemapCoords(x, y, z);
00269 y += 2 * TILE_SIZE;
00270 Point pt2 = RemapCoords(x, y, GetSlopePixelZ(x, y));
00271 SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
00272 }
00273
00274 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
00275 {
00276 SndPlayScreenCoordFx(sound,
00277 v->coord.left, v->coord.right,
00278 v->coord.top, v->coord.bottom
00279 );
00280 }
00281
00282 void SndPlayFx(SoundID sound)
00283 {
00284 StartSound(sound, 0.5, _settings_client.music.effect_vol);
00285 }
00286
00287 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<SoundsSet>, SoundsSet)
00288
00289
00290 static const char * const _sound_file_names[] = { "samples" };
00291
00292
00293 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
00294 const char * const *BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names = _sound_file_names;
00295
00296 template <class Tbase_set>
00297 const char *BaseMedia<Tbase_set>::GetExtension()
00298 {
00299 return ".obs";
00300 }
00301
00302 template <class Tbase_set>
00303 bool BaseMedia<Tbase_set>::DetermineBestSet()
00304 {
00305 if (BaseMedia<Tbase_set>::used_set != NULL) return true;
00306
00307 const Tbase_set *best = NULL;
00308 for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
00309
00310 if (c->GetNumMissing() != 0) continue;
00311
00312 if (best == NULL ||
00313 (best->fallback && !c->fallback) ||
00314 best->valid_files < c->valid_files ||
00315 (best->valid_files == c->valid_files &&
00316 (best->shortname == c->shortname && best->version < c->version))) {
00317 best = c;
00318 }
00319 }
00320
00321 BaseMedia<Tbase_set>::used_set = best;
00322 return BaseMedia<Tbase_set>::used_set != NULL;
00323 }
00324