# sound.cpp

Go to the documentation of this file.

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