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