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 const SoundEntry *sound = GetSound(sound_id);
00163 if (sound == NULL) return;
00164
00165
00166 if (sound->rate == 0) return;
00167
00168 MixerChannel *mc = MxAllocateChannel();
00169 if (mc == NULL) return;
00170
00171 if (!SetBankSource(mc, sound)) return;
00172
00173
00174 volume = sound->volume * volume;
00175
00176 MxSetChannelVolume(mc, volume, pan);
00177 MxActivateChannel(mc);
00178 }
00179
00180
00181 static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87};
00182 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
00183
00184 static const byte _sound_base_vol[] = {
00185 128, 90, 128, 128, 128, 128, 128, 128,
00186 128, 90, 90, 128, 128, 128, 128, 128,
00187 128, 128, 128, 80, 128, 128, 128, 128,
00188 128, 128, 128, 128, 128, 128, 128, 128,
00189 128, 128, 90, 90, 90, 128, 90, 128,
00190 128, 90, 128, 128, 128, 90, 128, 128,
00191 128, 128, 128, 128, 90, 128, 128, 128,
00192 128, 90, 128, 128, 128, 128, 128, 128,
00193 128, 128, 90, 90, 90, 128, 128, 128,
00194 90,
00195 };
00196
00197 static const byte _sound_idx[] = {
00198 2, 3, 4, 5, 6, 7, 8, 9,
00199 10, 11, 12, 13, 14, 15, 16, 17,
00200 18, 19, 20, 21, 22, 23, 24, 25,
00201 26, 27, 28, 29, 30, 31, 32, 33,
00202 34, 35, 36, 37, 38, 39, 40, 0,
00203 1, 41, 42, 43, 44, 45, 46, 47,
00204 48, 49, 50, 51, 52, 53, 54, 55,
00205 56, 57, 58, 59, 60, 61, 62, 63,
00206 64, 65, 66, 67, 68, 69, 70, 71,
00207 72,
00208 };
00209
00210 void SndCopyToPool()
00211 {
00212 for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
00213 SoundEntry *sound = AllocateSound();
00214 *sound = _original_sounds[_sound_idx[i]];
00215 sound->volume = _sound_base_vol[i];
00216 sound->priority = 0;
00217 }
00218 }
00219
00228 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
00229 {
00230 if (_settings_client.music.effect_vol == 0) return;
00231
00232 const Window *w;
00233 FOR_ALL_WINDOWS_FROM_BACK(w) {
00234 const ViewPort *vp = w->viewport;
00235
00236 if (vp != NULL &&
00237 left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
00238 top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
00239 int screen_x = (left + right) / 2 - vp->virtual_left;
00240 int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
00241 float panning = (float)screen_x / width;
00242
00243 StartSound(
00244 sound,
00245 panning,
00246 (_settings_client.music.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
00247 );
00248 return;
00249 }
00250 }
00251 }
00252
00253 void SndPlayTileFx(SoundID sound, TileIndex tile)
00254 {
00255
00256 int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
00257 int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
00258 int z = (y < 0 ? 0 : GetSlopePixelZ(x, y));
00259 Point pt = RemapCoords(x, y, z);
00260 y += 2 * TILE_SIZE;
00261 Point pt2 = RemapCoords(x, y, GetSlopePixelZ(x, y));
00262 SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
00263 }
00264
00265 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
00266 {
00267 SndPlayScreenCoordFx(sound,
00268 v->coord.left, v->coord.right,
00269 v->coord.top, v->coord.bottom
00270 );
00271 }
00272
00273 void SndPlayFx(SoundID sound)
00274 {
00275 StartSound(sound, 0.5, _settings_client.music.effect_vol);
00276 }
00277
00278 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<SoundsSet>, SoundsSet)
00279
00280
00281 static const char * const _sound_file_names[] = { "samples" };
00282
00283
00284 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
00285 const char * const *BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names = _sound_file_names;
00286
00287 template <class Tbase_set>
00288 const char *BaseMedia<Tbase_set>::GetExtension()
00289 {
00290 return ".obs";
00291 }
00292
00293 template <class Tbase_set>
00294 bool BaseMedia<Tbase_set>::DetermineBestSet()
00295 {
00296 if (BaseMedia<Tbase_set>::used_set != NULL) return true;
00297
00298 const Tbase_set *best = NULL;
00299 for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
00300
00301 if (c->GetNumMissing() != 0) continue;
00302
00303 if (best == NULL ||
00304 (best->fallback && !c->fallback) ||
00305 best->valid_files < c->valid_files ||
00306 (best->valid_files == c->valid_files &&
00307 (best->shortname == c->shortname && best->version < c->version))) {
00308 best = c;
00309 }
00310 }
00311
00312 BaseMedia<Tbase_set>::used_set = best;
00313 return BaseMedia<Tbase_set>::used_set != NULL;
00314 }
00315