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