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 #include "debug.h"
00020
00021
00022 #define SET_TYPE "sounds"
00023 #include "base_media_func.h"
00024
00025 static SoundEntry _original_sounds[ORIGINAL_SAMPLE_COUNT];
00026 MusicFileSettings msf;
00027
00028
00029 #define PANNING_LEVELS 16
00030
00031 static void OpenBankFile(const char *filename)
00032 {
00033 memset(_original_sounds, 0, sizeof(_original_sounds));
00034
00035 FioOpenFile(SOUND_SLOT, filename);
00036 size_t pos = FioGetPos();
00037 uint count = FioReadDword();
00038
00039
00040 bool new_format = HasBit(count, 31);
00041 ClrBit(count, 31);
00042 count /= 8;
00043
00044
00045 if (count != ORIGINAL_SAMPLE_COUNT) {
00046
00047
00048
00049 DEBUG(misc, 6, "Incorrect number of sounds in '%s', ignoring.", filename);
00050 return;
00051 }
00052
00053 FioSeekTo(pos, SEEK_SET);
00054
00055 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
00056 _original_sounds[i].file_slot = SOUND_SLOT;
00057 _original_sounds[i].file_offset = GB(FioReadDword(), 0, 31) + pos;
00058 _original_sounds[i].file_size = FioReadDword();
00059 }
00060
00061 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
00062 SoundEntry *sound = &_original_sounds[i];
00063 char name[255];
00064
00065 FioSeekTo(sound->file_offset, SEEK_SET);
00066
00067
00068 FioReadBlock(name, FioReadByte());
00069 if (new_format || strcmp(name, "Corrupt sound") != 0) {
00070 FioSeekTo(12, SEEK_CUR);
00071
00072
00073 for (;;) {
00074 uint32 tag = FioReadDword();
00075 uint32 size = FioReadDword();
00076
00077 if (tag == ' tmf') {
00078 FioReadWord();
00079 sound->channels = FioReadWord();
00080 sound->rate = FioReadDword();
00081 if (!new_format) sound->rate = 11025;
00082 FioReadDword();
00083 FioReadWord();
00084 sound->bits_per_sample = FioReadByte();
00085 FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
00086 } else if (tag == 'atad') {
00087 sound->file_size = size;
00088 sound->file_slot = SOUND_SLOT;
00089 sound->file_offset = FioGetPos();
00090 break;
00091 } else {
00092 sound->file_size = 0;
00093 break;
00094 }
00095 }
00096 } else {
00097
00098
00099
00100
00101
00102 sound->channels = 1;
00103 sound->rate = 11025;
00104 sound->bits_per_sample = 8;
00105 sound->file_slot = SOUND_SLOT;
00106 sound->file_offset = FioGetPos();
00107 }
00108 }
00109 }
00110
00111 static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound)
00112 {
00113 assert(sound != NULL);
00114
00115 if (sound->file_size == 0) 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, int panning, uint volume)
00160 {
00161 if (volume == 0) return;
00162
00163 const SoundEntry *sound = GetSound(sound_id);
00164 if (sound == NULL) return;
00165
00166 MixerChannel *mc = MxAllocateChannel();
00167 if (mc == NULL) return;
00168
00169 if (!SetBankSource(mc, sound)) return;
00170
00171
00172 volume = (sound->volume * volume) / 128;
00173
00174 panning = Clamp(panning, -PANNING_LEVELS, PANNING_LEVELS);
00175 uint left_vol = (volume * PANNING_LEVELS) - (volume * panning);
00176 uint right_vol = (volume * PANNING_LEVELS) + (volume * panning);
00177 MxSetChannelVolume(mc, left_vol * 128 / PANNING_LEVELS, right_vol * 128 / PANNING_LEVELS);
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 int panning = (screen_x * PANNING_LEVELS * 2) / width - PANNING_LEVELS;
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, 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->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