# sound.cpp

Go to the documentation of this file.

    00001 /* $Id: sound.cpp 15299 2009-01-31 20:16:06Z smatz $ */
    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   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; // Convert unsigned sound data to signed
    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 /* Low level sound player */
    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   /* Apply the sound effect's own volume. */
    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   /* emits sound from center of the tile */
    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 }