# sound.cpp

Go to the documentation of this file.

    00001 /* $Id: sound.cpp 15718 2009-03-15 00:32:18Z 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
    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   /* Simple check for the correct number of original sounds. */
    00037   if (count != ORIGINAL_SAMPLE_COUNT) {
    00038     /* Corrupt sample data? Just leave the allocated memory as those tell
    00039      * there is no sound to play (size = 0 due to calloc). Not allocating
    00040      * the memory disables valid NewGRFs that replace sounds. */
    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     /* Check for special case, see else case */
    00059     FioReadBlock(name, FioReadByte()); // Read the name of the sound
    00060     if (strcmp(name, "Corrupt sound") != 0) {
    00061       FioSeekTo(12, SEEK_CUR); // Skip past RIFF header
    00062
    00063       /* Read riff tags */
    00064       for (;;) {
    00065         uint32 tag = FioReadDword();
    00066         uint32 size = FioReadDword();
    00067
    00068         if (tag == ' tmf') {
    00069           FioReadWord(); // wFormatTag
    00070           fe->channels = FioReadWord(); // wChannels
    00071           FioReadDword();   // samples per second
    00072           fe->rate = 11025; // seems like all samples should be played at this rate.
    00073           FioReadDword();   // avg bytes per second
    00074           FioReadWord();    // alignment
    00075           fe->bits_per_sample = FioReadByte(); // bits per sample
    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        * Special case for the jackhammer sound
    00090        * (name in sample.cat is "Corrupt sound")
    00091        * It's no RIFF file, but raw PCM data
    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; // Convert unsigned sound data to signed
    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 /* Low level sound player */
    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   /* Apply the sound effect's own volume. */
    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   /* emits sound from center of the tile */
    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->coord.left, v->coord.right,
    00249     v->coord.top, v->coord.bottom
    00250   );
    00251 }
    00252
    00253 void SndPlayFx(SoundFx sound)
    00254 {
    00255   StartSound(sound, 0, msf.effect_vol);
    00256 }