00001
00002
00005 #include "stdafx.h"
00006 #include "landscape.h"
00007 #include "mixer.h"
00008 #include "fileio_func.h"
00009 #include "newgrf_sound.h"
00010 #include "fios.h"
00011 #include "window_gui.h"
00012 #include "map_func.h"
00013 #include "vehicle_base.h"
00014 #include "debug.h"
00015
00016 static uint _file_count;
00017 static FileEntry *_files;
00018 MusicFileSettings msf;
00019
00020
00021 #define PANNING_LEVELS 16
00022
00024 static const uint ORIGINAL_SAMPLE_COUNT = 73;
00025
00026 static void OpenBankFile(const char *filename)
00027 {
00028 FileEntry *fe = CallocT<FileEntry>(ORIGINAL_SAMPLE_COUNT);
00029 _file_count = ORIGINAL_SAMPLE_COUNT;
00030 _files = fe;
00031
00032 FioOpenFile(SOUND_SLOT, filename);
00033 size_t pos = FioGetPos();
00034 uint count = FioReadDword() / 8;
00035
00036
00037 if (count != ORIGINAL_SAMPLE_COUNT) {
00038
00039
00040
00041 DEBUG(misc, 6, "Incorrect number of sounds in '%s', ignoring.", filename);
00042 return;
00043 }
00044
00045 FioSeekTo(pos, SEEK_SET);
00046
00047 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
00048 fe[i].file_slot = SOUND_SLOT;
00049 fe[i].file_offset = FioReadDword() + pos;
00050 fe[i].file_size = FioReadDword();
00051 }
00052
00053 for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++, fe++) {
00054 char name[255];
00055
00056 FioSeekTo(fe->file_offset, SEEK_SET);
00057
00058
00059 FioReadBlock(name, FioReadByte());
00060 if (strcmp(name, "Corrupt sound") != 0) {
00061 FioSeekTo(12, SEEK_CUR);
00062
00063
00064 for (;;) {
00065 uint32 tag = FioReadDword();
00066 uint32 size = FioReadDword();
00067
00068 if (tag == ' tmf') {
00069 FioReadWord();
00070 fe->channels = FioReadWord();
00071 FioReadDword();
00072 fe->rate = 11025;
00073 FioReadDword();
00074 FioReadWord();
00075 fe->bits_per_sample = FioReadByte();
00076 FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
00077 } else if (tag == 'atad') {
00078 fe->file_size = size;
00079 fe->file_slot = SOUND_SLOT;
00080 fe->file_offset = FioGetPos();
00081 break;
00082 } else {
00083 fe->file_size = 0;
00084 break;
00085 }
00086 }
00087 } else {
00088
00089
00090
00091
00092
00093 fe->channels = 1;
00094 fe->rate = 11025;
00095 fe->bits_per_sample = 8;
00096 fe->file_slot = SOUND_SLOT;
00097 fe->file_offset = FioGetPos();
00098 }
00099 }
00100 }
00101
00102 uint GetNumOriginalSounds()
00103 {
00104 return _file_count;
00105 }
00106
00107 static bool SetBankSource(MixerChannel *mc, const FileEntry *fe)
00108 {
00109 assert(fe != NULL);
00110
00111 if (fe->file_size == 0) return false;
00112
00113 int8 *mem = MallocT<int8>(fe->file_size);
00114 if (mem == NULL) return false;
00115
00116 FioSeekToFile(fe->file_slot, fe->file_offset);
00117 FioReadBlock(mem, fe->file_size);
00118
00119 for (uint i = 0; i != fe->file_size; i++) {
00120 mem[i] += -128;
00121 }
00122
00123 assert(fe->bits_per_sample == 8 && fe->channels == 1 && fe->file_size != 0 && fe->rate != 0);
00124
00125 MxSetChannelRawSrc(mc, mem, fe->file_size, fe->rate, MX_AUTOFREE);
00126
00127 return true;
00128 }
00129
00130 bool SoundInitialize(const char *filename)
00131 {
00132 OpenBankFile(filename);
00133 return true;
00134 }
00135
00136
00137 static void StartSound(uint sound, int panning, uint volume)
00138 {
00139 if (volume == 0) return;
00140
00141 const FileEntry *fe = GetSound(sound);
00142 if (fe == NULL) return;
00143
00144 MixerChannel *mc = MxAllocateChannel();
00145 if (mc == NULL) return;
00146
00147 if (!SetBankSource(mc, fe)) return;
00148
00149
00150 volume = (fe->volume * volume) / 128;
00151
00152 panning = Clamp(panning, -PANNING_LEVELS, PANNING_LEVELS);
00153 uint left_vol = (volume * PANNING_LEVELS) - (volume * panning);
00154 uint right_vol = (volume * PANNING_LEVELS) + (volume * panning);
00155 MxSetChannelVolume(mc, left_vol * 128 / PANNING_LEVELS, right_vol * 128 / PANNING_LEVELS);
00156 MxActivateChannel(mc);
00157 }
00158
00159
00160 static const byte _vol_factor_by_zoom[] = {255, 190, 134, 87};
00161 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
00162
00163 static const byte _sound_base_vol[] = {
00164 128, 90, 128, 128, 128, 128, 128, 128,
00165 128, 90, 90, 128, 128, 128, 128, 128,
00166 128, 128, 128, 80, 128, 128, 128, 128,
00167 128, 128, 128, 128, 128, 128, 128, 128,
00168 128, 128, 90, 90, 90, 128, 90, 128,
00169 128, 90, 128, 128, 128, 90, 128, 128,
00170 128, 128, 128, 128, 90, 128, 128, 128,
00171 128, 90, 128, 128, 128, 128, 128, 128,
00172 128, 128, 90, 90, 90, 128, 128, 128,
00173 90,
00174 };
00175
00176 static const byte _sound_idx[] = {
00177 2, 3, 4, 5, 6, 7, 8, 9,
00178 10, 11, 12, 13, 14, 15, 16, 17,
00179 18, 19, 20, 21, 22, 23, 24, 25,
00180 26, 27, 28, 29, 30, 31, 32, 33,
00181 34, 35, 36, 37, 38, 39, 40, 0,
00182 1, 41, 42, 43, 44, 45, 46, 47,
00183 48, 49, 50, 51, 52, 53, 54, 55,
00184 56, 57, 58, 59, 60, 61, 62, 63,
00185 64, 65, 66, 67, 68, 69, 70, 71,
00186 72,
00187 };
00188
00189 void SndCopyToPool()
00190 {
00191 for (uint i = 0; i < _file_count; i++) {
00192 FileEntry *orig = &_files[_sound_idx[i]];
00193 FileEntry *fe = AllocateFileEntry();
00194
00195 *fe = *orig;
00196 fe->volume = _sound_base_vol[i];
00197 fe->priority = 0;
00198 }
00199 }
00200
00209 static void SndPlayScreenCoordFx(SoundFx sound, int left, int right, int top, int bottom)
00210 {
00211 if (msf.effect_vol == 0) return;
00212
00213 const Window *w;
00214 FOR_ALL_WINDOWS_FROM_BACK(w) {
00215 const ViewPort *vp = w->viewport;
00216
00217 if (vp != NULL &&
00218 left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
00219 top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
00220 int screen_x = (left + right) / 2 - vp->virtual_left;
00221 int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
00222 int panning = (screen_x * PANNING_LEVELS * 2) / width - PANNING_LEVELS;
00223
00224 StartSound(
00225 sound,
00226 panning,
00227 (msf.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
00228 );
00229 return;
00230 }
00231 }
00232 }
00233
00234 void SndPlayTileFx(SoundFx sound, TileIndex tile)
00235 {
00236
00237 int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
00238 int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
00239 uint z = (y < 0 ? 0 : GetSlopeZ(x, y));
00240 Point pt = RemapCoords(x, y, z);
00241 y += 2 * TILE_SIZE;
00242 Point pt2 = RemapCoords(x, y, GetSlopeZ(x, y));
00243 SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
00244 }
00245
00246 void SndPlayVehicleFx(SoundFx sound, const Vehicle *v)
00247 {
00248 SndPlayScreenCoordFx(sound,
00249 v->left_coord, v->right_coord,
00250 v->top_coord, v->top_coord
00251 );
00252 }
00253
00254 void SndPlayFx(SoundFx sound)
00255 {
00256 StartSound(sound, 0, msf.effect_vol);
00257 }