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