# sound.cpp

Go to the documentation of this file.

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