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 if (sound->file_size == 0) 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, 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 (msf.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 (msf.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 uint z = (y < 0 ? 0 : GetSlopeZ(x, y));
00259 Point pt = RemapCoords(x, y, z);
00260 y += 2 * TILE_SIZE;
00261 Point pt2 = RemapCoords(x, y, GetSlopeZ(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, msf.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, Subdirectory Tsubdir>
00285 const char * const *BaseSet<T, Tnum_files, Tsubdir>::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