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
00115 FioSeekToFile(fe->file_slot, fe->file_offset);
00116 FioReadBlock(mem, fe->file_size);
00117
00118 for (uint i = 0; i != fe->file_size; i++) {
00119 mem[i] += -128;
00120 }
00121
00122 assert(fe->bits_per_sample == 8 && fe->channels == 1 && fe->file_size != 0 && fe->rate != 0);
00123
00124 MxSetChannelRawSrc(mc, mem, fe->file_size, fe->rate, MX_AUTOFREE);
00125
00126 return true;
00127 }
00128
00129 bool SoundInitialize(const char *filename)
00130 {
00131 OpenBankFile(filename);
00132 return true;
00133 }
00134
00135
00136 static void StartSound(uint sound, int panning, uint volume)
00137 {
00138 if (volume == 0) return;
00139
00140 const FileEntry *fe = GetSound(sound);
00141 if (fe == NULL) return;
00142
00143 MixerChannel *mc = MxAllocateChannel();
00144 if (mc == NULL) return;
00145
00146 if (!SetBankSource(mc, fe)) return;
00147
00148
00149 volume = (fe->volume * volume) / 128;
00150
00151 panning = Clamp(panning, -PANNING_LEVELS, PANNING_LEVELS);
00152 uint left_vol = (volume * PANNING_LEVELS) - (volume * panning);
00153 uint right_vol = (volume * PANNING_LEVELS) + (volume * panning);
00154 MxSetChannelVolume(mc, left_vol * 128 / PANNING_LEVELS, right_vol * 128 / PANNING_LEVELS);
00155 MxActivateChannel(mc);
00156 }
00157
00158
00159 static const byte _vol_factor_by_zoom[] = {255, 190, 134, 87};
00160 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
00161
00162 static const byte _sound_base_vol[] = {
00163 128, 90, 128, 128, 128, 128, 128, 128,
00164 128, 90, 90, 128, 128, 128, 128, 128,
00165 128, 128, 128, 80, 128, 128, 128, 128,
00166 128, 128, 128, 128, 128, 128, 128, 128,
00167 128, 128, 90, 90, 90, 128, 90, 128,
00168 128, 90, 128, 128, 128, 90, 128, 128,
00169 128, 128, 128, 128, 90, 128, 128, 128,
00170 128, 90, 128, 128, 128, 128, 128, 128,
00171 128, 128, 90, 90, 90, 128, 128, 128,
00172 90,
00173 };
00174
00175 static const byte _sound_idx[] = {
00176 2, 3, 4, 5, 6, 7, 8, 9,
00177 10, 11, 12, 13, 14, 15, 16, 17,
00178 18, 19, 20, 21, 22, 23, 24, 25,
00179 26, 27, 28, 29, 30, 31, 32, 33,
00180 34, 35, 36, 37, 38, 39, 40, 0,
00181 1, 41, 42, 43, 44, 45, 46, 47,
00182 48, 49, 50, 51, 52, 53, 54, 55,
00183 56, 57, 58, 59, 60, 61, 62, 63,
00184 64, 65, 66, 67, 68, 69, 70, 71,
00185 72,
00186 };
00187
00188 void SndCopyToPool()
00189 {
00190 for (uint i = 0; i < _file_count; i++) {
00191 FileEntry *orig = &_files[_sound_idx[i]];
00192 FileEntry *fe = AllocateFileEntry();
00193
00194 *fe = *orig;
00195 fe->volume = _sound_base_vol[i];
00196 fe->priority = 0;
00197 }
00198 }
00199
00208 static void SndPlayScreenCoordFx(SoundFx sound, int left, int right, int top, int bottom)
00209 {
00210 if (msf.effect_vol == 0) return;
00211
00212 const Window *w;
00213 FOR_ALL_WINDOWS_FROM_BACK(w) {
00214 const ViewPort *vp = w->viewport;
00215
00216 if (vp != NULL &&
00217 left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
00218 top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
00219 int screen_x = (left + right) / 2 - vp->virtual_left;
00220 int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
00221 int panning = (screen_x * PANNING_LEVELS * 2) / width - PANNING_LEVELS;
00222
00223 StartSound(
00224 sound,
00225 panning,
00226 (msf.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
00227 );
00228 return;
00229 }
00230 }
00231 }
00232
00233 void SndPlayTileFx(SoundFx sound, TileIndex tile)
00234 {
00235
00236 int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
00237 int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
00238 uint z = (y < 0 ? 0 : GetSlopeZ(x, y));
00239 Point pt = RemapCoords(x, y, z);
00240 y += 2 * TILE_SIZE;
00241 Point pt2 = RemapCoords(x, y, GetSlopeZ(x, y));
00242 SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
00243 }
00244
00245 void SndPlayVehicleFx(SoundFx sound, const Vehicle *v)
00246 {
00247 SndPlayScreenCoordFx(sound,
00248 v->left_coord, v->right_coord,
00249 v->top_coord, v->top_coord
00250 );
00251 }
00252
00253 void SndPlayFx(SoundFx sound)
00254 {
00255 StartSound(sound, 0, msf.effect_vol);
00256 }